Files
flenser/js4g/StackMachine.h
ADAM David Alan Martin 9391349966 Memoize a function call.
I dunno that this will help much, it adds a lot of complexity,
but for my simple test cases, I see no major benefit.

It might be needed with more defined functions, so I'm saving it
here.
2025-09-27 17:53:26 -04:00

136 lines
3.1 KiB
C++

static_assert( __cplusplus >= 2023'02 );
#pragma once
#include <Dillo/Dillo.h>
#include <iostream>
#include <map>
#include <unordered_map>
#include <vector>
#include <string>
#include <variant>
#include <deque>
#include <memory>
#include <list>
#include <boost/container/flat_map.hpp>
namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
{
inline namespace exports
{
class StackMachine;
}
/*!
* Machine state for JS4G (Java Script Forth Grinder, AKA: JavaScriptForge JS4G).
*
* This class represents the state of a JavaScript execution, post translation to
* the forth grinder format.
*/
class exports::StackMachine
{
private:
using Long= std::uint64_t;
using Integer= std::int32_t;
using Float= long double;
using Value= std::variant< std::string, Integer, Long >;
// The main runtime stack of the forth engine.
// It grows on the "back".
// A `std::deque` is used instead of `std::vector`, because
// it helps cut down on large allocations, by subdividing things.
std::vector< Value > stack;
// TODO: Should these tokens be binary?
// Upside: compressed.
// Downside: more memory management in the machine end?
// It's `void *` to break the cycle with itself
struct TokenHolder;
using Token= std::variant< std::string_view, std::shared_ptr< TokenHolder > >;
std::vector< std::shared_ptr< TokenHolder > > tokenHolders;
std::vector< std::string > backing;
std::vector< Token > tokens;
friend struct Tokenizer;
struct Tokenizer
{
std::vector< Token >::iterator pos;
std::vector< Token >::iterator end;
explicit
Tokenizer( std::vector< Token > &tokens )
: pos( tokens.begin() ), end( tokens.end() ) {}
bool hasNext() const { return pos != end; }
Token
next( StackMachine *const machine )
{
auto &rv= *pos++;
machine->current= &rv;
return rv;
}
};
std::vector< Tokenizer > tokenStack;
Token *current= nullptr;
std::list< std::string > wordNames;
std::unordered_map< std::string_view, std::vector< Token > > words;
// Which side of the current conditional to take.
enum ConditionalState { If, Else, Skipped };
std::vector< ConditionalState > conditionals;
std::vector< ConditionalState > resumeConditionals;
ConditionalState currentState;
std::optional< std::string > definition;
std::ostream &output;
void runWord( std::string_view word );
Value pop();
Value &peek();
void push( std::string s );
void push( Integer s );
void push( Long s );
void push( Value s );
template< typename T >
T pop();
template< typename T >
void push( const T &t );
void compile( std::unordered_map< std::string_view, std::vector< Token > >::iterator );
Token next();
void recurse( std::string_view func );
public:
StackMachine( std::ostream &output= std::cout );
void loadProgram( std::vector< std::string > tokens );
void run();
};
}
namespace Dillo::Hydrogen::JavaScriptForge::inline exports::inline StackMachine_m
{
using namespace detail::StackMachine_m::exports;
}