2025-12-21 12:06:55 +11:00
# include "parser.h"
2025-12-24 13:15:48 +11:00
# include "error.h"
2025-12-22 13:49:44 +11:00
# include <groundvm.h>
2025-12-21 12:06:55 +11:00
# include <cstring>
2025-12-28 13:41:05 +11:00
# include <string>
2025-12-21 12:06:55 +11:00
2025-12-25 22:37:40 +11:00
# define parseOneToken(token) Parser({token}).parse().children[0]
2025-12-21 12:06:55 +11:00
namespace Solstice {
namespace Parser {
2025-12-22 19:38:06 +11:00
bool isTemp ( std : : string id ) {
return id . rfind ( " tmp_ " , 0 ) = = 0 ;
}
2025-12-26 13:28:47 +11:00
std : : map < std : : string , std : : string > variables ;
2025-12-24 13:15:48 +11:00
2025-12-26 13:28:47 +11:00
std : : string checkNodeReturnType ( SolNode i ) {
2025-12-24 13:15:48 +11:00
switch ( i . nodeType ) {
case SolNodeType : : Identifier : {
if ( variables . find ( i . outputId ) ! = variables . end ( ) ) {
return variables [ i . outputId ] ;
} else {
2025-12-29 10:30:07 +11:00
Error : : syntaxError ( " Unknown variable " + i . outputId , i . line , i . lineContent ) ;
2025-12-24 13:15:48 +11:00
}
break ;
}
2025-12-24 14:31:43 +11:00
case SolNodeType : : Value : {
2025-12-26 13:28:47 +11:00
return i . data . getTypeString ( ) ;
2025-12-24 14:31:43 +11:00
}
2025-12-24 13:15:48 +11:00
case SolNodeType : : Equal :
case SolNodeType : : Inequal :
case SolNodeType : : Greater :
case SolNodeType : : Lesser :
case SolNodeType : : EqGreater :
case SolNodeType : : EqLesser :
2025-12-26 13:28:47 +11:00
return " bool " ;
2025-12-24 13:15:48 +11:00
break ;
case SolNodeType : : Add :
{
2025-12-26 13:28:47 +11:00
if ( checkNodeReturnType ( i . children [ 0 ] ) = = " string " & & checkNodeReturnType ( i . children [ 1 ] ) = = " string " ) {
return " string " ;
2025-12-24 13:15:48 +11:00
}
}
case SolNodeType : : Subtract :
case SolNodeType : : Multiply :
case SolNodeType : : Divide :
{
2025-12-26 13:28:47 +11:00
if ( checkNodeReturnType ( i . children [ 0 ] ) = = " double " ) {
return " double " ;
2025-12-24 13:15:48 +11:00
}
2025-12-26 13:28:47 +11:00
if ( checkNodeReturnType ( i . children [ 1 ] ) = = " double " ) {
return " double " ;
2025-12-24 13:15:48 +11:00
}
2025-12-26 13:28:47 +11:00
return " int " ;
2025-12-24 13:15:48 +11:00
break ;
}
2025-12-29 10:30:07 +11:00
case SolNodeType : : FunctionCall : {
if ( i . children [ 0 ] . outputId = = " input " ) {
if ( i . children . size ( ) > 1 ) {
ensure ( i . children [ 1 ] , " string " , " input function argument " ) ;
}
return " string " ;
}
std : : string funcName = i . children [ 0 ] . outputId ;
if ( variables . find ( funcName ) = = variables . end ( ) ) {
Error : : syntaxError ( " Unknown function " + funcName , i . line , i . lineContent ) ;
}
std : : string signature = variables [ funcName ] ;
// Parse signature: fun(arg1, arg2) retType
if ( signature . rfind ( " fun( " , 0 ) ! = 0 ) {
// Not a function signature, maybe it's a variable being called?
Error : : typingError ( funcName + " is not a function " , i . line , i . lineContent ) ;
}
size_t endParen = signature . find ( ' ) ' ) ;
if ( endParen = = std : : string : : npos ) {
Error : : typingError ( " Invalid function signature for " + funcName , i . line , i . lineContent ) ;
}
std : : string argsStr = signature . substr ( 4 , endParen - 4 ) ;
std : : string retType = signature . substr ( endParen + 2 ) ; // skip ") "
std : : vector < std : : string > expectedArgs ;
if ( ! argsStr . empty ( ) ) {
size_t start = 0 ;
size_t end = argsStr . find ( " , " ) ;
while ( end ! = std : : string : : npos ) {
expectedArgs . push_back ( argsStr . substr ( start , end - start ) ) ;
start = end + 2 ;
end = argsStr . find ( " , " , start ) ;
}
expectedArgs . push_back ( argsStr . substr ( start ) ) ;
}
// Check arguments
// children[0] is function name, children[1..] are args
if ( i . children . size ( ) - 1 ! = expectedArgs . size ( ) ) {
Error : : typingError ( " Expected " + std : : to_string ( expectedArgs . size ( ) ) + " arguments for " + funcName + " , got " + std : : to_string ( i . children . size ( ) - 1 ) , i . line , i . lineContent ) ;
return " none " ;
}
for ( size_t k = 0 ; k < expectedArgs . size ( ) ; + + k ) {
std : : string argType = checkNodeReturnType ( i . children [ k + 1 ] ) ;
if ( argType ! = expectedArgs [ k ] ) {
Error : : typingError ( " Expected argument " + std : : to_string ( k + 1 ) + " of " + funcName + " to be " + expectedArgs [ k ] + " , got " + argType , i . children [ k + 1 ] . line , i . children [ k + 1 ] . lineContent ) ;
}
}
return retType ;
break ;
}
2025-12-24 13:15:48 +11:00
case SolNodeType : : Puts :
case SolNodeType : : If :
case SolNodeType : : While :
case SolNodeType : : CodeBlock :
2025-12-24 14:31:43 +11:00
case SolNodeType : : Set :
case SolNodeType : : Root :
case SolNodeType : : None :
2025-12-26 13:28:47 +11:00
case SolNodeType : : FunctionDef :
return " none " ;
2025-12-24 13:15:48 +11:00
break ;
}
2025-12-26 13:28:47 +11:00
return " none " ;
2025-12-24 13:15:48 +11:00
}
2025-12-21 12:06:55 +11:00
// SolData Implementation
SolData : : SolData ( int64_t in ) : data ( in ) , type ( SolDataType : : Int ) { }
SolData : : SolData ( double in ) : data ( in ) , type ( SolDataType : : Double ) { }
SolData : : SolData ( std : : string in ) : data ( in ) , type ( SolDataType : : String ) { }
SolData : : SolData ( char in ) : data ( in ) , type ( SolDataType : : Char ) { }
SolData : : SolData ( bool in ) : data ( in ) , type ( SolDataType : : Bool ) { }
2025-12-26 13:28:47 +11:00
SolData : : SolData ( SolFunction in ) : data ( in ) , type ( SolDataType : : Function ) { }
2025-12-21 12:06:55 +11:00
std : : optional < int64_t > SolData : : getInt ( ) {
if ( type = = SolDataType : : Int ) {
return std : : get < int64_t > ( data ) ;
} else {
return { } ;
}
}
std : : optional < double > SolData : : getDouble ( ) {
if ( type = = SolDataType : : Double ) {
return std : : get < double > ( data ) ;
} else {
return { } ;
}
}
std : : optional < std : : string > SolData : : getString ( ) {
if ( type = = SolDataType : : String ) {
return std : : get < std : : string > ( data ) ;
} else {
return { } ;
}
}
std : : optional < char > SolData : : getChar ( ) {
if ( type = = SolDataType : : Char ) {
return std : : get < char > ( data ) ;
} else {
return { } ;
}
}
std : : optional < bool > SolData : : getBool ( ) {
if ( type = = SolDataType : : Bool ) {
return std : : get < bool > ( data ) ;
} else {
return { } ;
}
}
2025-12-26 13:28:47 +11:00
std : : optional < SolFunction > SolData : : getFunction ( ) {
if ( type = = SolDataType : : Function ) {
return std : : get < SolFunction > ( data ) ;
} else {
return { } ;
}
}
std : : string SolData : : getTypeString ( ) {
switch ( type ) {
case SolDataType : : Int : return " int " ;
case SolDataType : : Double : return " double " ;
case SolDataType : : String : return " string " ;
case SolDataType : : Char : return " char " ;
case SolDataType : : Bool : return " bool " ;
case SolDataType : : Function : return " function " ;
case SolDataType : : None : return " none " ;
}
return " none " ;
}
2025-12-21 12:06:55 +11:00
// SolNode Implementation
SolNode : : SolNode ( SolNodeType nodeType ) : nodeType ( nodeType ) { }
SolNode : : SolNode ( SolNodeType nodeType , SolData data ) : data ( data ) , nodeType ( nodeType ) { }
void SolNode : : addNode ( SolNode in ) {
children . push_back ( in ) ;
}
void SolNode : : setValue ( SolData in ) {
data = in ;
}
2025-12-28 13:49:05 +11:00
std : : string currentFunctionRetType = " " ;
2025-12-21 12:06:55 +11:00
const std : : vector < SolGroundCodeBlock > SolNode : : generateCode ( ) {
std : : vector < SolGroundCodeBlock > code ;
if ( nodeType ! = SolNodeType : : If & & nodeType ! = SolNodeType : : While ) for ( auto & child : children ) {
auto childCode = child . generateCode ( ) ;
code . insert ( code . end ( ) , childCode . begin ( ) , childCode . end ( ) ) ;
}
switch ( nodeType ) {
case SolNodeType : : Value : {
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
SolGroundCodeBlock codeBlock ;
GroundInstruction gi = groundCreateInstruction ( SET ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
switch ( data . type ) {
case SolDataType : : Int : {
auto dataopt = data . getInt ( ) ;
if ( dataopt ) {
groundAddValueToInstruction ( & gi , groundCreateValue ( INT , dataopt . value ( ) ) ) ;
}
break ;
}
case SolDataType : : Double : {
auto dataopt = data . getDouble ( ) ;
if ( dataopt ) {
groundAddValueToInstruction ( & gi , groundCreateValue ( DOUBLE , dataopt . value ( ) ) ) ;
}
break ;
}
case SolDataType : : String : {
auto dataopt = data . getString ( ) ;
if ( dataopt ) {
2025-12-22 19:38:06 +11:00
char * str = ( char * ) malloc ( dataopt . value ( ) . size ( ) + 1 ) ;
strcpy ( str , dataopt . value ( ) . c_str ( ) ) ;
groundAddValueToInstruction ( & gi , groundCreateValue ( STRING , str ) ) ;
2025-12-21 12:06:55 +11:00
}
break ;
}
case SolDataType : : Char : {
auto dataopt = data . getChar ( ) ;
if ( dataopt ) {
groundAddValueToInstruction ( & gi , groundCreateValue ( CHAR , dataopt . value ( ) ) ) ;
}
break ;
}
case SolDataType : : Bool : {
auto dataopt = data . getBool ( ) ;
if ( dataopt ) {
groundAddValueToInstruction ( & gi , groundCreateValue ( BOOL , dataopt . value ( ) ) ) ;
}
break ;
}
}
codeBlock . code . push_back ( gi ) ;
code . push_back ( codeBlock ) ;
break ;
}
case SolNodeType : : Add : {
2025-12-26 13:28:47 +11:00
ensure3 ( children [ 0 ] , " int " , " double " , " string " , " operator '+' " ) ;
ensure3 ( children [ 1 ] , " int " , " double " , " string " , " operator '+' " ) ;
2025-12-25 22:37:40 +11:00
ensuresame ( children [ 0 ] , children [ 1 ] , " operator '+' " ) ;
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock codeBlock ;
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
GroundInstruction gi = groundCreateInstruction ( ADD ) ;
if ( children . size ( ) < 2 ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Need more stuff to add " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-21 12:06:55 +11:00
}
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
codeBlock . code . push_back ( gi ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
if ( isTemp ( children [ 1 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
2025-12-21 12:06:55 +11:00
code . push_back ( codeBlock ) ;
break ;
}
2025-12-24 14:31:43 +11:00
case SolNodeType : : Subtract : {
2025-12-26 13:28:47 +11:00
ensure2 ( children [ 0 ] , " int " , " double " , " operator '-' " ) ;
ensure2 ( children [ 1 ] , " int " , " double " , " operator '-' " ) ;
2025-12-24 14:31:43 +11:00
SolGroundCodeBlock codeBlock ;
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
GroundInstruction gi = groundCreateInstruction ( SUBTRACT ) ;
if ( children . size ( ) < 2 ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Need more stuff to subtract " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-24 14:31:43 +11:00
}
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
2025-12-24 16:22:51 +11:00
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
codeBlock . code . push_back ( gi ) ;
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
if ( isTemp ( children [ 1 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
code . push_back ( codeBlock ) ;
break ;
}
case SolNodeType : : Multiply : {
2025-12-26 13:28:47 +11:00
ensure2 ( children [ 0 ] , " int " , " double " , " operator '*' " ) ;
ensure2 ( children [ 1 ] , " int " , " double " , " operator '*' " ) ;
2025-12-24 16:22:51 +11:00
SolGroundCodeBlock codeBlock ;
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
GroundInstruction gi = groundCreateInstruction ( MULTIPLY ) ;
if ( children . size ( ) < 2 ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Need more stuff to multiply " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-24 16:22:51 +11:00
}
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
codeBlock . code . push_back ( gi ) ;
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
if ( isTemp ( children [ 1 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
code . push_back ( codeBlock ) ;
break ;
}
case SolNodeType : : Divide : {
2025-12-26 13:28:47 +11:00
ensure2 ( children [ 0 ] , " int " , " double " , " operator '/' " ) ;
ensure2 ( children [ 1 ] , " int " , " double " , " operator '/' " ) ;
2025-12-24 16:22:51 +11:00
SolGroundCodeBlock codeBlock ;
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
GroundInstruction gi = groundCreateInstruction ( DIVIDE ) ;
if ( children . size ( ) < 2 ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Need more stuff to divide " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-24 16:22:51 +11:00
}
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
2025-12-24 14:31:43 +11:00
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
codeBlock . code . push_back ( gi ) ;
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
if ( isTemp ( children [ 1 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
code . push_back ( codeBlock ) ;
break ;
}
2025-12-21 12:06:55 +11:00
case SolNodeType : : Equal : {
2025-12-25 22:37:40 +11:00
ensuresame ( children [ 0 ] , children [ 1 ] , " operator '==' " ) ;
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock codeBlock ;
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
GroundInstruction gi = groundCreateInstruction ( EQUAL ) ;
if ( children . size ( ) < 2 ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Need more stuff to equal " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-21 12:06:55 +11:00
}
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
codeBlock . code . push_back ( gi ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
if ( isTemp ( children [ 1 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
2025-12-21 12:06:55 +11:00
code . push_back ( codeBlock ) ;
break ;
}
case SolNodeType : : Inequal : {
2025-12-25 22:37:40 +11:00
ensuresame ( children [ 0 ] , children [ 1 ] , " operator '!=' " ) ;
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock codeBlock ;
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
GroundInstruction gi = groundCreateInstruction ( INEQUAL ) ;
if ( children . size ( ) < 2 ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Need more stuff to inequal " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-21 12:06:55 +11:00
}
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
codeBlock . code . push_back ( gi ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
if ( isTemp ( children [ 1 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
2025-12-21 12:06:55 +11:00
code . push_back ( codeBlock ) ;
break ;
}
2025-12-22 13:49:44 +11:00
case SolNodeType : : Greater : {
2025-12-25 22:37:40 +11:00
ensuresame ( children [ 0 ] , children [ 1 ] , " operator '>' " ) ;
2025-12-22 13:49:44 +11:00
SolGroundCodeBlock codeBlock ;
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
GroundInstruction gi = groundCreateInstruction ( GREATER ) ;
if ( children . size ( ) < 2 ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Need more stuff to greater " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-22 13:49:44 +11:00
}
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
codeBlock . code . push_back ( gi ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
if ( isTemp ( children [ 1 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
2025-12-22 13:49:44 +11:00
code . push_back ( codeBlock ) ;
break ;
}
case SolNodeType : : Lesser : {
2025-12-25 22:37:40 +11:00
ensuresame ( children [ 0 ] , children [ 1 ] , " operator '<' " ) ;
2025-12-22 13:49:44 +11:00
SolGroundCodeBlock codeBlock ;
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
GroundInstruction gi = groundCreateInstruction ( LESSER ) ;
if ( children . size ( ) < 2 ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Need more stuff to lesser " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-22 13:49:44 +11:00
}
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
codeBlock . code . push_back ( gi ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
if ( isTemp ( children [ 1 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
2025-12-22 13:49:44 +11:00
code . push_back ( codeBlock ) ;
break ;
}
case SolNodeType : : EqGreater : {
2025-12-25 22:37:40 +11:00
ensuresame ( children [ 0 ] , children [ 1 ] , " operator '>=' " ) ;
2025-12-22 13:49:44 +11:00
SolGroundCodeBlock codeBlock ;
if ( children . size ( ) < 2 ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Need more stuff to inequal " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-22 13:49:44 +11:00
}
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
std : : string trueLabelIdString = " internal_true " + std : : to_string ( labelIterator + + ) ;
std : : string falseLabelIdString = " internal_false " + std : : to_string ( labelIterator ) ;
std : : string endLabelIdString = " internal_end " + std : : to_string ( labelIterator ) ;
char * trueLabelId = ( char * ) malloc ( sizeof ( char ) * ( trueLabelIdString . size ( ) + 1 ) ) ;
strcpy ( trueLabelId , trueLabelIdString . data ( ) ) ;
char * falseLabelId = ( char * ) malloc ( sizeof ( char ) * ( falseLabelIdString . size ( ) + 1 ) ) ;
strcpy ( falseLabelId , falseLabelIdString . data ( ) ) ;
char * endLabelId = ( char * ) malloc ( sizeof ( char ) * ( endLabelIdString . size ( ) + 1 ) ) ;
strcpy ( endLabelId , endLabelIdString . data ( ) ) ;
// greater $tmp_0 $tmp_1 &cond
GroundInstruction gi = groundCreateInstruction ( GREATER ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , ( char * ) " internal_cond0 " ) ) ;
codeBlock . code . push_back ( gi ) ;
// if &cond %true
gi = groundCreateInstruction ( IF ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , ( char * ) " internal_cond0 " ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LINEREF , trueLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// equal $tmp_0 $tmp_1 &cond
gi = groundCreateInstruction ( EQUAL ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , ( char * ) " internal_cond1 " ) ) ;
codeBlock . code . push_back ( gi ) ;
// if $cond %true
gi = groundCreateInstruction ( IF ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , ( char * ) " internal_cond1 " ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LINEREF , trueLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// jump %false
gi = groundCreateInstruction ( JUMP ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LINEREF , falseLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// @true
gi = groundCreateInstruction ( CREATELABEL ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LABEL , trueLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// set &tmp_x true
gi = groundCreateInstruction ( SET ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
groundAddValueToInstruction ( & gi , groundCreateValue ( BOOL , true ) ) ;
codeBlock . code . push_back ( gi ) ;
// jump %end
gi = groundCreateInstruction ( JUMP ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LINEREF , endLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// @false
gi = groundCreateInstruction ( CREATELABEL ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LABEL , falseLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// set &tmp_x false
gi = groundCreateInstruction ( SET ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
groundAddValueToInstruction ( & gi , groundCreateValue ( BOOL , false ) ) ;
codeBlock . code . push_back ( gi ) ;
// @end
gi = groundCreateInstruction ( CREATELABEL ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LABEL , endLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
if ( isTemp ( children [ 1 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
2025-12-22 13:49:44 +11:00
code . push_back ( codeBlock ) ;
break ;
}
case SolNodeType : : EqLesser : {
2025-12-25 22:37:40 +11:00
ensuresame ( children [ 0 ] , children [ 1 ] , " operator '<=' " ) ;
2025-12-22 13:49:44 +11:00
SolGroundCodeBlock codeBlock ;
if ( children . size ( ) < 2 ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Need more stuff to inequal " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-22 13:49:44 +11:00
}
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
std : : string trueLabelIdString = " internal_true " + std : : to_string ( labelIterator + + ) ;
std : : string falseLabelIdString = " internal_false " + std : : to_string ( labelIterator ) ;
std : : string endLabelIdString = " internal_end " + std : : to_string ( labelIterator ) ;
char * trueLabelId = ( char * ) malloc ( sizeof ( char ) * ( trueLabelIdString . size ( ) + 1 ) ) ;
strcpy ( trueLabelId , trueLabelIdString . data ( ) ) ;
char * falseLabelId = ( char * ) malloc ( sizeof ( char ) * ( falseLabelIdString . size ( ) + 1 ) ) ;
strcpy ( falseLabelId , falseLabelIdString . data ( ) ) ;
char * endLabelId = ( char * ) malloc ( sizeof ( char ) * ( endLabelIdString . size ( ) + 1 ) ) ;
strcpy ( endLabelId , endLabelIdString . data ( ) ) ;
// lesser $tmp_0 $tmp_1 &cond
GroundInstruction gi = groundCreateInstruction ( LESSER ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , ( char * ) " internal_cond0 " ) ) ;
codeBlock . code . push_back ( gi ) ;
// if &cond %true
gi = groundCreateInstruction ( IF ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , ( char * ) " internal_cond0 " ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LINEREF , trueLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// equal $tmp_0 $tmp_1 &cond
gi = groundCreateInstruction ( EQUAL ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , ( char * ) " internal_cond1 " ) ) ;
codeBlock . code . push_back ( gi ) ;
// if $cond %true
gi = groundCreateInstruction ( IF ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , ( char * ) " internal_cond1 " ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LINEREF , trueLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// jump %false
gi = groundCreateInstruction ( JUMP ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LINEREF , falseLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// @true
gi = groundCreateInstruction ( CREATELABEL ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LABEL , trueLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// set &tmp_x true
gi = groundCreateInstruction ( SET ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
groundAddValueToInstruction ( & gi , groundCreateValue ( BOOL , true ) ) ;
codeBlock . code . push_back ( gi ) ;
// jump %end
gi = groundCreateInstruction ( JUMP ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LINEREF , endLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// @false
gi = groundCreateInstruction ( CREATELABEL ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LABEL , falseLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
// set &tmp_x false
gi = groundCreateInstruction ( SET ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
groundAddValueToInstruction ( & gi , groundCreateValue ( BOOL , false ) ) ;
codeBlock . code . push_back ( gi ) ;
// @end
gi = groundCreateInstruction ( CREATELABEL ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( LABEL , endLabelId ) ) ;
codeBlock . code . push_back ( gi ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
if ( isTemp ( children [ 1 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
2025-12-22 13:49:44 +11:00
code . push_back ( codeBlock ) ;
break ;
}
2025-12-21 12:06:55 +11:00
case SolNodeType : : Puts : {
SolGroundCodeBlock codeBlock ;
2025-12-24 14:31:43 +11:00
exists ( children [ 0 ] ) ;
2025-12-21 12:06:55 +11:00
GroundInstruction gi = groundCreateInstruction ( PRINTLN ) ;
if ( children . size ( ) < 1 ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Need more stuff to puts " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-21 12:06:55 +11:00
}
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
codeBlock . code . push_back ( gi ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
2025-12-21 12:06:55 +11:00
code . push_back ( codeBlock ) ;
break ;
}
case SolNodeType : : If : {
2025-12-26 13:28:47 +11:00
ensure ( children [ 0 ] , " bool " , " if condition " ) ;
2025-12-21 12:06:55 +11:00
auto conditionCode = children [ 0 ] . generateCode ( ) ;
code . insert ( code . end ( ) , conditionCode . begin ( ) , conditionCode . end ( ) ) ;
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
SolGroundCodeBlock codeBlock ;
2025-12-22 14:26:12 +11:00
codeBlock . toBeDropped . push_back ( outputId ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 0 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
2025-12-21 12:06:55 +11:00
GroundInstruction gi = groundCreateInstruction ( NOT ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
codeBlock . code . push_back ( gi ) ;
std : : string labelIdString = " if_ " + std : : to_string ( labelIterator + + ) ;
char * labelId = ( char * ) malloc ( sizeof ( char ) * labelIdString . size ( ) + 1 ) ;
strcpy ( labelId , labelIdString . data ( ) ) ;
GroundInstruction gi2 = groundCreateInstruction ( IF ) ;
groundAddReferenceToInstruction ( & gi2 , groundCreateReference ( VALREF , outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi2 , groundCreateReference ( LINEREF , labelId ) ) ;
codeBlock . code . push_back ( gi2 ) ;
code . push_back ( codeBlock ) ;
for ( size_t i = 1 ; i < children . size ( ) ; i + + ) {
auto childCode = children [ i ] . generateCode ( ) ;
code . insert ( code . end ( ) , childCode . begin ( ) , childCode . end ( ) ) ;
}
codeBlock . code . clear ( ) ;
2025-12-22 19:38:06 +11:00
codeBlock . toBeDropped . clear ( ) ;
2025-12-21 12:06:55 +11:00
GroundInstruction gi3 = groundCreateInstruction ( CREATELABEL ) ;
groundAddReferenceToInstruction ( & gi3 , groundCreateReference ( LABEL , labelId ) ) ;
codeBlock . code . push_back ( gi3 ) ;
code . push_back ( codeBlock ) ;
break ;
}
case SolNodeType : : While : {
2025-12-26 13:28:47 +11:00
ensure ( children [ 0 ] , " bool " , " while condition " ) ;
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock startLabelBlock ;
std : : string startLabelIdString = " whilestart_ " + std : : to_string ( labelIterator + + ) ;
std : : string endLabelIdString = " whileend_ " + std : : to_string ( labelIterator ) ;
char * startLabelId = ( char * ) malloc ( sizeof ( char ) * ( startLabelIdString . size ( ) + 1 ) ) ;
strcpy ( startLabelId , startLabelIdString . data ( ) ) ;
char * endLabelId = ( char * ) malloc ( sizeof ( char ) * ( endLabelIdString . size ( ) + 1 ) ) ;
strcpy ( endLabelId , endLabelIdString . data ( ) ) ;
GroundInstruction startLabel = groundCreateInstruction ( CREATELABEL ) ;
groundAddReferenceToInstruction ( & startLabel , groundCreateReference ( LABEL , startLabelId ) ) ;
startLabelBlock . code . push_back ( startLabel ) ;
code . push_back ( startLabelBlock ) ;
auto conditionCode = children [ 0 ] . generateCode ( ) ;
code . insert ( code . end ( ) , conditionCode . begin ( ) , conditionCode . end ( ) ) ;
SolGroundCodeBlock checkBlock ;
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
2025-12-22 14:26:12 +11:00
checkBlock . toBeDropped . push_back ( outputId ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 0 ] . outputId ) ) checkBlock . toBeDropped . push_back ( children [ 0 ] . outputId ) ;
2025-12-21 12:06:55 +11:00
GroundInstruction gi = groundCreateInstruction ( NOT ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
checkBlock . code . push_back ( gi ) ;
GroundInstruction gi2 = groundCreateInstruction ( IF ) ;
groundAddReferenceToInstruction ( & gi2 , groundCreateReference ( VALREF , outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & gi2 , groundCreateReference ( LINEREF , endLabelId ) ) ;
checkBlock . code . push_back ( gi2 ) ;
code . push_back ( checkBlock ) ;
for ( size_t i = 1 ; i < children . size ( ) ; i + + ) {
auto childCode = children [ i ] . generateCode ( ) ;
code . insert ( code . end ( ) , childCode . begin ( ) , childCode . end ( ) ) ;
}
SolGroundCodeBlock endBlock ;
GroundInstruction gi3 = groundCreateInstruction ( JUMP ) ;
groundAddReferenceToInstruction ( & gi3 , groundCreateReference ( LINEREF , startLabelId ) ) ;
endBlock . code . push_back ( gi3 ) ;
GroundInstruction gi4 = groundCreateInstruction ( CREATELABEL ) ;
groundAddReferenceToInstruction ( & gi4 , groundCreateReference ( LABEL , endLabelId ) ) ;
endBlock . code . push_back ( gi4 ) ;
code . push_back ( endBlock ) ;
break ;
}
case SolNodeType : : Identifier : {
break ;
}
case SolNodeType : : Set : {
2025-12-24 13:15:48 +11:00
if ( variables . find ( children [ 0 ] . outputId ) ! = variables . end ( ) ) {
if ( variables [ children [ 0 ] . outputId ] ! = checkNodeReturnType ( children [ 1 ] ) ) {
2025-12-25 22:37:40 +11:00
Error : : typingError ( " Cannot change type of this variable " , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
2025-12-24 13:15:48 +11:00
}
}
2025-12-24 14:31:43 +11:00
exists ( children [ 1 ] ) ;
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock codeBlock ;
GroundInstruction setInstruction = groundCreateInstruction ( SET ) ;
groundAddReferenceToInstruction ( & setInstruction , groundCreateReference ( DIRREF , children [ 0 ] . outputId . data ( ) ) ) ;
groundAddReferenceToInstruction ( & setInstruction , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
codeBlock . code . push_back ( setInstruction ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 1 ] . outputId ) ) codeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
2025-12-21 12:06:55 +11:00
code . push_back ( codeBlock ) ;
2025-12-24 13:15:48 +11:00
// Make sure we know what the variable type is
2025-12-26 13:28:47 +11:00
variables [ children [ 0 ] . outputId ] = children [ 1 ] . data . getTypeString ( ) ;
2025-12-21 12:06:55 +11:00
break ;
}
case SolNodeType : : FunctionCall : {
2025-12-29 10:30:07 +11:00
checkNodeReturnType ( * this ) ;
2025-12-21 12:06:55 +11:00
// Take care of in built functions
2025-12-26 13:28:47 +11:00
// This will be removed when inline ground is added
2025-12-21 12:06:55 +11:00
if ( children [ 0 ] . outputId = = " input " ) {
2025-12-26 13:28:47 +11:00
ensure ( children [ 1 ] , " string " , " input function argument " ) ;
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock inputCodeBlock ;
if ( children . size ( ) > 1 ) {
GroundInstruction printInstruction = groundCreateInstruction ( PRINT ) ;
groundAddReferenceToInstruction ( & printInstruction , groundCreateReference ( VALREF , children [ 1 ] . outputId . data ( ) ) ) ;
inputCodeBlock . code . push_back ( printInstruction ) ;
2025-12-22 19:38:06 +11:00
if ( isTemp ( children [ 1 ] . outputId ) ) inputCodeBlock . toBeDropped . push_back ( children [ 1 ] . outputId ) ;
2025-12-21 12:06:55 +11:00
}
GroundInstruction inputInstruction = groundCreateInstruction ( INPUT ) ;
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
groundAddReferenceToInstruction ( & inputInstruction , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
inputCodeBlock . code . push_back ( inputInstruction ) ;
code . push_back ( inputCodeBlock ) ;
break ;
}
2025-12-26 13:50:14 +11:00
exists ( children [ 0 ] ) ;
2025-12-26 13:28:47 +11:00
std : : string fnToCall = children [ 0 ] . outputId ;
2025-12-28 13:41:05 +11:00
outputId = " tmp_ " + std : : to_string ( tmpIdIterator + + ) ;
SolGroundCodeBlock codeBlock ;
GroundInstruction callInstruction = groundCreateInstruction ( CALL ) ;
groundAddReferenceToInstruction ( & callInstruction , groundCreateReference ( FNREF , children [ 0 ] . outputId . data ( ) ) ) ;
for ( int i = 1 ; i < children . size ( ) ; i + + ) {
groundAddReferenceToInstruction ( & callInstruction , groundCreateReference ( VALREF , children [ i ] . outputId . data ( ) ) ) ;
}
groundAddReferenceToInstruction ( & callInstruction , groundCreateReference ( DIRREF , outputId . data ( ) ) ) ;
codeBlock . code . push_back ( callInstruction ) ;
code . push_back ( codeBlock ) ;
break ;
}
case SolNodeType : : Return : {
2025-12-29 10:30:07 +11:00
std : : string retType = checkNodeReturnType ( children [ 0 ] ) ;
if ( currentFunctionRetType ! = " " & & retType ! = currentFunctionRetType ) {
Error : : typingError ( " Expected return type " + currentFunctionRetType + " but got " + retType , children [ 0 ] . line , children [ 0 ] . lineContent ) ;
}
2025-12-28 13:41:05 +11:00
SolGroundCodeBlock codeBlock ;
GroundInstruction returnInstruction = groundCreateInstruction ( RETURN ) ;
groundAddReferenceToInstruction ( & returnInstruction , groundCreateReference ( VALREF , children [ 0 ] . outputId . data ( ) ) ) ;
codeBlock . code . push_back ( returnInstruction ) ;
code . push_back ( codeBlock ) ;
break ;
}
case SolNodeType : : FunctionDef : {
auto functionopt = data . getFunction ( ) ;
if ( functionopt . has_value ( ) ) {
SolFunction function = functionopt . value ( ) ;
SolGroundCodeBlock codeBlock ;
GroundInstruction inst = groundCreateInstruction ( FUN ) ;
char * fnName = ( char * ) malloc ( sizeof ( char ) * ( function . name . size ( ) + 1 ) ) ;
strcpy ( fnName , function . name . c_str ( ) ) ;
char * retType = ( char * ) malloc ( sizeof ( char ) * ( function . returnType . size ( ) + 1 ) ) ;
strcpy ( retType , function . returnType . c_str ( ) ) ;
groundAddReferenceToInstruction ( & inst , groundCreateReference ( FNREF , fnName ) ) ;
groundAddReferenceToInstruction ( & inst , groundCreateReference ( TYPEREF , retType ) ) ;
2025-12-29 10:30:07 +11:00
// Scope Management
2025-12-28 13:41:05 +11:00
auto variablebackup = variables ;
2025-12-29 10:30:07 +11:00
std : : string oldRetType = currentFunctionRetType ;
variables . clear ( ) ;
currentFunctionRetType = function . returnType ;
2025-12-28 13:41:05 +11:00
for ( auto & pair : function . parameters ) {
groundAddReferenceToInstruction ( & inst , groundCreateReference ( TYPEREF , pair . second . data ( ) ) ) ;
groundAddReferenceToInstruction ( & inst , groundCreateReference ( DIRREF , pair . first . data ( ) ) ) ;
2025-12-29 10:30:07 +11:00
variables [ pair . first ] = pair . second ; // Correctly map Name -> Type
2025-12-28 13:41:05 +11:00
}
2025-12-29 10:30:07 +11:00
2025-12-28 13:41:05 +11:00
codeBlock . code . push_back ( inst ) ;
code . push_back ( codeBlock ) ;
codeBlock . code . clear ( ) ;
2025-12-29 10:30:07 +11:00
// Generate body code with local variables visible
2025-12-28 13:41:05 +11:00
auto childCode = function . content - > generateCode ( ) ;
code . insert ( code . end ( ) , childCode . begin ( ) , childCode . end ( ) ) ;
2025-12-29 10:30:07 +11:00
2025-12-28 13:41:05 +11:00
codeBlock . code . push_back ( groundCreateInstruction ( ENDFUN ) ) ;
code . push_back ( codeBlock ) ;
2025-12-29 10:30:07 +11:00
// Restore Scope
variables = variablebackup ;
currentFunctionRetType = oldRetType ;
2025-12-28 13:41:05 +11:00
}
2025-12-21 12:06:55 +11:00
break ;
}
default : { }
}
return code ;
}
// Parser Implementation
2025-12-25 22:37:40 +11:00
Parser : : Parser ( std : : vector < Token > in ) : tokensToParse ( in ) { }
2025-12-21 12:06:55 +11:00
2025-12-25 22:37:40 +11:00
std : : optional < Token > Parser : : peek ( int ahead ) {
2025-12-21 12:06:55 +11:00
if ( current + ahead < size ) {
return tokensToParse [ current + ahead ] ;
} else {
return { } ;
}
}
2025-12-25 22:37:40 +11:00
std : : optional < Token > Parser : : consume ( ) {
2025-12-21 12:06:55 +11:00
if ( current < size ) {
return tokensToParse [ current + + ] ;
} else {
return { } ;
}
}
// Helper functions
bool Parser : : isInt ( std : : string in ) {
for ( const char & c : in ) {
if ( ! std : : isdigit ( c ) ) {
return false ;
}
}
return true ;
}
bool Parser : : isDouble ( std : : string in ) {
bool foundDot = false ;
for ( const char & c : in ) {
if ( ! std : : isdigit ( c ) ) {
if ( ! foundDot & & c = = ' . ' ) {
foundDot = true ;
continue ;
}
return false ;
}
}
return true ;
}
bool Parser : : isString ( std : : string in ) {
if ( in . size ( ) > 1 & & in [ 0 ] = = ' " ' & & in . back ( ) = = ' " ' ) {
return true ;
}
return false ;
}
bool Parser : : isChar ( std : : string in ) {
if ( in . size ( ) = = 3 & & in [ 0 ] = = ' \' ' & & in . back ( ) = = ' \' ' ) {
return true ;
}
return false ;
}
bool Parser : : isBool ( std : : string in ) {
if ( in = = " true " | | in = = " false " ) {
return true ;
}
return false ;
}
SolDataType Parser : : getDataType ( std : : string in ) {
if ( isInt ( in ) ) {
return SolDataType : : Int ;
}
if ( isDouble ( in ) ) {
return SolDataType : : Double ;
}
if ( isString ( in ) ) {
return SolDataType : : String ;
}
if ( isChar ( in ) ) {
return SolDataType : : Char ;
}
if ( isBool ( in ) ) {
return SolDataType : : Bool ;
}
return SolDataType : : None ;
}
SolNodeType Parser : : getNodeType ( std : : string in ) {
if ( getDataType ( in ) ! = SolDataType : : None ) {
return SolNodeType : : Value ;
}
if ( in = = " + " ) {
return SolNodeType : : Add ;
}
2025-12-24 14:31:43 +11:00
if ( in = = " - " ) {
return SolNodeType : : Subtract ;
}
if ( in = = " * " ) {
return SolNodeType : : Multiply ;
}
if ( in = = " / " ) {
return SolNodeType : : Divide ;
}
2025-12-21 12:06:55 +11:00
if ( in = = " = " ) {
return SolNodeType : : Set ;
}
if ( in = = " == " ) {
return SolNodeType : : Equal ;
}
if ( in = = " != " ) {
return SolNodeType : : Inequal ;
}
2025-12-22 13:49:44 +11:00
if ( in = = " >= " ) {
return SolNodeType : : EqGreater ;
}
if ( in = = " <= " ) {
return SolNodeType : : EqLesser ;
}
if ( in = = " > " ) {
return SolNodeType : : Greater ;
}
if ( in = = " < " ) {
return SolNodeType : : Lesser ;
}
2025-12-21 12:06:55 +11:00
if ( in = = " puts " ) {
return SolNodeType : : Puts ;
}
if ( in = = " if " ) {
return SolNodeType : : If ;
}
if ( in = = " while " ) {
return SolNodeType : : While ;
}
2025-12-26 13:28:47 +11:00
if ( in = = " def " ) {
return SolNodeType : : FunctionDef ;
}
2025-12-28 13:41:05 +11:00
if ( in = = " return " ) {
return SolNodeType : : Return ;
}
2025-12-21 12:06:55 +11:00
if ( in = = " { " ) {
return SolNodeType : : CodeBlockStart ;
}
if ( in = = " } " ) {
return SolNodeType : : CodeBlockEnd ;
}
if ( in = = " ( " ) {
return SolNodeType : : BracketStart ;
}
if ( in = = " ) " ) {
return SolNodeType : : BracketEnd ;
}
return SolNodeType : : Identifier ;
}
2025-12-24 22:01:16 +11:00
int Parser : : getPrecedence ( std : : string token ) {
if ( token = = " * " | | token = = " / " ) return 2 ;
if ( token = = " + " | | token = = " - " ) return 1 ;
return 0 ;
}
SolNode Parser : : parsePrimary ( ) {
auto tokenopt = consume ( ) ;
if ( ! tokenopt ) {
2025-12-25 22:37:40 +11:00
Error : : syntaxError ( " Unexpected end of input " ) ;
2025-12-24 22:01:16 +11:00
}
2025-12-25 22:37:40 +11:00
Token tokenObj = tokenopt . value ( ) ;
std : : string token = tokenObj . value ;
2025-12-24 22:01:16 +11:00
SolNodeType type = getNodeType ( token ) ;
if ( type = = SolNodeType : : Value ) {
SolNode node ( SolNodeType : : Value ) ;
2025-12-25 22:37:40 +11:00
node . line = tokenObj . line ;
node . lineContent = tokenObj . lineContent ;
2025-12-24 22:01:16 +11:00
switch ( getDataType ( token ) ) {
case SolDataType : : Int : node . setValue ( ( int64_t ) std : : stoll ( token ) ) ; break ;
case SolDataType : : Double : node . setValue ( std : : stod ( token ) ) ; break ;
case SolDataType : : String : node . setValue ( token . substr ( 1 , token . size ( ) - 2 ) ) ; break ;
case SolDataType : : Char : node . setValue ( token [ 1 ] ) ; break ;
case SolDataType : : Bool : node . setValue ( token = = " true " ) ; break ;
default : break ;
}
return node ;
}
if ( type = = SolNodeType : : Identifier ) {
SolNode idNode ( SolNodeType : : Identifier ) ;
idNode . outputId = token ;
2025-12-25 22:37:40 +11:00
idNode . line = tokenObj . line ;
idNode . lineContent = tokenObj . lineContent ;
auto peekOpt = peek ( ) ;
if ( peekOpt . has_value ( ) & & peekOpt . value ( ) . value = = " ( " ) {
2025-12-24 22:01:16 +11:00
consume ( ) ; // (
SolNode fnCallNode ( SolNodeType : : FunctionCall ) ;
2025-12-25 22:37:40 +11:00
fnCallNode . line = tokenObj . line ;
fnCallNode . lineContent = tokenObj . lineContent ;
2025-12-24 22:01:16 +11:00
fnCallNode . addNode ( idNode ) ;
2025-12-25 22:37:40 +11:00
std : : vector < Token > tokens ;
2025-12-24 22:01:16 +11:00
size_t brackets = 1 ;
while ( auto t = consume ( ) ) {
2025-12-25 22:37:40 +11:00
if ( t . value ( ) . value = = " ( " ) brackets + + ;
if ( t . value ( ) . value = = " ) " ) brackets - - ;
2025-12-24 22:01:16 +11:00
if ( brackets = = 0 ) break ;
tokens . push_back ( t . value ( ) ) ;
}
2025-12-25 22:37:40 +11:00
if ( brackets ! = 0 ) {
Error : : syntaxError ( " Unclosed function call bracket " , tokenObj . line , tokenObj . lineContent ) ;
}
2025-12-24 22:01:16 +11:00
auto args = Parser ( tokens ) . parse ( ) ;
for ( auto & child : args . children ) fnCallNode . addNode ( child ) ;
return fnCallNode ;
}
return idNode ;
}
if ( type = = SolNodeType : : BracketStart ) {
2025-12-25 22:37:40 +11:00
std : : vector < Token > tokens ;
2025-12-24 22:01:16 +11:00
size_t brackets = 1 ;
while ( auto t = consume ( ) ) {
2025-12-25 22:37:40 +11:00
if ( t . value ( ) . value = = " ( " ) brackets + + ;
if ( t . value ( ) . value = = " ) " ) brackets - - ;
2025-12-24 22:01:16 +11:00
if ( brackets = = 0 ) break ;
tokens . push_back ( t . value ( ) ) ;
}
2025-12-25 22:37:40 +11:00
if ( brackets ! = 0 ) {
Error : : syntaxError ( " Unclosed bracket " , tokenObj . line , tokenObj . lineContent ) ;
}
2025-12-24 22:01:16 +11:00
auto inner = Parser ( tokens ) . parse ( ) ;
if ( inner . children . size ( ) > 0 ) return inner . children [ 0 ] ;
return SolNode ( SolNodeType : : None ) ;
}
2025-12-25 22:37:40 +11:00
Error : : syntaxError ( " Unexpected token in expression: " + token , tokenObj . line , tokenObj . lineContent ) ;
2025-12-28 13:41:05 +11:00
return SolNode ( SolNodeType : : None ) ;
2025-12-24 22:01:16 +11:00
}
SolNode Parser : : parseExpression ( int minPrec ) {
SolNode lhs = parsePrimary ( ) ;
while ( true ) {
auto opOpt = peek ( ) ;
if ( ! opOpt ) break ;
2025-12-25 22:37:40 +11:00
Token opToken = opOpt . value ( ) ;
std : : string op = opToken . value ;
2025-12-24 22:01:16 +11:00
int prec = getPrecedence ( op ) ;
if ( prec < minPrec ) break ;
consume ( ) ;
SolNode rhs = parseExpression ( prec + 1 ) ;
SolNode newNode ( getNodeType ( op ) ) ;
2025-12-25 22:37:40 +11:00
newNode . line = opToken . line ;
newNode . lineContent = opToken . lineContent ;
2025-12-24 22:01:16 +11:00
newNode . addNode ( lhs ) ;
newNode . addNode ( rhs ) ;
lhs = newNode ;
}
return lhs ;
}
2025-12-21 12:06:55 +11:00
SolNode Parser : : parse ( ) {
current = 0 ;
size = tokensToParse . size ( ) ;
SolNode rootNode ( SolNodeType : : Root ) ;
while ( auto tokenopt = consume ( ) ) {
2025-12-25 22:37:40 +11:00
Token tokenObj = tokenopt . value ( ) ;
std : : string token = tokenObj . value ;
2025-12-21 12:06:55 +11:00
switch ( getNodeType ( token ) ) {
case SolNodeType : : Value : {
switch ( getDataType ( token ) ) {
case SolDataType : : Int : {
SolNode intNode ( SolNodeType : : Value ) ;
intNode . setValue ( ( int64_t ) std : : stoll ( token ) ) ;
2025-12-25 22:37:40 +11:00
intNode . line = tokenObj . line ;
intNode . lineContent = tokenObj . lineContent ;
2025-12-21 12:06:55 +11:00
rootNode . addNode ( intNode ) ;
break ;
}
case SolDataType : : Double : {
SolNode doubleNode ( SolNodeType : : Value ) ;
doubleNode . setValue ( std : : stod ( token ) ) ;
2025-12-25 22:37:40 +11:00
doubleNode . line = tokenObj . line ;
doubleNode . lineContent = tokenObj . lineContent ;
2025-12-21 12:06:55 +11:00
rootNode . addNode ( doubleNode ) ;
break ;
}
case SolDataType : : String : {
SolNode stringNode ( SolNodeType : : Value ) ;
stringNode . setValue ( token . substr ( 1 , token . size ( ) - 2 ) ) ;
2025-12-25 22:37:40 +11:00
stringNode . line = tokenObj . line ;
stringNode . lineContent = tokenObj . lineContent ;
2025-12-21 12:06:55 +11:00
rootNode . addNode ( stringNode ) ;
break ;
}
case SolDataType : : Char : {
SolNode charNode ( SolNodeType : : Value ) ;
charNode . setValue ( token [ 1 ] ) ;
2025-12-25 22:37:40 +11:00
charNode . line = tokenObj . line ;
charNode . lineContent = tokenObj . lineContent ;
2025-12-21 12:06:55 +11:00
rootNode . addNode ( charNode ) ;
break ;
}
case SolDataType : : Bool : {
SolNode boolNode ( SolNodeType : : Value ) ;
boolNode . setValue ( token = = " true " ) ;
2025-12-25 22:37:40 +11:00
boolNode . line = tokenObj . line ;
boolNode . lineContent = tokenObj . lineContent ;
2025-12-21 12:06:55 +11:00
rootNode . addNode ( boolNode ) ;
break ;
}
}
break ;
}
2025-12-24 14:31:43 +11:00
case SolNodeType : : Add :
case SolNodeType : : Subtract :
case SolNodeType : : Multiply :
case SolNodeType : : Divide :
{
2025-12-24 22:01:16 +11:00
SolNode opNode ( getNodeType ( token ) ) ;
2025-12-25 22:37:40 +11:00
opNode . line = tokenObj . line ;
opNode . lineContent = tokenObj . lineContent ;
2025-12-24 22:01:16 +11:00
if ( rootNode . children . empty ( ) ) {
2025-12-25 22:37:40 +11:00
Error : : syntaxError ( " Expected operand before operator " , tokenObj . line , tokenObj . lineContent ) ;
2025-12-21 12:06:55 +11:00
}
2025-12-24 22:01:16 +11:00
opNode . addNode ( rootNode . children . back ( ) ) ;
rootNode . children . pop_back ( ) ;
// Parse RHS with higher precedence
SolNode rhs = parseExpression ( getPrecedence ( token ) + 1 ) ;
opNode . addNode ( rhs ) ;
rootNode . addNode ( opNode ) ;
2025-12-21 12:06:55 +11:00
break ;
}
2025-12-22 13:49:44 +11:00
case SolNodeType : : Equal :
case SolNodeType : : Inequal :
case SolNodeType : : Lesser :
case SolNodeType : : Greater :
case SolNodeType : : EqLesser :
case SolNodeType : : EqGreater :
{
SolNode equalNode ( getNodeType ( token ) ) ;
2025-12-25 22:37:40 +11:00
equalNode . line = tokenObj . line ;
equalNode . lineContent = tokenObj . lineContent ;
2025-12-22 13:49:44 +11:00
if ( rootNode . children . empty ( ) ) {
2025-12-25 22:37:40 +11:00
Error : : syntaxError ( " Expected operand before comparison " , tokenObj . line , tokenObj . lineContent ) ;
2025-12-21 12:06:55 +11:00
}
2025-12-22 13:49:44 +11:00
equalNode . addNode ( rootNode . children . back ( ) ) ;
2025-12-21 12:06:55 +11:00
rootNode . children . pop_back ( ) ;
2025-12-25 22:37:40 +11:00
std : : vector < Token > tokens ;
2025-12-22 13:49:44 +11:00
while ( auto tokenopt = consume ( ) ) {
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " \n " ) {
2025-12-22 13:49:44 +11:00
break ;
}
tokens . push_back ( tokenopt . value ( ) ) ;
2025-12-21 12:06:55 +11:00
}
2025-12-22 13:49:44 +11:00
auto children = Parser ( tokens ) . parse ( ) ;
equalNode . addNode ( children . children [ 0 ] ) ;
rootNode . addNode ( equalNode ) ;
2025-12-21 12:06:55 +11:00
break ;
}
case SolNodeType : : Puts : {
SolNode putsNode ( SolNodeType : : Puts ) ;
2025-12-25 22:37:40 +11:00
putsNode . line = tokenObj . line ;
putsNode . lineContent = tokenObj . lineContent ;
std : : vector < Token > tokens ;
2025-12-21 12:06:55 +11:00
while ( auto tokenopt = consume ( ) ) {
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " \n " ) {
2025-12-21 12:06:55 +11:00
break ;
}
tokens . push_back ( tokenopt . value ( ) ) ;
}
auto children = Parser ( tokens ) . parse ( ) ;
for ( auto & child : children . children ) {
putsNode . addNode ( child ) ;
}
rootNode . addNode ( putsNode ) ;
break ;
}
case SolNodeType : : If : {
SolNode ifNode ( SolNodeType : : If ) ;
2025-12-25 22:37:40 +11:00
ifNode . line = tokenObj . line ;
ifNode . lineContent = tokenObj . lineContent ;
std : : vector < Token > tokens ;
2025-12-21 12:06:55 +11:00
while ( auto tokenopt = consume ( ) ) {
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " \n " ) {
2025-12-21 12:06:55 +11:00
break ;
}
tokens . push_back ( tokenopt . value ( ) ) ;
}
auto children = Parser ( tokens ) . parse ( ) ;
ifNode . addNode ( children . children [ 0 ] ) ;
tokens . clear ( ) ;
size_t brackets = 1 ;
auto tokenopt = consume ( ) ;
if ( tokenopt ) {
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " { " ) {
2025-12-21 12:06:55 +11:00
tokens . push_back ( tokenopt . value ( ) ) ;
while ( auto tokenopt = consume ( ) ) {
tokens . push_back ( tokenopt . value ( ) ) ;
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " { " ) {
2025-12-21 12:06:55 +11:00
brackets + + ;
}
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " } " ) {
2025-12-21 12:06:55 +11:00
brackets - - ;
}
if ( brackets = = 0 ) {
break ;
}
}
2025-12-25 22:37:40 +11:00
if ( brackets ! = 0 ) {
Error : : syntaxError ( " Unclosed code block " , tokenopt . value ( ) . line , tokenopt . value ( ) . lineContent ) ;
}
2025-12-21 12:06:55 +11:00
} else {
2025-12-25 22:37:40 +11:00
Error : : syntaxError ( " I want a code block instead of a " + tokenopt . value ( ) . value , tokenopt . value ( ) . line , tokenopt . value ( ) . lineContent ) ;
2025-12-21 12:06:55 +11:00
}
} else {
2025-12-25 22:37:40 +11:00
Error : : syntaxError ( " Expected code block after if condition " , ifNode . line , ifNode . lineContent ) ;
2025-12-21 12:06:55 +11:00
}
auto childCodeBlock = Parser ( tokens ) . parse ( ) ;
ifNode . addNode ( childCodeBlock . children [ 0 ] ) ;
rootNode . addNode ( ifNode ) ;
break ;
}
case SolNodeType : : While : {
SolNode whileNode ( SolNodeType : : While ) ;
2025-12-25 22:37:40 +11:00
whileNode . line = tokenObj . line ;
whileNode . lineContent = tokenObj . lineContent ;
std : : vector < Token > tokens ;
2025-12-21 12:06:55 +11:00
while ( auto tokenopt = consume ( ) ) {
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " \n " ) {
2025-12-21 12:06:55 +11:00
break ;
}
tokens . push_back ( tokenopt . value ( ) ) ;
}
auto children = Parser ( tokens ) . parse ( ) ;
whileNode . addNode ( children . children [ 0 ] ) ;
tokens . clear ( ) ;
size_t brackets = 1 ;
auto tokenopt = consume ( ) ;
if ( tokenopt ) {
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " { " ) {
2025-12-21 12:06:55 +11:00
tokens . push_back ( tokenopt . value ( ) ) ;
while ( auto tokenopt = consume ( ) ) {
tokens . push_back ( tokenopt . value ( ) ) ;
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " { " ) {
2025-12-21 12:06:55 +11:00
brackets + + ;
}
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " } " ) {
2025-12-21 12:06:55 +11:00
brackets - - ;
}
if ( brackets = = 0 ) {
break ;
}
}
2025-12-25 22:37:40 +11:00
if ( brackets ! = 0 ) {
Error : : syntaxError ( " Unclosed code block " , tokenopt . value ( ) . line , tokenopt . value ( ) . lineContent ) ;
}
2025-12-21 12:06:55 +11:00
} else {
2025-12-25 22:37:40 +11:00
Error : : syntaxError ( " I want a code block instead of a " + tokenopt . value ( ) . value , tokenopt . value ( ) . line , tokenopt . value ( ) . lineContent ) ;
2025-12-21 12:06:55 +11:00
}
} else {
2025-12-25 22:37:40 +11:00
Error : : syntaxError ( " Expected code block after while condition " , whileNode . line , whileNode . lineContent ) ;
2025-12-21 12:06:55 +11:00
}
auto childCodeBlock = Parser ( tokens ) . parse ( ) ;
whileNode . addNode ( childCodeBlock . children [ 0 ] ) ;
rootNode . addNode ( whileNode ) ;
break ;
}
case SolNodeType : : CodeBlockStart : {
SolNode codeBlockNode ( SolNodeType : : CodeBlock ) ;
2025-12-25 22:37:40 +11:00
codeBlockNode . line = tokenObj . line ;
codeBlockNode . lineContent = tokenObj . lineContent ;
2025-12-21 12:06:55 +11:00
size_t brackets = 1 ;
2025-12-25 22:37:40 +11:00
std : : vector < Token > tokens ;
2025-12-21 12:06:55 +11:00
while ( auto tokenopt = consume ( ) ) {
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " { " ) {
2025-12-21 12:06:55 +11:00
brackets + + ;
}
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " } " ) {
2025-12-21 12:06:55 +11:00
brackets - - ;
}
if ( brackets = = 0 ) {
break ;
}
tokens . push_back ( tokenopt . value ( ) ) ;
}
2025-12-25 22:37:40 +11:00
if ( brackets ! = 0 ) {
Error : : syntaxError ( " Unclosed code block " , tokenObj . line , tokenObj . lineContent ) ;
}
2025-12-21 12:06:55 +11:00
codeBlockNode . children = Parser ( tokens ) . parse ( ) . children ;
rootNode . addNode ( codeBlockNode ) ;
break ;
}
case SolNodeType : : Identifier : {
SolNode idNode ( SolNodeType : : Identifier ) ;
idNode . outputId = token ;
2025-12-25 22:37:40 +11:00
idNode . line = tokenObj . line ;
idNode . lineContent = tokenObj . lineContent ;
2025-12-21 12:06:55 +11:00
rootNode . addNode ( idNode ) ;
break ;
}
case SolNodeType : : Set : {
SolNode setNode ( SolNodeType : : Set ) ;
2025-12-25 22:37:40 +11:00
setNode . line = tokenObj . line ;
setNode . lineContent = tokenObj . lineContent ;
2025-12-21 12:06:55 +11:00
setNode . addNode ( rootNode . children . back ( ) ) ;
rootNode . children . pop_back ( ) ;
2025-12-25 22:37:40 +11:00
std : : vector < Token > tokens ;
2025-12-21 12:06:55 +11:00
while ( auto tokenopt = consume ( ) ) {
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " \n " ) {
2025-12-21 12:06:55 +11:00
break ;
}
tokens . push_back ( tokenopt . value ( ) ) ;
}
auto children = Parser ( tokens ) . parse ( ) ;
setNode . addNode ( children . children [ 0 ] ) ;
rootNode . addNode ( setNode ) ;
break ;
}
case SolNodeType : : BracketStart : {
2025-12-28 13:49:05 +11:00
// function call
2025-12-21 12:06:55 +11:00
if ( rootNode . children . back ( ) . nodeType = = SolNodeType : : Identifier ) {
SolNode fnCallNode ( SolNodeType : : FunctionCall ) ;
2025-12-25 22:37:40 +11:00
fnCallNode . line = tokenObj . line ;
fnCallNode . lineContent = tokenObj . lineContent ;
2025-12-21 12:06:55 +11:00
fnCallNode . addNode ( rootNode . children . back ( ) ) ;
rootNode . children . pop_back ( ) ;
2025-12-25 22:37:40 +11:00
std : : vector < Token > tokens ;
2025-12-21 12:06:55 +11:00
size_t brackets = 1 ;
while ( auto tokenopt = consume ( ) ) {
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " ( " ) {
2025-12-21 12:06:55 +11:00
brackets + + ;
}
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " ) " ) {
2025-12-21 12:06:55 +11:00
brackets - - ;
}
2025-12-28 13:49:05 +11:00
// comma, eval statement here
if ( tokenopt . value ( ) . value = = " , " & & brackets = = 1 ) {
auto node = Parser ( tokens ) . parse ( ) ;
if ( ! node . children . empty ( ) ) fnCallNode . children . push_back ( node . children [ 0 ] ) ;
else {
Error : : syntaxError ( " dingus " ) ;
}
tokens . clear ( ) ;
continue ;
}
2025-12-21 12:06:55 +11:00
if ( brackets < 1 ) {
break ;
}
tokens . push_back ( tokenopt . value ( ) ) ;
}
auto node = Parser ( tokens ) . parse ( ) ;
fnCallNode . children . insert ( fnCallNode . children . end ( ) , node . children . begin ( ) , node . children . end ( ) ) ;
rootNode . addNode ( fnCallNode ) ;
} else {
2025-12-25 22:37:40 +11:00
std : : vector < Token > tokens ;
2025-12-21 12:06:55 +11:00
size_t brackets = 1 ;
while ( auto tokenopt = consume ( ) ) {
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " ( " ) {
2025-12-21 12:06:55 +11:00
brackets + + ;
}
2025-12-25 22:37:40 +11:00
if ( tokenopt . value ( ) . value = = " ) " ) {
2025-12-21 12:06:55 +11:00
brackets - - ;
}
if ( brackets < 1 ) {
break ;
}
tokens . push_back ( tokenopt . value ( ) ) ;
}
auto node = Parser ( tokens ) . parse ( ) ;
node . nodeType = SolNodeType : : Expression ;
rootNode . addNode ( node ) ;
}
2025-12-26 13:50:14 +11:00
break ;
2025-12-21 12:06:55 +11:00
}
2025-12-26 13:28:47 +11:00
case SolNodeType : : FunctionDef : {
SolFunction fn ;
auto nameTokenOpt = consume ( ) ;
if ( ! nameTokenOpt | | getNodeType ( nameTokenOpt . value ( ) . value ) ! = SolNodeType : : Identifier ) {
Error : : syntaxError ( " Expected function name " , tokenObj . line , tokenObj . lineContent ) ;
}
2025-12-28 13:41:05 +11:00
fn . name = nameTokenOpt . value ( ) . value ;
2025-12-26 13:28:47 +11:00
auto openParen = consume ( ) ;
if ( ! openParen | | openParen . value ( ) . value ! = " ( " ) {
Error : : syntaxError ( " Expected '(' after function name " , tokenObj . line , tokenObj . lineContent ) ;
}
std : : string signature = " fun( " ;
bool first = true ;
while ( auto next = peek ( ) ) {
if ( next . value ( ) . value = = " ) " ) {
consume ( ) ;
break ;
}
if ( ! first ) {
auto comma = consume ( ) ;
if ( comma . value ( ) . value ! = " , " ) {
Error : : syntaxError ( " Expected ',' between arguments " , tokenObj . line , tokenObj . lineContent ) ;
}
}
auto typeToken = consume ( ) ;
if ( ! typeToken ) Error : : syntaxError ( " Expected type " , tokenObj . line , tokenObj . lineContent ) ;
std : : string argType = typeToken . value ( ) . value ;
auto argNameToken = consume ( ) ;
if ( ! argNameToken ) Error : : syntaxError ( " Expected argument name " , tokenObj . line , tokenObj . lineContent ) ;
std : : string argName = argNameToken . value ( ) . value ;
fn . parameters . push_back ( { argName , argType } ) ;
if ( ! first ) signature + = " , " ;
signature + = argType ;
first = false ;
}
signature + = " ) " ;
while ( peek ( ) & & peek ( ) . value ( ) . value = = " \n " ) consume ( ) ;
auto next = peek ( ) ;
if ( next & & next . value ( ) . value ! = " { " ) {
auto retTypeToken = consume ( ) ;
fn . returnType = retTypeToken . value ( ) . value ;
} else {
fn . returnType = " void " ;
}
signature + = fn . returnType ;
fn . signature = signature ;
while ( peek ( ) & & peek ( ) . value ( ) . value = = " \n " ) consume ( ) ;
auto brace = peek ( ) ;
if ( ! brace | | brace . value ( ) . value ! = " { " ) {
Error : : syntaxError ( " Expected '{' starting function body " , tokenObj . line , tokenObj . lineContent ) ;
}
consume ( ) ;
std : : vector < Token > bodyTokens ;
size_t brackets = 1 ;
while ( auto t = consume ( ) ) {
if ( t . value ( ) . value = = " { " ) brackets + + ;
if ( t . value ( ) . value = = " } " ) brackets - - ;
if ( brackets = = 0 ) break ;
bodyTokens . push_back ( t . value ( ) ) ;
}
if ( brackets ! = 0 ) Error : : syntaxError ( " Unclosed function body " , tokenObj . line , tokenObj . lineContent ) ;
auto parsedBody = Parser ( bodyTokens ) . parse ( ) ;
auto bodyNode = std : : make_shared < SolNode > ( SolNodeType : : CodeBlock ) ;
bodyNode - > children = parsedBody . children ;
fn . content = bodyNode ;
SolNode fnNode ( SolNodeType : : FunctionDef ) ;
fnNode . data = SolData ( fn ) ;
2025-12-28 13:41:05 +11:00
variables [ fn . name ] = signature ;
2025-12-26 13:28:47 +11:00
rootNode . addNode ( fnNode ) ;
break ;
}
2025-12-28 13:41:05 +11:00
case SolNodeType : : Return : {
SolNode returnNode ( SolNodeType : : Return ) ;
returnNode . line = tokenObj . line ;
returnNode . lineContent = tokenObj . lineContent ;
std : : vector < Token > tokens ;
while ( auto tokenopt = consume ( ) ) {
if ( tokenopt . value ( ) . value = = " \n " ) {
break ;
}
tokens . push_back ( tokenopt . value ( ) ) ;
}
auto children = Parser ( tokens ) . parse ( ) ;
for ( auto & child : children . children ) {
returnNode . addNode ( child ) ;
}
rootNode . addNode ( returnNode ) ;
break ;
}
2025-12-21 12:06:55 +11:00
}
}
return rootNode ;
}
GroundProgram assembleProgram ( SolNode & rootNode ) {
GroundProgram gp = groundCreateProgram ( ) ;
auto code = rootNode . generateCode ( ) ;
for ( int i = 0 ; i < code . size ( ) ; i + + ) {
for ( const auto & inst : code [ i ] . code ) {
groundAddInstructionToProgram ( & gp , inst ) ;
}
2025-12-22 14:26:12 +11:00
for ( auto & tmpVar : code [ i ] . toBeDropped ) {
GroundInstruction gi = groundCreateInstruction ( DROP ) ;
2025-12-22 19:38:06 +11:00
char * droppedVar = ( char * ) malloc ( tmpVar . size ( ) + 1 ) ;
strcpy ( droppedVar , tmpVar . c_str ( ) ) ;
groundAddReferenceToInstruction ( & gi , groundCreateReference ( DIRREF , droppedVar ) ) ;
2025-12-22 14:26:12 +11:00
groundAddInstructionToProgram ( & gp , gi ) ;
}
2025-12-21 12:06:55 +11:00
}
return gp ;
}
} // namespace Parser
2025-12-26 13:28:47 +11:00
}