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.
This commit is contained in:
2025-09-27 17:53:26 -04:00
parent 602e0b4fcc
commit 9391349966
2 changed files with 65 additions and 23 deletions

View File

@ -12,7 +12,10 @@ namespace
namespace C namespace C
{ {
constexpr bool debug= false; constexpr bool debug= false;
constexpr bool debugCompiledCall= C::debug or false;
} }
void breakpoint() {}
} }
namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m 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 void
StackMachine::run() StackMachine::run()
{ {
while( not tokenStack.empty() and tokenStack.back().hasNext() ) 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 ) std::cerr << "After processing stack is now: " << std::endl;
if( C::debug ) for( const auto &element: stack ) 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." }; throw std::runtime_error{ "FATAL: Token required, no more tokens left." };
} }
const auto rv= tokenStack.back().next(); auto rv= tokenStack.back().next( this );
while( not tokenStack.empty() and not tokenStack.back().hasNext() ) tokenStack.pop_back(); while( not tokenStack.empty() and not tokenStack.back().hasNext() ) [[unlikely]] tokenStack.pop_back();
return rv; return rv;
} }
@ -117,11 +146,11 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
} }
else ; // We skip the statement. else ; // We skip the statement.
} }
else if( word == "@else"sv ) else if( word == "@else"sv ) [[unlikely]]
{ {
throw std::runtime_error{ "Syntax error: unexpected `@else`" }; 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`" }; throw std::runtime_error{ "Syntax error: unexpected `@endif`" };
} }
@ -195,7 +224,7 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
} }
else if( word == "{"sv ) 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 >() ); wordNames.push_back( pop< std::string >() );
definition= wordNames.back(); definition= wordNames.back();
@ -214,9 +243,9 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
+ "`" }; + "`" };
} }
const auto &def= words.at( invoke ); auto found= words.find( invoke );
tokenStack.emplace_back( found->second );
tokenStack.emplace_back( def ); compile( found ); // Memoize it for next time.
} }
else 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 if constexpr( std::is_same_v< std::string, T > ) push( t );
else push( boost::lexical_cast< std::string >( 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 int

View File

@ -12,6 +12,7 @@ static_assert( __cplusplus >= 2023'02 );
#include <string> #include <string>
#include <variant> #include <variant>
#include <deque> #include <deque>
#include <memory>
#include <list> #include <list>
#include <boost/container/flat_map.hpp> #include <boost/container/flat_map.hpp>
@ -50,27 +51,36 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
// It's `void *` to break the cycle with itself // It's `void *` to break the cycle with itself
struct TokenHolder; 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< std::string > backing;
std::vector< Token > tokens; std::vector< Token > tokens;
friend struct Tokenizer;
struct Tokenizer struct Tokenizer
{ {
std::vector< Token >::const_iterator pos; std::vector< Token >::iterator pos;
std::vector< Token >::const_iterator end; std::vector< Token >::iterator end;
explicit explicit
Tokenizer( const std::vector< Token > &tokens ) Tokenizer( std::vector< Token > &tokens )
: pos( tokens.begin() ), end( tokens.end() ) {} : pos( tokens.begin() ), end( tokens.end() ) {}
bool hasNext() const { return pos != 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; std::vector< Tokenizer > tokenStack;
Token *current= nullptr;
std::list< std::string > wordNames; std::list< std::string > wordNames;
@ -105,6 +115,7 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
void push( const T &t ); void push( const T &t );
void compile( std::unordered_map< std::string_view, std::vector< Token > >::iterator );
Token next(); Token next();
void recurse( std::string_view func ); void recurse( std::string_view func );
@ -112,15 +123,7 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
public: public:
StackMachine( std::ostream &output= std::cout ); StackMachine( std::ostream &output= std::cout );
void void loadProgram( std::vector< std::string > tokens );
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 run(); void run();
}; };