2024-01-20 11:18:57 +00:00
# include "generated/vn_scene2.meta.c"
////////////////////////////////
//~ sixten: Scene Message Functions
static void S2_PushMessage ( arena * Arena , scene2_message_list * List , token Token , string Message )
{
scene2_message * Node = PushStruct ( Arena , scene2_message ) ;
Node - > Message = PushString ( Arena , Message ) ;
Node - > Token = Token ;
QueuePush ( List - > First , List - > Last , Node ) ;
List - > Count + = 1 ;
}
static void S2_PushMessageFV ( arena * Arena , scene2_message_list * List , token Token , char * Format , va_list Arguments )
{
scene2_message * Node = PushStruct ( Arena , scene2_message ) ;
Node - > Message = PushFormatVariadic ( Arena , Format , Arguments ) ;
Node - > Token = Token ;
QueuePush ( List - > First , List - > Last , Node ) ;
List - > Count + = 1 ;
}
static void S2_PushMessageF ( arena * Arena , scene2_message_list * List , token Token , char * Format , . . . )
{
va_list Arguments ;
va_start ( Arguments , Format ) ;
S2_PushMessageFV ( Arena , List , Token , Format , Arguments ) ;
va_end ( Arguments ) ;
}
static scene2_message_list S2_CopyMessageList ( arena * Arena , scene2_message_list * Source )
{
scene2_message_list List = { } ;
for ( scene2_message * Message = Source - > First ; Message ! = 0 ; Message = Message - > Next )
{
S2_PushMessage ( Arena , & List , Message - > Token , Message - > Message ) ;
}
return ( List ) ;
}
static void S2_ConcatMessageList ( arena * Arena , scene2_message_list * Dest , scene2_message_list * Source )
{
for ( scene2_message * Message = Source - > First ; Message ! = 0 ; Message = Message - > Next )
{
S2_PushMessage ( Arena , Dest , Message - > Token , Message - > Message ) ;
}
}
////////////////////////////////
//~ sixten: Scene Action Functions
static void S2_SceneActionPush ( scene2_action_list * List , scene2_action * Action )
{
QueuePush ( List - > First , List - > Last , Action ) ;
List - > Count + = 1 ;
}
////////////////////////////////
//~ sixten: Scene Parsing Helpers
static token S2_Token ( scene2_compiler * Compiler )
{
token Token = { } ;
if ( Compiler - > At > = 0 & & Compiler - > At < Compiler - > Tokens . Count )
{
Token = Compiler - > Tokens . Tokens [ Compiler - > At ] ;
}
return ( Token ) ;
}
static token S2_NextToken ( scene2_compiler * Compiler )
{
token Token = { } ;
if ( Compiler - > At + 1 > = 0 & & Compiler - > At + 1 < Compiler - > Tokens . Count )
{
Token = Compiler - > Tokens . Tokens [ Compiler - > At + 1 ] ;
}
return ( Token ) ;
}
static string S2_StringFromToken ( scene2_compiler * Compiler , token Token )
{
string Result = Substring ( Compiler - > Source , Intersection ( Token . Range , Range1S64 ( 0 , Compiler - > Source . Count ) ) ) ;
return ( Result ) ;
}
static string S2_TokenString ( scene2_compiler * Compiler )
{
string Result = S2_StringFromToken ( Compiler , S2_Token ( Compiler ) ) ;
return ( Result ) ;
}
static void S2_ParseError ( scene2_compiler * Compiler , token Token , string Message )
{
S2_PushMessage ( Compiler - > Arena , & Compiler - > Messages , Token , Message ) ;
Compiler - > InPanicMode = true ;
}
static token S2_Consume ( scene2_compiler * Compiler , token_kind Expected , string Message )
{
if ( S2_Token ( Compiler ) . Kind ! = Expected )
{
S2_ParseError ( Compiler , S2_Token ( Compiler ) , Message ) ;
}
token Result = Compiler - > Tokens . Tokens [ Compiler - > At ] ;
S2_Advance ( Compiler ) ;
return ( Result ) ;
}
static void S2_Advance ( scene2_compiler * Compiler )
{
Compiler - > At + = 1 ;
}
static scene2_parse_rule S2_ParseRuleFromToken ( scene2_compiler * Compiler , token Token )
{
scene2_parse_rule Result = { } ;
switch ( Token . Kind )
{
case TokenKind_ParenthesisOpen : { Result = { S2_ParseGrouping , 0 , S2_Precedence_None } ; } break ;
case TokenKind_Bang : { Result = { S2_ParseUnary , 0 , S2_Precedence_None } ; } break ;
case TokenKind_Minus : { Result = { S2_ParseUnary , S2_ParseBinary , S2_Precedence_Term } ; } break ;
case TokenKind_Plus : { Result = { 0 , S2_ParseBinary , S2_Precedence_Term } ; } break ;
case TokenKind_Star : { Result = { 0 , S2_ParseBinary , S2_Precedence_Factor } ; } break ;
case TokenKind_Slash : { Result = { 0 , S2_ParseBinary , S2_Precedence_Factor } ; } break ;
case TokenKind_EqualEqual : { Result = { 0 , S2_ParseBinary , S2_Precedence_Equality } ; } break ;
case TokenKind_BangEqual : { Result = { 0 , S2_ParseBinary , S2_Precedence_Equality } ; } break ;
case TokenKind_Greater : { Result = { 0 , S2_ParseBinary , S2_Precedence_Comparison } ; } break ;
case TokenKind_GreaterEqual : { Result = { 0 , S2_ParseBinary , S2_Precedence_Comparison } ; } break ;
case TokenKind_Less : { Result = { 0 , S2_ParseBinary , S2_Precedence_Comparison } ; } break ;
case TokenKind_LessEqual : { Result = { 0 , S2_ParseBinary , S2_Precedence_Comparison } ; } break ;
case TokenKind_False : { Result = { S2_ParseLiteral , 0 , S2_Precedence_None } ; } break ;
case TokenKind_True : { Result = { S2_ParseLiteral , 0 , S2_Precedence_None } ; } break ;
case TokenKind_Numeric : { Result = { S2_ParseNumber , 0 , S2_Precedence_None } ; } break ;
case TokenKind_StringLiteral : { Result = { S2_ParseString , 0 , S2_Precedence_None } ; } break ;
case TokenKind_Identifier : { Result = { S2_ParseVariable , 0 , S2_Precedence_None } ; } break ;
case TokenKind_Call : { Result = { S2_ParseCall , 0 , S2_Precedence_None } ; } break ;
default : { } break ;
}
return ( Result ) ;
}
static scene2_instruction S2_Instruction ( scene2_opcode Opcode )
{
scene2_instruction Result = { } ;
Result . Opcode = Opcode ;
return ( Result ) ;
}
static scene2_instruction S2_Instruction ( scene2_opcode Opcode , u64 Arg )
{
scene2_instruction Result = { } ;
Result . Opcode = Opcode ;
Result . Arg = Arg ;
return ( Result ) ;
}
static scene2_instruction S2_Instruction ( scene2_opcode Opcode , r64 Number )
{
scene2_instruction Result = { } ;
Result . Opcode = Opcode ;
Result . Number = Number ;
return ( Result ) ;
}
static scene2_instruction S2_Instruction ( scene2_opcode Opcode , u32 Arg1 , u32 Arg2 )
{
scene2_instruction Result = { } ;
Result . Opcode = Opcode ;
Result . Arg1 = Arg1 ;
Result . Arg2 = Arg2 ;
return ( Result ) ;
}
static scene2_instruction S2_Instruction ( scene2_opcode Opcode , range1_s64 Range )
{
Assert ( 0 < = Range . Min & & Range . Min < = U32_Max ) ;
Assert ( 0 < = Range . Max & & Range . Max < = U32_Max ) ;
scene2_instruction Result = { } ;
Result . Opcode = Opcode ;
Result . Min = Range . Min ;
Result . Max = Range . Max ;
return ( Result ) ;
}
static scene2_instruction * S2_Emit ( scene2_compiler * Compiler , scene2_instruction Instruction )
{
scene2_instruction_chunk * Chunk = Compiler - > LastChunk ;
if ( ! Chunk | | Chunk - > InstructionsUsed > = ArrayCount ( Chunk - > Instructions ) )
{
Chunk = PushStruct ( Compiler - > Arena , scene2_instruction_chunk ) ;
QueuePush ( Compiler - > FirstChunk , Compiler - > LastChunk , Chunk ) ;
}
scene2_instruction * Result = Chunk - > Instructions + Chunk - > InstructionsUsed ;
Chunk - > InstructionsUsed + = 1 ;
Compiler - > InstructionPointer + = 1 ;
* Result = Instruction ;
return ( Result ) ;
}
////////////////////////////////
//~ sixten: Scene Parsing Functions
static void S2_ParseTopLevel ( scene2_compiler * Compiler )
{
// sixten(NOTE): top-level -> { proc declaration }
for ( ; Compiler - > At < Compiler - > Tokens . Count ; )
{
switch ( S2_Token ( Compiler ) . Kind )
{
case TokenKind_Proc :
{
S2_ParseProc ( Compiler ) ;
} break ;
default :
{
S2_ParseError ( Compiler , S2_Token ( Compiler ) , StrLit ( " Expected top level delaration (proc) " ) ) ;
S2_Advance ( Compiler ) ;
} break ;
}
}
}
static void S2_ParseProc ( scene2_compiler * Compiler )
{
// sixten(NOTE): proc -> 'proc' name { statement } 'end'
S2_Advance ( Compiler ) ; // sixten: skip 'proc'
token NameToken = S2_Consume ( Compiler , TokenKind_Identifier , StrLit ( " Expected name after 'proc'. " ) ) ;
scene2_proc_node * Node = PushStruct ( Compiler - > Arena , scene2_proc_node ) ;
QueuePush ( Compiler - > ProcList . First , Compiler - > ProcList . Last , Node ) ;
Compiler - > ProcList . Count + = 1 ;
Node - > Info . InstructionBegin = Compiler - > InstructionPointer ;
Node - > Info . Name = S2_StringFromToken ( Compiler , NameToken ) ;
S2_ParseBlock ( Compiler ) ;
Node - > Info . InstructionEnd = Compiler - > InstructionPointer ;
}
static void S2_ParseBlock ( scene2_compiler * Compiler )
{
// sixten: block -> { statement } 'end'
S2_Emit ( Compiler , S2_Instruction ( S2_Op_BeginBlock ) ) ;
b32 FoundEnd = false ;
for ( ; Compiler - > At < Compiler - > Tokens . Count ; )
{
switch ( S2_Token ( Compiler ) . Kind )
{
case TokenKind_End :
{
S2_Advance ( Compiler ) ; // sixten: skip 'end'
FoundEnd = true ;
goto Done ;
} break ;
default :
{
S2_ParseStatement ( Compiler ) ;
} break ;
}
}
Done : ;
if ( ! FoundEnd )
{
S2_ParseError ( Compiler , S2_Token ( Compiler ) , StrLit ( " Expected 'end' after block. " ) ) ;
}
S2_Emit ( Compiler , S2_Instruction ( S2_Op_EndBlock ) ) ;
}
static void S2_ParseStatement ( scene2_compiler * Compiler )
{
// sixten: statement -> if statement | while statement | let statetment | expression
switch ( S2_Token ( Compiler ) . Kind )
{
case TokenKind_Wait : { S2_ParseWaitStatement ( Compiler ) ; } break ;
case TokenKind_If : { S2_ParseIfStatement ( Compiler ) ; } break ;
case TokenKind_While : { S2_ParseWhileStatement ( Compiler ) ; } break ;
case TokenKind_Let : { S2_ParseLetStatement ( Compiler ) ; } break ;
case TokenKind_DollarSign : { S2_ParseShorthand ( Compiler ) ; } break ;
default : { S2_ParseExpression ( Compiler ) ; } break ;
}
if ( Compiler - > InPanicMode )
{
for ( ; Compiler - > At < Compiler - > Tokens . Count ; )
{
if ( S2_Token ( Compiler ) . Kind = = TokenKind_End )
{
break ;
}
else
{
S2_Advance ( Compiler ) ;
}
}
Compiler - > InPanicMode = false ;
}
}
static void S2_ParseWaitStatement ( scene2_compiler * Compiler )
{
S2_Advance ( Compiler ) ; // sixten: skip 'wait'
S2_Emit ( Compiler , S2_Instruction ( S2_Op_Wait ) ) ;
}
static void S2_ParseIfStatement ( scene2_compiler * Compiler )
{
S2_Advance ( Compiler ) ; // sixten: skip 'if'
S2_ParseExpression ( Compiler ) ;
S2_Emit ( Compiler , S2_Instruction ( S2_Op_Not ) ) ; // sixten: we only jump if the condition is _NOT_ satisfied.
scene2_instruction * JumpInstruction = S2_Emit ( Compiler , S2_Instruction ( S2_Op_CondJump ) ) ;
u64 OffsetBefore = Compiler - > InstructionPointer ;
S2_Consume ( Compiler , TokenKind_Then , StrLit ( " Expected 'then' after if-statement " ) ) ;
S2_ParseBlock ( Compiler ) ;
u64 JumpOffset = Compiler - > InstructionPointer - OffsetBefore ;
JumpInstruction - > Arg = JumpOffset ;
}
static void S2_ParseWhileStatement ( scene2_compiler * Compiler )
{
S2_Advance ( Compiler ) ; // sixten: skip 'while'
u64 CondBeginOffset = Compiler - > InstructionPointer ;
S2_ParseExpression ( Compiler ) ;
S2_Emit ( Compiler , S2_Instruction ( S2_Op_Not ) ) ; // sixten: we only jump if the condition is _NOT_ satisfied.
scene2_instruction * CondNotSatisfiedJump = S2_Emit ( Compiler , S2_Instruction ( S2_Op_CondJump ) ) ;
u64 OffsetJump = Compiler - > InstructionPointer ;
S2_Consume ( Compiler , TokenKind_Then , StrLit ( " Expected 'then' after while-statement " ) ) ;
S2_ParseBlock ( Compiler ) ;
S2_Emit ( Compiler , S2_Instruction ( S2_Op_Jump , ( u64 ) ( CondBeginOffset - Compiler - > InstructionPointer - 1 ) ) ) ;
u64 EndOffset = Compiler - > InstructionPointer ;
CondNotSatisfiedJump - > Arg = EndOffset - OffsetJump ;
}
static void S2_ParseLetStatement ( scene2_compiler * Compiler )
{
S2_Advance ( Compiler ) ; // sixten: skip 'let'
token LocalName = S2_Consume ( Compiler , TokenKind_Identifier , StrLit ( " Expected variable name after 'let' " ) ) ;
if ( S2_Token ( Compiler ) . Kind = = TokenKind_Equal )
{
S2_Advance ( Compiler ) ; // sixten: skip equals
S2_ParseExpression ( Compiler ) ;
S2_Emit ( Compiler , S2_Instruction ( S2_Op_SetLocal , LocalName . Range ) ) ;
S2_Emit ( Compiler , S2_Instruction ( S2_Op_SetVariable , LocalName . Range ) ) ;
}
else
{
S2_Emit ( Compiler , S2_Instruction ( S2_Op_SetLocal , LocalName . Range ) ) ;
}
}
static void S2_ParseShorthand ( scene2_compiler * Compiler )
{
S2_Advance ( Compiler ) ; // sixten: skip '$'
// sixten(NOTE): since we're using the parenthesis to check for a target specifier, we cannot
// use grouping as the text to append to the textbox. Should never really be an issue, but it
// does technically change how the languange should be documented.
S2_Emit ( Compiler , S2_Instruction ( S2_Op_Call , S2_CallFunctionIndexFromString ( StrLit ( " ctr_unset_all_talking " ) ) ) ) ;
S2_Emit ( Compiler , S2_Instruction ( S2_Op_Call , S2_CallFunctionIndexFromString ( StrLit ( " text_clear " ) ) ) ) ;
if ( S2_Token ( Compiler ) . Kind = = TokenKind_ParenthesisOpen )
{
S2_Advance ( Compiler ) ; // sixten: skip the '('
S2_ParseExpression ( Compiler ) ; // sixten: emit the target
S2_Emit ( Compiler , S2_Instruction ( S2_Op_DuplicateStack , 1llu ) ) ;
// sixten: emit the action
if ( S2_Token ( Compiler ) . Kind = = TokenKind_Comma )
{
S2_Advance ( Compiler ) ; // sixten: skip the ','
token AssetToken = S2_Consume ( Compiler , TokenKind_Identifier , StrLit ( " Expected asset name after shorthand & target specifier " ) ) ;
asset_id ID = A_AssetIDFromString ( S2_StringFromToken ( Compiler , AssetToken ) ) ;
if ( ID = = AssetID_None )
{
S2_ParseError ( Compiler , AssetToken , StrLit ( " Unknown asset " ) ) ;
}
S2_Emit ( Compiler , S2_Instruction ( S2_Op_PushNumber , ( r64 ) ID ) ) ;
}
else
{
S2_Emit ( Compiler , S2_Instruction ( S2_Op_PushNil ) ) ;
}
S2_Consume ( Compiler , TokenKind_ParenthesisClose , StrLit ( " Expetcted ')' after shorthand specifier " ) ) ;
S2_Emit ( Compiler , S2_Instruction ( S2_Op_Call , S2_CallFunctionIndexFromString ( StrLit ( " ctr_set " ) ) ) ) ;
S2_Emit ( Compiler , S2_Instruction ( S2_Op_Call , S2_CallFunctionIndexFromString ( StrLit ( " ctr_set_talking " ) ) ) ) ;
}
S2_ParseExpression ( Compiler ) ;
S2_Emit ( Compiler , S2_Instruction ( S2_Op_Call , S2_CallFunctionIndexFromString ( StrLit ( " text_append " ) ) ) ) ;
S2_Emit ( Compiler , S2_Instruction ( S2_Op_Wait ) ) ;
}
static void S2_ParseExpression ( scene2_compiler * Compiler )
{
S2_ParsePrecedence ( Compiler , S2_Precedence_Assignment ) ;
}
static void S2_ParsePrecedence ( scene2_compiler * Compiler , scene2_precedence Precedence )
{
b32 CanAssign = Precedence < = S2_Precedence_Assignment ;
//- sixten: do prefix rule
{
scene2_parse_rule Rule = S2_ParseRuleFromToken ( Compiler , S2_Token ( Compiler ) ) ;
if ( Rule . PrefixRule )
{
Rule . PrefixRule ( Compiler , CanAssign ) ;
}
else
{
S2_ParseError ( Compiler , S2_Token ( Compiler ) , StrLit ( " Expected expression. " ) ) ;
}
}
//- sixten: do infix rule
for ( ; ; )
{
scene2_parse_rule Rule = S2_ParseRuleFromToken ( Compiler , S2_Token ( Compiler ) ) ;
if ( Precedence < = Rule . Precedence )
{
Rule . InfixRule ( Compiler , CanAssign ) ;
}
else
{
break ;
}
}
if ( CanAssign & & S2_Token ( Compiler ) . Kind = = TokenKind_Equal )
{
S2_ParseError ( Compiler , S2_Token ( Compiler ) , StrLit ( " Invalid assignment target. " ) ) ;
}
}
static void S2_ParseGrouping ( scene2_compiler * Compiler , b32 CanAssign )
{
UnusedVariable ( CanAssign ) ;
S2_Advance ( Compiler ) ; // sixten: skip '('
S2_ParseExpression ( Compiler ) ;
S2_Consume ( Compiler , TokenKind_ParenthesisClose , StrLit ( " Expected ')' after expression. " ) ) ;
}
static void S2_ParseUnary ( scene2_compiler * Compiler , b32 CanAssign )
{
UnusedVariable ( CanAssign ) ;
scene2_operator Operator = S2_OperatorFromString ( S2_TokenString ( Compiler ) ) ;
S2_Advance ( Compiler ) ;
S2_ParsePrecedence ( Compiler , S2_Precedence_Unary ) ;
switch ( Operator )
{
case S2_Operator_Minus : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Negate ) ) ; } break ;
case S2_Operator_Not : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Not ) ) ; } break ;
InvalidDefaultCase ;
}
}
static void S2_ParseBinary ( scene2_compiler * Compiler , b32 CanAssign )
{
UnusedVariable ( CanAssign ) ;
token Token = S2_Token ( Compiler ) ;
scene2_operator Operator = S2_OperatorFromString ( S2_TokenString ( Compiler ) ) ;
scene2_parse_rule Rule = S2_ParseRuleFromToken ( Compiler , Token ) ;
S2_Advance ( Compiler ) ; // sixten: skip operator
S2_ParsePrecedence ( Compiler , ( scene2_precedence ) ( Rule . Precedence + 1 ) ) ;
switch ( Operator )
{
case S2_Operator_Add : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Add ) ) ; } break ;
case S2_Operator_Minus : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Subtract ) ) ; } break ;
case S2_Operator_Multiply : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Multiply ) ) ; } break ;
case S2_Operator_Divide : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Divide ) ) ; } break ;
case S2_Operator_Equals : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Equals ) ) ; } break ;
case S2_Operator_NotEquals : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Equals ) ) ; S2_Emit ( Compiler , S2_Instruction ( S2_Op_Not ) ) ; } break ;
case S2_Operator_Greater : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Greater ) ) ; } break ;
case S2_Operator_GreaterThanOrEquals : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Less ) ) ; S2_Emit ( Compiler , S2_Instruction ( S2_Op_Not ) ) ; } break ;
case S2_Operator_Less : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Less ) ) ; } break ;
case S2_Operator_LessThanOrEquals : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_Greater ) ) ; S2_Emit ( Compiler , S2_Instruction ( S2_Op_Not ) ) ; } break ;
InvalidDefaultCase ;
}
}
static void S2_ParseVariable ( scene2_compiler * Compiler , b32 CanAssign )
{
token VariableToken = S2_Consume ( Compiler , TokenKind_Identifier , StrLit ( " Expected identifier. " ) ) ;
if ( CanAssign & & S2_Token ( Compiler ) . Kind = = TokenKind_Equal )
{
S2_Advance ( Compiler ) ;
S2_ParseExpression ( Compiler ) ;
S2_Emit ( Compiler , S2_Instruction ( S2_Op_SetVariable , VariableToken . Range ) ) ;
}
else
{
S2_Emit ( Compiler , S2_Instruction ( S2_Op_PushVariable , VariableToken . Range ) ) ;
}
}
static void S2_ParseCall ( scene2_compiler * Compiler , b32 CanAssign )
{
UnusedVariable ( CanAssign ) ;
S2_Advance ( Compiler ) ; // sixten: skip 'call'
token NameToken = S2_Consume ( Compiler , TokenKind_Identifier , StrLit ( " Expected function name. " ) ) ;
S2_Consume ( Compiler , TokenKind_ParenthesisOpen , StrLit ( " Expected '(' after function name " ) ) ;
//- sixten: parse arguments
token Token = S2_Token ( Compiler ) ;
if ( Token . Kind ! = TokenKind_ParenthesisClose )
{
for ( ; Compiler - > At < Compiler - > Tokens . Count ; )
{
S2_ParseExpression ( Compiler ) ;
Token = S2_Token ( Compiler ) ;
if ( Token . Kind = = TokenKind_ParenthesisClose )
{
break ;
}
else
{
S2_Consume ( Compiler , TokenKind_Comma , StrLit ( " Expected ',' or ')'. " ) ) ;
}
}
}
S2_Advance ( Compiler ) ; // sixten: skip ')'
S2_Emit ( Compiler , S2_Instruction ( S2_Op_Call , S2_CallFunctionIndexFromString ( S2_StringFromToken ( Compiler , NameToken ) ) ) ) ;
}
static void S2_ParseLiteral ( scene2_compiler * Compiler , b32 CanAssign )
{
UnusedVariable ( CanAssign ) ;
token LiteralToken = S2_Token ( Compiler ) ;
switch ( LiteralToken . Kind )
{
case TokenKind_False : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_PushBool , 0ull ) ) ; } break ;
case TokenKind_True : { S2_Emit ( Compiler , S2_Instruction ( S2_Op_PushBool , 1ull ) ) ; } break ;
InvalidDefaultCase ;
}
S2_Advance ( Compiler ) ; // sixten: skip the literal
}
static void S2_ParseNumber ( scene2_compiler * Compiler , b32 CanAssign )
{
UnusedVariable ( CanAssign ) ;
token NumberToken = S2_Token ( Compiler ) ;
S2_Advance ( Compiler ) ; // sixten: skip the numeric literal
S2_Emit ( Compiler , S2_Instruction ( S2_Op_PushNumber , DoubleFromString ( S2_StringFromToken ( Compiler , NumberToken ) ) ) ) ;
}
static void S2_ParseString ( scene2_compiler * Compiler , b32 CanAssign )
{
UnusedVariable ( CanAssign ) ;
token StringToken = S2_Token ( Compiler ) ;
S2_Advance ( Compiler ) ; // sixten: skip the string literal
S2_Emit ( Compiler , S2_Instruction ( S2_Op_PushString , Pad ( StringToken . Range , - 1 ) ) ) ; // sixten(TODO): push the string to the stack
}
static scene2_proc_list S2_CopyProcList ( arena * Arena , scene2_proc_list Source )
{
scene2_proc_list Result = { } ;
for ( scene2_proc_node * Node = Source . First ; Node ! = 0 ; Node = Node - > Next )
{
scene2_proc_node * New = PushStruct ( Arena , scene2_proc_node ) ;
New - > Info . Name = PushString ( Arena , Node - > Info . Name ) ;
New - > Info . InstructionBegin = Node - > Info . InstructionBegin ;
New - > Info . InstructionEnd = Node - > Info . InstructionEnd ;
QueuePush ( Result . First , Result . Last , New ) ;
Result . Count + = 1 ;
}
Assert ( Result . Count = = Source . Count ) ;
return ( Result ) ;
}
////////////////////////////////
//~ sixten: Scene Runtime Helper Functions
static string S2_StringFromObject ( arena * Arena , scene2_object Object )
{
string Result = StrLit ( " unknown " ) ;
switch ( Object . Kind )
{
case S2_ObjectKind_Nil : { Result = StrLit ( " nil " ) ; } break ;
case S2_ObjectKind_Bool : { Result = PushFormat ( Arena , " %b " , Object . As . Bool ) ; } break ;
case S2_ObjectKind_Number :
{
if ( Object . As . Number = = Round ( Object . As . Number ) )
{
Result = PushFormat ( Arena , " %i " , ( s64 ) Object . As . Number ) ;
}
else
{
Result = PushFormat ( Arena , " %f " , Object . As . Number ) ;
}
} break ;
case S2_ObjectKind_String : { Result = PushString ( Arena , Object . As . String ) ; } break ;
}
return ( Result ) ;
}
static void S2_StackPush ( scene2_runtime * Runtime , scene2_object Object )
{
if ( Runtime - > StackPointer < ArrayCount ( Runtime - > Stack ) )
{
Runtime - > Stack [ Runtime - > StackPointer + + ] = Object ;
}
}
static scene2_object S2_StackPop ( scene2_runtime * Runtime )
{
scene2_object Result = { } ;
if ( Runtime - > StackPointer > 0 )
{
Result = Runtime - > Stack [ - - Runtime - > StackPointer ] ;
}
return ( Result ) ;
}
static scene2_object S2_MakeNil ( void )
{
scene2_object Result = { } ;
Result . Kind = S2_ObjectKind_Nil ;
return ( Result ) ;
}
static scene2_object S2_MakeBool ( b32 Bool )
{
scene2_object Result = { } ;
Result . Kind = S2_ObjectKind_Bool ;
Result . As . Bool = Bool ;
return ( Result ) ;
}
static scene2_object S2_MakeNumber ( r64 Number )
{
scene2_object Result = { } ;
Result . Kind = S2_ObjectKind_Number ;
Result . As . Number = Number ;
return ( Result ) ;
}
static scene2_object S2_MakeString ( string String )
{
scene2_object Result = { } ;
Result . Kind = S2_ObjectKind_String ;
Result . As . String = String ;
return ( Result ) ;
}
static b32 S2_ObjectIsTrue ( scene2_object Object )
{
b32 Result = false ;
if ( Object . Kind = = S2_ObjectKind_Bool )
{
Result = Object . As . Bool ;
}
else if ( Object . Kind = = S2_ObjectKind_Number & & Object . As . Number ! = 0 )
{
Result = true ;
}
else if ( Object . Kind = = S2_ObjectKind_String )
{
Result = true ;
}
return ( Result ) ;
}
static string S2_StringFromInstruction ( compiled_scene2 * Compiled , scene2_instruction Instruction )
{
string Result = Substring ( Compiled - > Source , Range1S64 ( Instruction . Min , Instruction . Max ) ) ;
return ( Result ) ;
}
static scene2_variable * S2_NewVariable ( scene2_runtime * Runtime )
{
scene2_variable * Result = Runtime - > FirstFreeVariable ;
if ( Result )
{
DLLRemove ( Runtime - > FirstFreeVariable , Runtime - > LastFreeVariable , Result ) ;
ZeroStruct ( Result ) ;
}
else
{
Result = PushStruct ( Runtime - > VariableArena , scene2_variable ) ;
}
return ( Result ) ;
}
static scene2_variable * S2_VariableFromString ( scene2_runtime * Runtime , string Name )
{
scene2_variable * Result = 0 ;
//- sixten: check if the variable exists
for ( scene2_variable * Variable = Runtime - > FirstGlobalVariable ; Variable ! = 0 ; Variable = Variable - > Next )
{
if ( AreEqual ( Name , Variable - > Name ) )
{
Result = Variable ;
break ;
}
}
if ( ! Result )
{
Result = S2_NewVariable ( Runtime ) ;
Result - > Name = PushString ( Runtime - > VariableArena , Name ) ;
DLLInsertLast ( Runtime - > FirstGlobalVariable , Runtime - > LastGlobalVariable , Result ) ;
}
return ( Result ) ;
}
////////////////////////////////
//~ sixten: Scene Interface Functions
static compiled_scene2 S2_CompiledFromString ( arena * Arena , string String )
{
temp Scratch = GetScratch ( & Arena , 1 ) ;
//- sixten: string -> tokens
tokenize_result TokenizeResult = T_TokenizeFromText ( Scratch . Arena , String , T_IsIrregular ) ;
scene2_compiler Compiler = { } ;
Compiler . Arena = Scratch . Arena ;
Compiler . Tokens = TokenizeResult . Tokens ;
Compiler . Source = String ;
//- sixten: tokens -> bytecode
S2_ParseTopLevel ( & Compiler ) ;
compiled_scene2 Result = { } ;
{
//- sixten: copy source
Result . Source = PushString ( Arena , String ) ;
//- sixten: copy messages
Result . Messages = S2_CopyMessageList ( Arena , & Compiler . Messages ) ;
//- sixten: copy instructions
Result . InstructionCount = Compiler . InstructionPointer ;
Result . Instructions = PushArray ( Arena , scene2_instruction , Result . InstructionCount ) ;
u64 InstructionIndex = 0 ;
for ( scene2_instruction_chunk * Chunk = Compiler . FirstChunk ; Chunk ! = 0 ; Chunk = Chunk - > Next )
{
Copy ( Result . Instructions + InstructionIndex , Chunk - > Instructions , Chunk - > InstructionsUsed * sizeof ( scene2_instruction ) ) ;
InstructionIndex + = Chunk - > InstructionsUsed ;
}
//- sixten: copy procs
Result . ProcList = S2_CopyProcList ( Arena , Compiler . ProcList ) ;
}
ReleaseScratch ( Scratch ) ;
return ( Result ) ;
}
static compiled_scene2 S2_CopyCompiledScene ( arena * Arena , compiled_scene2 * Source )
{
compiled_scene2 Result = { } ;
Result . Source = PushString ( Arena , Source - > Source ) ;
Result . Messages = S2_CopyMessageList ( Arena , & Source - > Messages ) ;
Result . InstructionCount = Source - > InstructionCount ;
Result . Instructions = PushArray ( Arena , scene2_instruction , Result . InstructionCount ) ;
Copy ( Result . Instructions , Source - > Instructions , Result . InstructionCount * sizeof ( scene2_instruction ) ) ;
Result . ProcList = S2_CopyProcList ( Arena , Source - > ProcList ) ;
return ( Result ) ;
}
static void S2_SetCurrentProc ( scene2_runtime * Runtime , scene2_proc_info Info )
{
Runtime - > CurrentProc = Info ;
Runtime - > InstructionPointer = Info . InstructionBegin ;
}
static scene2_proc_info S2_ProcFromName ( compiled_scene2 * Compiled , string Name )
{
scene2_proc_info Result = { } ;
for ( scene2_proc_node * Node = Compiled - > ProcList . First ; Node ! = 0 ; Node = Node - > Next )
{
if ( AreEqual ( Node - > Info . Name , Name ) )
{
Result = Node - > Info ;
break ;
}
}
return ( Result ) ;
}
static void S2_Init ( scene2_runtime * Runtime )
{
Runtime - > VariableArena = ArenaAlloc ( 4096 , true , " Scene Runtime Variable Arena " ) ;
}
static scene2_run_result S2_Run ( arena * Arena , scene2_runtime * Runtime , compiled_scene2 * Compiled , b32 PlayerAction )
{
scene2_run_result Result = { } ;
scene2_proc_info * ProcInfo = & Runtime - > CurrentProc ;
for ( ; ProcInfo - > InstructionBegin < = Runtime - > InstructionPointer & & Runtime - > InstructionPointer < ProcInfo - > InstructionEnd & & Result . Messages . Count < 100 ; )
{
scene2_instruction Instruction = Compiled - > Instructions [ Runtime - > InstructionPointer ] ;
switch ( Instruction . Opcode )
{
case S2_Op_None :
default :
{
if ( S2_Op_None < = Instruction . Opcode & & Instruction . Opcode < S2_Op_COUNT )
{
S2_PushMessageF ( Arena , & Result . Messages , T_EmptyToken , " Unimplemented opcode: %S (%S) " , S2_InstructionNameLookup [ Instruction . Opcode ] , S2_InstructionInfoLookup [ Instruction . Opcode ] ) ;
}
else
{
S2_PushMessageF ( Arena , & Result . Messages , T_EmptyToken , " Unknown opcode: %i " , Instruction . Opcode ) ;
}
} break ;
case S2_Op_Call :
{
// sixten: find the binding
scene2_call_function * Function = S2_CallBindingLookup [ Instruction . Arg ] ;
if ( Function = = S2_Call_Stub )
{
// sixten(TODO): do we error here??
}
Function ( Runtime , Compiled ) ;
} break ;
case S2_Op_Wait :
{
if ( PlayerAction )
{
// sixten: "consume" the action
PlayerAction = false ;
}
else
{
goto Done ;
}
} break ;
case S2_Op_Pop :
{
S2_StackPop ( Runtime ) ;
} break ;
case S2_Op_PushBool :
{
S2_StackPush ( Runtime , S2_MakeBool ( Instruction . Arg ) ) ;
} break ;
case S2_Op_PushNumber :
{
S2_StackPush ( Runtime , S2_MakeNumber ( Instruction . Number ) ) ;
} break ;
case S2_Op_PushString :
{
S2_StackPush ( Runtime , S2_MakeString ( S2_StringFromInstruction ( Compiled , Instruction ) ) ) ;
} break ;
case S2_Op_PushNil :
{
S2_StackPush ( Runtime , S2_MakeNil ( ) ) ;
} break ;
case S2_Op_PushVariable :
{
scene2_variable * Variable = S2_VariableFromString ( Runtime , S2_StringFromInstruction ( Compiled , Instruction ) ) ;
S2_StackPush ( Runtime , Variable - > Value ) ;
} break ;
case S2_Op_DuplicateStack :
{
temp Scratch = GetScratch ( ) ;
scene2_object * Stack = PushArrayNoClear ( Scratch . Arena , scene2_object , Instruction . Arg ) ;
for ( u64 Index = 0 ; Index < Instruction . Arg ; Index + = 1 )
{
Stack [ Index ] = S2_StackPop ( Runtime ) ;
}
for ( u64 Index = 0 ; Index < 2 * Instruction . Arg ; Index + = 1 )
{
S2_StackPush ( Runtime , Stack [ Index % Instruction . Arg ] ) ;
}
ReleaseScratch ( Scratch ) ;
} break ;
case S2_Op_SetVariable :
{
scene2_object NewValue = S2_StackPop ( Runtime ) ;
scene2_variable * Variable = S2_VariableFromString ( Runtime , S2_StringFromInstruction ( Compiled , Instruction ) ) ;
Variable - > Value = NewValue ;
} break ;
case S2_Op_SetLocal :
{
InvalidCodepath ;
} break ;
case S2_Op_BeginBlock :
{
} break ;
case S2_Op_EndBlock :
{
} break ;
case S2_Op_Jump :
{
Runtime - > InstructionPointer + = Instruction . Arg ;
} break ;
case S2_Op_CondJump :
{
if ( S2_ObjectIsTrue ( S2_StackPop ( Runtime ) ) )
{
Runtime - > InstructionPointer + = Instruction . Arg ;
}
} break ;
case S2_Op_Add :
{
scene2_object Object1 = S2_StackPop ( Runtime ) ;
scene2_object Object2 = S2_StackPop ( Runtime ) ;
if ( Object1 . Kind = = S2_ObjectKind_Number & & Object2 . Kind = = S2_ObjectKind_Number )
{
S2_StackPush ( Runtime , S2_MakeNumber ( Object1 . As . Number + Object2 . As . Number ) ) ;
}
else
{
S2_PushMessageF ( Arena , & Result . Messages , T_EmptyToken , " Trying to add two incompatible types: %S & %S. Will return nil. " , S2_ObjectKindNameLookup [ Object1 . Kind ] , S2_ObjectKindNameLookup [ Object2 . Kind ] ) ;
S2_StackPush ( Runtime , S2_MakeNil ( ) ) ;
}
} break ;
case S2_Op_Subtract :
{
scene2_object Object1 = S2_StackPop ( Runtime ) ;
scene2_object Object2 = S2_StackPop ( Runtime ) ;
if ( Object1 . Kind = = S2_ObjectKind_Number & & Object2 . Kind = = S2_ObjectKind_Number )
{
S2_StackPush ( Runtime , S2_MakeNumber ( Object2 . As . Number - Object1 . As . Number ) ) ;
}
else
{
S2_PushMessageF ( Arena , & Result . Messages , T_EmptyToken , " Trying to subtract two incompatible types: %S & %S. Will return nil. " , S2_ObjectKindNameLookup [ Object1 . Kind ] , S2_ObjectKindNameLookup [ Object2 . Kind ] ) ;
S2_StackPush ( Runtime , S2_MakeNil ( ) ) ;
}
} break ;
case S2_Op_Multiply :
{
scene2_object Object1 = S2_StackPop ( Runtime ) ;
scene2_object Object2 = S2_StackPop ( Runtime ) ;
if ( Object1 . Kind = = S2_ObjectKind_Number & & Object2 . Kind = = S2_ObjectKind_Number )
{
S2_StackPush ( Runtime , S2_MakeNumber ( Object2 . As . Number * Object1 . As . Number ) ) ;
}
else
{
S2_PushMessageF ( Arena , & Result . Messages , T_EmptyToken , " Trying to multiply two incompatible types: %S & %S. Will return nil. " , S2_ObjectKindNameLookup [ Object1 . Kind ] , S2_ObjectKindNameLookup [ Object2 . Kind ] ) ;
S2_StackPush ( Runtime , S2_MakeNil ( ) ) ;
}
} break ;
case S2_Op_Divide :
{
scene2_object Object1 = S2_StackPop ( Runtime ) ;
scene2_object Object2 = S2_StackPop ( Runtime ) ;
if ( Object1 . Kind = = S2_ObjectKind_Number & & Object2 . Kind = = S2_ObjectKind_Number )
{
S2_StackPush ( Runtime , S2_MakeNumber ( Object2 . As . Number / Object1 . As . Number ) ) ;
}
else
{
S2_PushMessageF ( Arena , & Result . Messages , T_EmptyToken , " Trying to divide two incompatible types: %S & %S. Will return nil. " , S2_ObjectKindNameLookup [ Object1 . Kind ] , S2_ObjectKindNameLookup [ Object2 . Kind ] ) ;
S2_StackPush ( Runtime , S2_MakeNil ( ) ) ;
}
} break ;
case S2_Op_Equals :
{
scene2_object Object1 = S2_StackPop ( Runtime ) ;
scene2_object Object2 = S2_StackPop ( Runtime ) ;
if ( Object1 . Kind = = S2_ObjectKind_Bool & & Object2 . Kind = = S2_ObjectKind_Bool )
{
S2_StackPush ( Runtime , S2_MakeBool ( Object1 . As . Bool = = Object2 . As . Bool ) ) ;
}
else if ( Object1 . Kind = = S2_ObjectKind_Number & & Object2 . Kind = = S2_ObjectKind_Number )
{
S2_StackPush ( Runtime , S2_MakeBool ( Object1 . As . Number = = Object2 . As . Number ) ) ;
}
else if ( Object1 . Kind = = S2_ObjectKind_String & & Object2 . Kind = = S2_ObjectKind_Number )
{
S2_StackPush ( Runtime , S2_MakeBool ( DoubleFromString ( Object1 . As . String ) = = Object1 . As . Number ) ) ;
}
else if ( Object1 . Kind = = S2_ObjectKind_Number & & Object2 . Kind = = S2_ObjectKind_String )
{
S2_StackPush ( Runtime , S2_MakeBool ( Object1 . As . Number = = DoubleFromString ( Object2 . As . String ) ) ) ;
}
else
{
S2_StackPush ( Runtime , S2_MakeBool ( false ) ) ;
}
} break ;
case S2_Op_Greater :
{
scene2_object Object1 = S2_StackPop ( Runtime ) ;
scene2_object Object2 = S2_StackPop ( Runtime ) ;
if ( Object1 . Kind = = S2_ObjectKind_Number & & Object2 . Kind = = S2_ObjectKind_Number )
{
S2_StackPush ( Runtime , S2_MakeBool ( Object2 . As . Number > Object1 . As . Number ) ) ;
}
else
{
S2_PushMessageF ( Arena , & Result . Messages , T_EmptyToken , " Trying to compare two incompatible types: %S & %S. Will return nil. " , S2_ObjectKindNameLookup [ Object1 . Kind ] , S2_ObjectKindNameLookup [ Object2 . Kind ] ) ;
S2_StackPush ( Runtime , S2_MakeBool ( false ) ) ;
}
} break ;
case S2_Op_Less :
{
scene2_object Object1 = S2_StackPop ( Runtime ) ;
scene2_object Object2 = S2_StackPop ( Runtime ) ;
if ( Object1 . Kind = = S2_ObjectKind_Number & & Object2 . Kind = = S2_ObjectKind_Number )
{
S2_StackPush ( Runtime , S2_MakeBool ( Object2 . As . Number < Object1 . As . Number ) ) ;
}
else
{
S2_PushMessageF ( Arena , & Result . Messages , T_EmptyToken , " Trying to compare two incompatible types: %S & %S. Will return nil. " , S2_ObjectKindNameLookup [ Object1 . Kind ] , S2_ObjectKindNameLookup [ Object2 . Kind ] ) ;
S2_StackPush ( Runtime , S2_MakeBool ( false ) ) ;
}
} break ;
case S2_Op_Not :
{
scene2_object Object = S2_StackPop ( Runtime ) ;
S2_StackPush ( Runtime , S2_MakeBool ( ! S2_ObjectIsTrue ( Object ) ) ) ;
} break ;
case S2_Op_Negate :
{
scene2_object Object = S2_StackPop ( Runtime ) ;
if ( Object . Kind = = S2_ObjectKind_Number )
{
S2_StackPush ( Runtime , S2_MakeBool ( - Object . As . Number ) ) ;
}
else
{
S2_PushMessageF ( Arena , & Result . Messages , T_EmptyToken , " Trying to negate invalid type: %S. Will return nil. " , S2_ObjectKindNameLookup [ Object . Kind ] ) ;
S2_StackPush ( Runtime , S2_MakeNil ( ) ) ;
}
} break ;
}
Runtime - > InstructionPointer + = 1 ;
}
Done : ;
2024-01-21 20:01:00 +00:00
if ( Runtime - > InstructionPointer > = ProcInfo - > InstructionEnd )
{
S2_SetCurrentProc ( Runtime , S_EmptyProcInfo ) ;
}
2024-01-20 11:18:57 +00:00
return ( Result ) ;
}