Partially working with nested conditionals.
Some of the conditional-skip code is a bit wrong...
This commit is contained in:
@ -7,6 +7,11 @@ static_assert( __cplusplus >= 2023'02 );
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
using namespace std::literals::string_literals;
|
using namespace std::literals::string_literals;
|
||||||
|
|
||||||
|
namespace C
|
||||||
|
{
|
||||||
|
constexpr bool debug= false or true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
|
namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
|
||||||
@ -21,22 +26,53 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
|
|||||||
{
|
{
|
||||||
while( not tokens.empty() )
|
while( not tokens.empty() )
|
||||||
{
|
{
|
||||||
const auto token= tokens.front();
|
runWord( next() );
|
||||||
tokens.pop_front();
|
|
||||||
|
|
||||||
runWord( token );
|
if( C::debug ) std::cerr << "After processing stack is now: " << std::endl;
|
||||||
|
if( C::debug ) std::copy( rbegin( stack ), rend( stack ), std::ostream_iterator< std::string >{ std::cerr, "\n" } );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "Run done with stack at size: " << stack.size() << std::endl;
|
if( C::debug ) std::cerr << "Run done with stack at size: " << stack.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
StackMachine::next()
|
||||||
|
{
|
||||||
|
if( tokens.empty() )
|
||||||
|
{
|
||||||
|
throw std::runtime_error{ "FATAL: Token required, no more tokens left." };
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto rv= tokens.front();
|
||||||
|
tokens.pop_front();
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StackMachine::runWord( const std::string_view word )
|
StackMachine::runWord( const std::string_view word )
|
||||||
{
|
{
|
||||||
|
if( C::debug ) std::cerr << "Processing token: " << word << std::endl;
|
||||||
const bool inConditional= not conditionals.empty();
|
const bool inConditional= not conditionals.empty();
|
||||||
|
|
||||||
if( false );
|
if( false );
|
||||||
else if( word.empty() );
|
else if( word.empty() );
|
||||||
|
else if( word == "@enddef" )
|
||||||
|
{
|
||||||
|
if( not definition.has_value() )
|
||||||
|
{
|
||||||
|
throw std::runtime_error{ "Stray end of function definition" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if( C::debug ) std::cerr << "Definition of " << definition.value() << " is done. It is: " << std::endl;
|
||||||
|
if( C::debug ) std::copy( begin( words.at( definition.value() ) ), end( words.at( definition.value() ) ),
|
||||||
|
std::ostream_iterator< std::string >{ std::cout, "\n" } );
|
||||||
|
definition= std::nullopt;
|
||||||
|
}
|
||||||
|
else if( definition.has_value() )
|
||||||
|
{
|
||||||
|
if( C::debug ) std::cerr << "Adding word: " << word << " to function definition: " << definition.value() << std::endl;
|
||||||
|
words[ definition.value() ].emplace_back( word );
|
||||||
|
}
|
||||||
else if( inConditional and word == "@else" and currentState != Else )
|
else if( inConditional and word == "@else" and currentState != Else )
|
||||||
{
|
{
|
||||||
currentState= Else;
|
currentState= Else;
|
||||||
@ -44,11 +80,18 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
|
|||||||
else if( inConditional and word == "@endif" )
|
else if( inConditional and word == "@endif" )
|
||||||
{
|
{
|
||||||
conditionals.pop_back();
|
conditionals.pop_back();
|
||||||
|
currentState= resumeConditionals.back();
|
||||||
|
resumeConditionals.pop_back();
|
||||||
}
|
}
|
||||||
else if( inConditional and currentState != conditionals.back() )
|
else if( inConditional and currentState != conditionals.back() )
|
||||||
{
|
{
|
||||||
// Pass (We skip things inside the wrong side)
|
if( word != "@if" )
|
||||||
// TODO: Nested if's won't work, here...
|
{
|
||||||
|
conditionals.push_back( Skipped );
|
||||||
|
resumeConditionals.push_back( currentState );
|
||||||
|
currentState= If;
|
||||||
|
}
|
||||||
|
else ; // We skip the statement.
|
||||||
}
|
}
|
||||||
else if( word == "@else" )
|
else if( word == "@else" )
|
||||||
{
|
{
|
||||||
@ -63,6 +106,13 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
|
|||||||
auto val= peek();
|
auto val= peek();
|
||||||
push( std::move( val ) );
|
push( std::move( val ) );
|
||||||
}
|
}
|
||||||
|
else if( word == "@swap" )
|
||||||
|
{
|
||||||
|
auto a= pop();
|
||||||
|
auto b= pop();
|
||||||
|
push( std::move( a ) );
|
||||||
|
push( std::move( b ) );
|
||||||
|
}
|
||||||
else if( word == "@drop" )
|
else if( word == "@drop" )
|
||||||
{
|
{
|
||||||
std::ignore= pop();
|
std::ignore= pop();
|
||||||
@ -72,6 +122,14 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
|
|||||||
auto val= pop< Integer >();
|
auto val= pop< Integer >();
|
||||||
push( val == 0 ? 1 : 0 );
|
push( val == 0 ? 1 : 0 );
|
||||||
}
|
}
|
||||||
|
else if( word == "@i_inc" )
|
||||||
|
{
|
||||||
|
push( pop< Integer >() + 1 );
|
||||||
|
}
|
||||||
|
else if( word == "@i_dec" )
|
||||||
|
{
|
||||||
|
push( pop< Integer >() - 1 );
|
||||||
|
}
|
||||||
else if( word == "@i_add" )
|
else if( word == "@i_add" )
|
||||||
{
|
{
|
||||||
const auto lhs= pop< Integer >();
|
const auto lhs= pop< Integer >();
|
||||||
@ -108,12 +166,31 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
|
|||||||
{
|
{
|
||||||
const auto val= pop< Integer >();
|
const auto val= pop< Integer >();
|
||||||
conditionals.push_back( val ? If : Else );
|
conditionals.push_back( val ? If : Else );
|
||||||
|
resumeConditionals.push_back( currentState );
|
||||||
currentState= If;
|
currentState= If;
|
||||||
}
|
}
|
||||||
|
else if( word == "@define" )
|
||||||
|
{
|
||||||
|
if( definition.has_value() ) throw std::runtime_error{ "Nested definitions not supported." };
|
||||||
|
|
||||||
|
definition= next();
|
||||||
|
|
||||||
|
if( C::debug ) std::cerr << "Starting function definition for " << definition.value() << std::endl;
|
||||||
|
}
|
||||||
else if( word.at( 0 ) == '@' )
|
else if( word.at( 0 ) == '@' )
|
||||||
{
|
{
|
||||||
throw std::runtime_error{ "Unknown keyword: `"s + std::string{ word }
|
const std::string invoke{ word.substr( 1 ) };
|
||||||
+ "`" };
|
if( not words.contains( invoke ) )
|
||||||
|
{
|
||||||
|
throw std::runtime_error{ "Unknown keyword: `"s + std::string{ word }
|
||||||
|
+ "`" };
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &def= words.at( invoke );
|
||||||
|
|
||||||
|
std::copy( rbegin( def ), rend( def ), front_inserter( tokens ) );
|
||||||
|
|
||||||
|
if( tokens.size() >= 1000 ) abort();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -42,14 +42,20 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
|
|||||||
using Float= long double;
|
using Float= long double;
|
||||||
|
|
||||||
|
|
||||||
std::map< std::string, std::string > words;
|
std::map< std::string, std::vector< std::string > > words;
|
||||||
|
|
||||||
// Which side of the current conditional to take.
|
// Which side of the current conditional to take.
|
||||||
enum ConditionalState { If, Else };
|
enum ConditionalState { If, Else, Skipped };
|
||||||
std::vector< ConditionalState > conditionals;
|
std::vector< ConditionalState > conditionals;
|
||||||
|
std::vector< ConditionalState > resumeConditionals;
|
||||||
|
|
||||||
ConditionalState currentState;
|
ConditionalState currentState;
|
||||||
|
|
||||||
|
std::optional< std::string > definition;
|
||||||
|
|
||||||
|
std::ostream &output;
|
||||||
|
|
||||||
|
|
||||||
void runWord( std::string_view word );
|
void runWord( std::string_view word );
|
||||||
|
|
||||||
std::string pop();
|
std::string pop();
|
||||||
@ -63,7 +69,7 @@ namespace Dillo::Hydrogen::JavaScriptForge ::detail:: StackMachine_m
|
|||||||
template< typename T >
|
template< typename T >
|
||||||
void push( const T &t );
|
void push( const T &t );
|
||||||
|
|
||||||
std::ostream &output;
|
std::string next();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StackMachine( std::ostream &output= std::cout );
|
StackMachine( std::ostream &output= std::cout );
|
||||||
|
|||||||
43
js4g/factorial.js4
Normal file
43
js4g/factorial.js4
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
@define factorial
|
||||||
|
@dup
|
||||||
|
@if
|
||||||
|
@dup @i_dec
|
||||||
|
@factorial
|
||||||
|
@i_mul
|
||||||
|
@else
|
||||||
|
@i_inc
|
||||||
|
@endif
|
||||||
|
@enddef
|
||||||
|
|
||||||
|
6 @factorial
|
||||||
|
@print
|
||||||
|
|
||||||
|
|
||||||
|
@define fib
|
||||||
|
@dup
|
||||||
|
@not
|
||||||
|
@if
|
||||||
|
@drop 1
|
||||||
|
@else
|
||||||
|
@dup
|
||||||
|
@i_dec
|
||||||
|
@not
|
||||||
|
@if
|
||||||
|
@drop 1
|
||||||
|
@else
|
||||||
|
@i_dec
|
||||||
|
@dup
|
||||||
|
@i_dec
|
||||||
|
@fib
|
||||||
|
@swap
|
||||||
|
@fib
|
||||||
|
@i_add
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
@enddef
|
||||||
|
|
||||||
|
|
||||||
|
8 @fib @print
|
||||||
|
|
||||||
|
10 @factorial
|
||||||
|
@print
|
||||||
26
js4g/fib.js4
Normal file
26
js4g/fib.js4
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
@define fib
|
||||||
|
@dup
|
||||||
|
@not
|
||||||
|
@if
|
||||||
|
@drop 1
|
||||||
|
@else
|
||||||
|
@dup
|
||||||
|
@i_dec
|
||||||
|
@not
|
||||||
|
@if
|
||||||
|
@drop 1
|
||||||
|
@else
|
||||||
|
@i_dec
|
||||||
|
@dup
|
||||||
|
@i_dec
|
||||||
|
@fib
|
||||||
|
@swap
|
||||||
|
@fib
|
||||||
|
@i_add
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
@enddef
|
||||||
|
|
||||||
|
|
||||||
|
9 @dup @print @fib @print
|
||||||
|
|
||||||
Reference in New Issue
Block a user