static_assert( __cplusplus >= 2023'02 ); #pragma once #include #include #include #include #include #include #include #include #include #include #include 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; }