From 939134996615a2b1922592b391ff44902ee066e9d17acfb561591e5844dd2baa Mon Sep 17 00:00:00 2001 From: ADAM David Alan Martin Date: Sat, 27 Sep 2025 17:53:26 -0400 Subject: [PATCH] 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. --- js4g/StackMachine.cc | 57 +++++++++++++++++++++++++++++++++++++------- js4g/StackMachine.h | 31 +++++++++++++----------- 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/js4g/StackMachine.cc b/js4g/StackMachine.cc index 8bf3157..7e195b3 100644 --- a/js4g/StackMachine.cc +++ b/js4g/StackMachine.cc @@ -12,7 +12,10 @@ namespace namespace C { constexpr bool debug= false; + constexpr bool debugCompiledCall= C::debug or false; } + + void breakpoint() {} } namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m @@ -22,12 +25,38 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m { } + struct StackMachine::TokenHolder + { + std::unordered_map< std::string_view, std::vector< Token > >::iterator where; + }; + + void + StackMachine::compile( const std::unordered_map< std::string_view, std::vector< Token > >::iterator def ) + { + tokenHolders.push_back( std::make_unique< TokenHolder >( TokenHolder{ def } ) ); + *current= tokenHolders.back(); + } + void StackMachine::run() { while( not tokenStack.empty() and tokenStack.back().hasNext() ) { - runWord( std::get< std::string_view >( next() ) ); + const bool inConditional= not conditionals.empty(); + + auto token= next(); + if( std::holds_alternative< std::shared_ptr< TokenHolder > >( token ) ) + { + if( inConditional and currentState != conditionals.back() ) { breakpoint(); continue; } + // If compiled, just go directly there. + //if( C::debug ) std::cerr << " Executing to compiled token: " << (void *) std::get< std::shared_ptr< TokenHolder > >( token ).get() << std::endl; + + tokenStack.emplace_back( std::get< std::shared_ptr< TokenHolder > >( token )->where->second ); + + continue; + //abort(); + } + else runWord( std::get< std::string_view >( token ) ); if( C::debug ) std::cerr << "After processing stack is now: " << std::endl; if( C::debug ) for( const auto &element: stack ) @@ -51,8 +80,8 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m throw std::runtime_error{ "FATAL: Token required, no more tokens left." }; } - const auto rv= tokenStack.back().next(); - while( not tokenStack.empty() and not tokenStack.back().hasNext() ) tokenStack.pop_back(); + auto rv= tokenStack.back().next( this ); + while( not tokenStack.empty() and not tokenStack.back().hasNext() ) [[unlikely]] tokenStack.pop_back(); return rv; } @@ -117,11 +146,11 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m } else ; // We skip the statement. } - else if( word == "@else"sv ) + else if( word == "@else"sv ) [[unlikely]] { throw std::runtime_error{ "Syntax error: unexpected `@else`" }; } - else if( word == "@endif"sv ) + else if( word == "@endif"sv ) [[unlikely]] { throw std::runtime_error{ "Syntax error: unexpected `@endif`" }; } @@ -195,7 +224,7 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m } else if( word == "{"sv ) { - if( definition.has_value() ) throw std::runtime_error{ "Nested definitions not supported." }; + if( definition.has_value() ) [[unlikely]] throw std::runtime_error{ "Nested definitions not supported." }; wordNames.push_back( pop< std::string >() ); definition= wordNames.back(); @@ -214,9 +243,9 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m + "`" }; } - const auto &def= words.at( invoke ); - - tokenStack.emplace_back( def ); + auto found= words.find( invoke ); + tokenStack.emplace_back( found->second ); + compile( found ); // Memoize it for next time. } else { @@ -282,6 +311,16 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m else if constexpr( std::is_same_v< std::string, T > ) push( t ); else push( boost::lexical_cast< std::string >( t ) ); } + + void + StackMachine::loadProgram( std::vector< std::string > tokens ) + { + backing= std::move( tokens ); + this->tokens.clear(); + std::copy( begin( backing ), end( backing ), back_inserter( this->tokens ) ); + tokenStack.clear(); + tokenStack.emplace_back( this->tokens ); + } } int diff --git a/js4g/StackMachine.h b/js4g/StackMachine.h index a1fa032..a3e2504 100644 --- a/js4g/StackMachine.h +++ b/js4g/StackMachine.h @@ -12,6 +12,7 @@ static_assert( __cplusplus >= 2023'02 ); #include #include #include +#include #include #include @@ -50,27 +51,36 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m // It's `void *` to break the cycle with itself struct TokenHolder; - using Token= std::variant< std::string_view, 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 >::const_iterator pos; - std::vector< Token >::const_iterator end; + std::vector< Token >::iterator pos; + std::vector< Token >::iterator end; explicit - Tokenizer( const std::vector< Token > &tokens ) + Tokenizer( std::vector< Token > &tokens ) : pos( tokens.begin() ), end( tokens.end() ) {} bool hasNext() const { return pos != end; } - Token next() { return *pos++; } + 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; @@ -105,6 +115,7 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m 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 ); @@ -112,15 +123,7 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m public: StackMachine( std::ostream &output= std::cout ); - void - loadProgram( std::vector< std::string > tokens ) - { - backing= std::move( tokens ); - this->tokens.clear(); - std::copy( begin( backing ), end( backing ), back_inserter( this->tokens ) ); - tokenStack.clear(); - tokenStack.emplace_back( this->tokens ); - } + void loadProgram( std::vector< std::string > tokens ); void run(); };