2023-08-06 10:35:09 +00:00
|
|
|
#include "generated/vn_scene.meta.h"
|
|
|
|
#include "generated/vn_scene.meta.c"
|
|
|
|
|
|
|
|
static void S_EmitByte(scene_compiler *Compiler, u8 Byte)
|
2023-07-19 15:09:41 +00:00
|
|
|
{
|
2023-08-06 10:35:09 +00:00
|
|
|
scene_annotated_bytecode_bucket *Bucket = Compiler->CurrentBucket;
|
|
|
|
scene_annotated_bytecode_chunk *Chunk = Bucket->Last;
|
|
|
|
if(!Chunk || Chunk->Count >= ArrayCount(Chunk->Data) || !AreEqual(Chunk->Name, Compiler->CurrentName))
|
|
|
|
{
|
|
|
|
Chunk = PushStruct(Compiler->Arena, scene_annotated_bytecode_chunk);
|
|
|
|
Chunk->Name = Compiler->CurrentName;
|
|
|
|
|
|
|
|
QueuePush(Bucket->First, Bucket->Last, Chunk);
|
|
|
|
Bucket->Count += 1;
|
|
|
|
}
|
|
|
|
Chunk->Data[Chunk->Count] = Byte;
|
|
|
|
Chunk->Count += 1;
|
2023-07-19 15:09:41 +00:00
|
|
|
}
|
|
|
|
|
2023-08-06 10:35:09 +00:00
|
|
|
static u64 S_MakeConstant(scene_compiler *Compiler, scene_value Value)
|
2023-07-19 15:09:41 +00:00
|
|
|
{
|
2023-08-06 10:35:09 +00:00
|
|
|
scene_value_chunk *Chunk = Compiler->LastValueChunk;
|
|
|
|
if(!Chunk || Chunk->Count >= ArrayCount(Chunk->Values))
|
|
|
|
{
|
|
|
|
Chunk = PushStruct(Compiler->Arena, scene_value_chunk);
|
|
|
|
QueuePush(Compiler->FirstValueChunk, Compiler->LastValueChunk, Chunk);
|
|
|
|
}
|
|
|
|
Chunk->Values[Chunk->Count] = Value;
|
|
|
|
u64 Result = Compiler->ValueCount;
|
|
|
|
Compiler->ValueCount += 1;
|
|
|
|
Chunk->Count += 1;
|
2023-07-19 15:09:41 +00:00
|
|
|
return(Result);
|
|
|
|
}
|
2023-08-06 10:35:09 +00:00
|
|
|
|
|
|
|
static void S_EmitVariableLength(scene_compiler *Compiler, u64 Value)
|
|
|
|
{
|
|
|
|
u64 Index = Value;
|
|
|
|
for(;Index > 0x7F; Index >>= 7)
|
|
|
|
{
|
|
|
|
S_EmitByte(Compiler, Index|0x80);
|
|
|
|
InvalidCodepath;
|
|
|
|
}
|
|
|
|
S_EmitByte(Compiler, Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
static u64 S_ReadVariableLength(u8 **BytePtr)
|
2023-07-19 15:09:41 +00:00
|
|
|
{
|
2023-08-06 10:35:09 +00:00
|
|
|
u64 Result = 0;
|
|
|
|
u8 *Byte = *BytePtr;
|
|
|
|
for(;*Byte & 0x80; Byte += 1)
|
|
|
|
{
|
|
|
|
Result = (Result<<7)|(*Byte & 0x7F);
|
|
|
|
}
|
|
|
|
Result = (Result<<7)|(*Byte & 0x7F);
|
|
|
|
*BytePtr = Byte;
|
|
|
|
return(Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_EmitConstant(scene_compiler *Compiler, scene_value Value)
|
|
|
|
{
|
|
|
|
S_EmitByte(Compiler, S_Op_Constant);
|
|
|
|
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, Value));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_SetEmissionTarget(scene_compiler *Compiler, string Target)
|
|
|
|
{
|
|
|
|
if(AreEqual(Target, StrLit("")))
|
|
|
|
{
|
|
|
|
Compiler->CurrentBucket = &Compiler->GlobalScope;
|
|
|
|
Compiler->CurrentName = StrLit("Global Scope");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u64 Hash = HashString(Target);
|
|
|
|
Compiler->CurrentBucket = &Compiler->ProcBuckets[Hash % ArrayCount(Compiler->ProcBuckets)];
|
|
|
|
Compiler->CurrentName = Target;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static scene_annotated_bytecode_chunk *S_FindBytecodeChunkByName(scene_compiler *Compiler, string Name)
|
|
|
|
{
|
|
|
|
scene_annotated_bytecode_chunk *Result = 0;
|
|
|
|
u64 Hash = HashString(Name);
|
|
|
|
scene_annotated_bytecode_bucket *Bucket = &Compiler->ProcBuckets[Hash%ArrayCount(Compiler->ProcBuckets)];
|
|
|
|
for(scene_annotated_bytecode_chunk *Chunk = Bucket->First; Chunk != 0; Chunk = Chunk->Next)
|
|
|
|
{
|
|
|
|
if(AreEqual(Chunk->Name, Name))
|
|
|
|
{
|
|
|
|
Result = Chunk;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_AdvanceCompiler(scene_compiler *Compiler)
|
|
|
|
{
|
|
|
|
Compiler->At += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static scene_parse_rule S_ParseRuleFromToken(scene_compiler *Compiler, token Token)
|
|
|
|
{
|
|
|
|
scene_parse_rule Result = {};
|
|
|
|
switch(Token.Kind)
|
|
|
|
{
|
|
|
|
case TokenKind_ParenthesisOpen: { Result = { S_ParseGrouping, 0, S_Precedence_None }; } break;
|
|
|
|
case TokenKind_Bang: { Result = { S_ParseUnary, 0, S_Precedence_None }; } break;
|
|
|
|
case TokenKind_Minus: { Result = { S_ParseUnary, S_ParseBinary, S_Precedence_Term }; } break;
|
|
|
|
case TokenKind_Plus: { Result = { 0, S_ParseBinary, S_Precedence_Term }; } break;
|
|
|
|
case TokenKind_Star: { Result = { 0, S_ParseBinary, S_Precedence_Factor }; } break;
|
|
|
|
case TokenKind_Slash: { Result = { 0, S_ParseBinary, S_Precedence_Factor }; } break;
|
|
|
|
case TokenKind_EqualEqual: { Result = { 0, S_ParseBinary, S_Precedence_Equality }; } break;
|
|
|
|
case TokenKind_BangEqual: { Result = { 0, S_ParseBinary, S_Precedence_Equality }; } break;
|
|
|
|
case TokenKind_Greater: { Result = { 0, S_ParseBinary, S_Precedence_Comparison }; } break;
|
|
|
|
case TokenKind_GreaterEqual: { Result = { 0, S_ParseBinary, S_Precedence_Comparison }; } break;
|
|
|
|
case TokenKind_Less: { Result = { 0, S_ParseBinary, S_Precedence_Comparison }; } break;
|
|
|
|
case TokenKind_LessEqual: { Result = { 0, S_ParseBinary, S_Precedence_Comparison }; } break;
|
|
|
|
case TokenKind_False: { Result = { S_ParseLiteral, 0, S_Precedence_None }; } break;
|
|
|
|
case TokenKind_True: { Result = { S_ParseLiteral, 0, S_Precedence_None }; } break;
|
|
|
|
case TokenKind_Numeric: { Result = { S_ParseNumber, 0, S_Precedence_None }; } break;
|
|
|
|
case TokenKind_Identifier: { Result = { S_ParseVariable, 0, S_Precedence_None }; } break;
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
//InvalidCodepath;
|
|
|
|
} break;
|
|
|
|
}
|
2023-07-19 15:09:41 +00:00
|
|
|
|
2023-08-06 10:35:09 +00:00
|
|
|
return(Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static b32 S_MatchToken(scene_compiler *Compiler, token Token, token_kind Kind)
|
|
|
|
{
|
|
|
|
b32 Result = false;
|
|
|
|
string String = T_StringFromToken(Compiler->Text, Token);
|
|
|
|
if(Token.Kind == Kind)
|
|
|
|
{
|
|
|
|
Result = true;
|
|
|
|
}
|
|
|
|
return(Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static token S_ConsumeToken(scene_compiler *Compiler, token_kind Kind, char *Message)
|
|
|
|
{
|
|
|
|
token Token = Compiler->At[0];
|
|
|
|
string String = T_StringFromToken(Compiler->Text, Token);
|
|
|
|
if(Token.Kind != Kind)
|
|
|
|
{
|
|
|
|
S_ParseError(Compiler, Message);
|
|
|
|
}
|
2023-07-19 15:09:41 +00:00
|
|
|
|
2023-08-06 10:35:09 +00:00
|
|
|
Compiler->At += 1;
|
|
|
|
return(Token);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseTopLevelDeclaration(scene_compiler *Compiler)
|
|
|
|
{
|
|
|
|
if(Compiler->At[0].Kind == TokenKind_Proc)
|
|
|
|
{
|
|
|
|
Compiler->At += 1;
|
|
|
|
S_ParseProcedure(Compiler);
|
|
|
|
}
|
|
|
|
else if(Compiler->At[0].Kind == TokenKind_Var)
|
|
|
|
{
|
|
|
|
Compiler->At += 1;
|
|
|
|
S_ParseVariableDeclaration(Compiler);
|
|
|
|
}
|
|
|
|
else
|
2023-07-19 15:09:41 +00:00
|
|
|
{
|
2023-08-06 10:35:09 +00:00
|
|
|
S_ParseError(Compiler, "Expected top-level declaration (proc or var)..");
|
2023-07-19 15:09:41 +00:00
|
|
|
}
|
2023-08-06 10:35:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseProcedure(scene_compiler *Compiler)
|
|
|
|
{
|
|
|
|
token NameToken = S_ConsumeToken(Compiler, TokenKind_Identifier, "Expected procedure name after 'proc'");
|
|
|
|
S_ConsumeToken(Compiler, TokenKind_CurlyOpen, "Expected '{' after procedure name.");
|
2023-07-19 15:09:41 +00:00
|
|
|
|
2023-08-06 10:35:09 +00:00
|
|
|
S_SetEmissionTarget(Compiler, T_StringFromToken(Compiler->Text, NameToken));
|
|
|
|
|
|
|
|
for(;Compiler->At < Compiler->TokensEnd;)
|
2023-07-19 15:09:41 +00:00
|
|
|
{
|
2023-08-06 10:35:09 +00:00
|
|
|
if(Compiler->At[0].Kind == TokenKind_CurlyClose)
|
2023-07-19 15:09:41 +00:00
|
|
|
{
|
2023-08-06 10:35:09 +00:00
|
|
|
Compiler->At += 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
S_ParseDeclaration(Compiler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseDeclaration(scene_compiler *Compiler)
|
|
|
|
{
|
|
|
|
switch(Compiler->At[0].Kind)
|
|
|
|
{
|
|
|
|
case TokenKind_Var:
|
|
|
|
{
|
|
|
|
Compiler->At += 1;
|
|
|
|
S_ParseVariableDeclaration(Compiler);
|
|
|
|
} break;
|
|
|
|
case TokenKind_StringLiteral:
|
|
|
|
{
|
|
|
|
Compiler->At += 1;
|
|
|
|
S_ParseLineEntry(Compiler);
|
|
|
|
} break;
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
S_ParseStatement(Compiler);
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseVariableDeclaration(scene_compiler *Compiler)
|
|
|
|
{
|
|
|
|
S_ConsumeToken(Compiler, TokenKind_Identifier, "Expected variable name.");
|
|
|
|
u64 NameConstant = S_MakeConstant(Compiler, S_MakePointer(&Compiler->At[-1]));
|
|
|
|
|
|
|
|
if(Compiler->At[0].Kind == TokenKind_Equal)
|
|
|
|
{
|
|
|
|
Compiler->At += 1;
|
|
|
|
S_ParseExpression(Compiler);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
S_EmitByte(Compiler, S_Op_Nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
S_ConsumeToken(Compiler, TokenKind_Semicolon, "Expected ';' after variable declaration.");
|
|
|
|
|
|
|
|
S_EmitByte(Compiler, S_Op_DefineGlobal);
|
|
|
|
u64 Index = NameConstant;
|
|
|
|
for(;Index > 0x7F; Index >>= 7)
|
|
|
|
{
|
|
|
|
S_EmitByte(Compiler, Index|0x80);
|
|
|
|
InvalidCodepath;
|
|
|
|
}
|
|
|
|
S_EmitByte(Compiler, Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseVariable(scene_compiler *Compiler, b32 CanAssign)
|
|
|
|
{
|
|
|
|
S_ParseNamedVariable(Compiler, &Compiler->At[-1], CanAssign);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseNamedVariable(scene_compiler *Compiler, token *Token, b32 CanAssign)
|
|
|
|
{
|
|
|
|
u64 NameConstant = S_MakeConstant(Compiler, S_MakePointer(Token));
|
|
|
|
if(CanAssign && Compiler->At[0].Kind == TokenKind_Equal)
|
|
|
|
{
|
|
|
|
Compiler->At += 1;
|
|
|
|
S_ParseExpression(Compiler);
|
|
|
|
S_EmitByte(Compiler, S_Op_SetGlobal);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
S_EmitByte(Compiler, S_Op_GetGlobal);
|
|
|
|
}
|
|
|
|
S_EmitVariableLength(Compiler, NameConstant);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseLineEntry(scene_compiler *Compiler)
|
|
|
|
{
|
|
|
|
token *LineToken = &Compiler->At[-1];
|
|
|
|
|
|
|
|
b32 EmitAwait = true;
|
|
|
|
|
|
|
|
// sixten: tags -> flags
|
|
|
|
scene_line_entry_flag Flags = 0;
|
|
|
|
for(;Compiler->At[0].Kind == TokenKind_PoundSign;)
|
|
|
|
{
|
|
|
|
Compiler->At += 1;
|
|
|
|
token TagToken = S_ConsumeToken(Compiler, TokenKind_Identifier, "Expected tag name after '#'.");
|
|
|
|
string TagString = T_StringFromToken(Compiler->Text, TagToken);
|
|
|
|
if(AreEqual(TagString, StrLit("noclear")))
|
|
|
|
{
|
|
|
|
Flags |= S_LineEntryFlag_NoClear;
|
|
|
|
}
|
|
|
|
else if(AreEqual(TagString, StrLit("noawait")))
|
|
|
|
{
|
|
|
|
EmitAwait = false;
|
2023-07-19 15:09:41 +00:00
|
|
|
}
|
2023-08-06 10:35:09 +00:00
|
|
|
else
|
2023-07-19 15:09:41 +00:00
|
|
|
{
|
2023-08-06 10:35:09 +00:00
|
|
|
S_ParseError(Compiler, "Unknown tag.");
|
2023-07-19 15:09:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-06 10:35:09 +00:00
|
|
|
S_ConsumeToken(Compiler, TokenKind_Semicolon, "Expected ';' after line entry.");
|
|
|
|
|
|
|
|
S_EmitByte(Compiler, S_Op_LineEntry|Flags);
|
|
|
|
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakePointer(LineToken)));
|
|
|
|
if(EmitAwait)
|
|
|
|
{
|
|
|
|
S_EmitByte(Compiler, S_Op_AwaitInput);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseStatement(scene_compiler *Compiler)
|
|
|
|
{
|
|
|
|
S_ParseExpression(Compiler);
|
|
|
|
S_ConsumeToken(Compiler, TokenKind_Semicolon, "Expected ';' after statement.");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseExpression(scene_compiler *Compiler)
|
|
|
|
{
|
|
|
|
S_ParsePrecedence(Compiler, S_Precedence_Assignment);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseLiteral(scene_compiler *Compiler, b32 CanAssign)
|
|
|
|
{
|
|
|
|
string Value = T_StringFromToken(Compiler->Text, Compiler->At[-1]);
|
|
|
|
switch(Compiler->At[-1].Kind)
|
|
|
|
{
|
|
|
|
case TokenKind_False: { S_EmitByte(Compiler, S_Op_False); } break;
|
|
|
|
case TokenKind_True: { S_EmitByte(Compiler, S_Op_True); } break;
|
|
|
|
InvalidDefaultCase;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseNumber(scene_compiler *Compiler, b32 CanAssign)
|
|
|
|
{
|
|
|
|
r64 Value = DoubleFromString(T_StringFromToken(Compiler->Text, Compiler->At[-1]));
|
|
|
|
|
|
|
|
S_EmitConstant(Compiler, S_MakeNumber(Value));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseGrouping(scene_compiler *Compiler, b32 CanAssign)
|
|
|
|
{
|
|
|
|
S_ParseExpression(Compiler);
|
|
|
|
S_ConsumeToken(Compiler, TokenKind_ParenthesisClose, "Expected ')' after expression.");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseUnary(scene_compiler *Compiler, b32 CanAssign)
|
|
|
|
{
|
|
|
|
scene_operator Operator = S_OperatorFromString(T_StringFromToken(Compiler->Text, Compiler->At[-1]));
|
|
|
|
S_ParsePrecedence(Compiler, S_Precedence_Unary);
|
|
|
|
|
|
|
|
switch(Operator)
|
|
|
|
{
|
|
|
|
case S_Operator_Minus: { S_EmitByte(Compiler, S_Op_Negate); } break;
|
|
|
|
case S_Operator_Not: { S_EmitByte(Compiler, S_Op_Not); } break;
|
|
|
|
InvalidDefaultCase;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParseBinary(scene_compiler *Compiler, b32 CanAssign)
|
|
|
|
{
|
|
|
|
token Token = Compiler->At[-1];
|
|
|
|
scene_operator Operator = S_OperatorFromString(T_StringFromToken(Compiler->Text, Token));
|
|
|
|
scene_parse_rule Rule = S_ParseRuleFromToken(Compiler, Token);
|
|
|
|
S_ParsePrecedence(Compiler, (scene_precedence)(Rule.Precedence + 1));
|
|
|
|
|
|
|
|
switch(Operator)
|
|
|
|
{
|
|
|
|
case S_Operator_Add: { S_EmitByte(Compiler, S_Op_Add); } break;
|
|
|
|
case S_Operator_Minus: { S_EmitByte(Compiler, S_Op_Subtract); } break;
|
|
|
|
case S_Operator_Multiply: { S_EmitByte(Compiler, S_Op_Multiply); } break;
|
|
|
|
case S_Operator_Divide: { S_EmitByte(Compiler, S_Op_Divide); } break;
|
|
|
|
case S_Operator_Equals: { S_EmitByte(Compiler, S_Op_Equal); } break;
|
|
|
|
case S_Operator_NotEquals: { S_EmitByte(Compiler, S_Op_Equal); S_EmitByte(Compiler, S_Op_Not); } break;
|
|
|
|
case S_Operator_Greater: { S_EmitByte(Compiler, S_Op_Greater); } break;
|
|
|
|
case S_Operator_GreaterThanOrEquals: { S_EmitByte(Compiler, S_Op_Less); S_EmitByte(Compiler, S_Op_Not); } break;
|
|
|
|
case S_Operator_Less: { S_EmitByte(Compiler, S_Op_Less); } break;
|
|
|
|
case S_Operator_LessThanOrEquals: { S_EmitByte(Compiler, S_Op_Greater); S_EmitByte(Compiler, S_Op_Not); } break;
|
|
|
|
InvalidDefaultCase;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void S_ParsePrecedence(scene_compiler *Compiler, scene_precedence Precedence)
|
|
|
|
{
|
|
|
|
b32 CanAssign = (Precedence <= S_Precedence_Assignment);
|
|
|
|
|
|
|
|
S_AdvanceCompiler(Compiler);
|
|
|
|
scene_parse_rule Rule = S_ParseRuleFromToken(Compiler, Compiler->At[-1]);
|
|
|
|
if(Rule.PrefixRule)
|
|
|
|
{
|
|
|
|
Rule.PrefixRule(Compiler, CanAssign);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
S_ParseError(Compiler, "Expected expression.");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
while(Precedence <= (Rule = S_ParseRuleFromToken(Compiler, Compiler->At[0])).Precedence)
|
|
|
|
{
|
|
|
|
S_AdvanceCompiler(Compiler);
|
|
|
|
Rule.InfixRule(Compiler, CanAssign);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(CanAssign && Compiler->At[0].Kind == TokenKind_Equal)
|
|
|
|
{
|
|
|
|
S_ParseError(Compiler, "Invalid assignment target.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static string S_DisassembleBytecode(scene_compiler *Compiler, scene_annotated_bytecode_chunk *Chunk, memory_arena *Arena)
|
|
|
|
{
|
|
|
|
string_list List = {};
|
|
|
|
|
|
|
|
temporary_memory Scratch = GetScratch(&Arena, 1);
|
|
|
|
|
|
|
|
u8 *ChunkBegin = Chunk->Data;
|
|
|
|
u8 *ChunkEnd = ChunkBegin + Chunk->Count;
|
|
|
|
for(u8 *Data = ChunkBegin; Data < ChunkEnd; Data += 1)
|
|
|
|
{
|
|
|
|
switch(*Data)
|
|
|
|
{
|
|
|
|
case S_Op_Constant:
|
|
|
|
{
|
|
|
|
Data += 1;
|
|
|
|
u64 ValueIndex = S_ReadVariableLength(&Data);
|
|
|
|
scene_value Value = Compiler->FirstValueChunk->Values[ValueIndex];
|
|
|
|
AppendString(&List, StrLit("Constant: "), Scratch.Arena);
|
|
|
|
switch(Value.Kind)
|
|
|
|
{
|
|
|
|
case S_ValueKind_Number: { AppendString(&List, PushFormat(Scratch.Arena, "%f (number)\n", Value.Number), Scratch.Arena); } break;
|
|
|
|
case S_ValueKind_Boolean: { AppendString(&List, PushFormat(Scratch.Arena, "%b (boolean)\n", Value.Boolean), Scratch.Arena); } break;
|
|
|
|
case S_ValueKind_Pointer: { AppendString(&List, PushFormat(Scratch.Arena, "%x (pointer)\n", Value.Pointer), Scratch.Arena); } break;
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
case S_Op_Nil: { AppendString(&List, StrLit("Nil\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_True: { AppendString(&List, StrLit("True\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_False: { AppendString(&List, StrLit("False\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_Negate: { AppendString(&List, StrLit("Negate\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_Not: { AppendString(&List, StrLit("Not\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_Add: { AppendString(&List, StrLit("Add\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_Subtract: { AppendString(&List, StrLit("Subtract\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_Multiply: { AppendString(&List, StrLit("Multiply\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_Divide: { AppendString(&List, StrLit("Divide\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_Equal: { AppendString(&List, StrLit("Equal\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_Greater: { AppendString(&List, StrLit("Greater\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_Less: { AppendString(&List, StrLit("Less\n"), Scratch.Arena); } break;
|
|
|
|
case S_Op_DefineGlobal:
|
|
|
|
{
|
|
|
|
Data += 1;
|
|
|
|
|
|
|
|
u64 Index = S_ReadVariableLength(&Data);
|
|
|
|
u64 Pointer = Compiler->FirstValueChunk->Values[Index].Pointer;
|
|
|
|
token *Token = (token *)Pointer;
|
|
|
|
string String = T_StringFromToken(Compiler->Text, *Token);
|
|
|
|
AppendString(&List, StrLit("Define Global: "), Scratch.Arena);
|
|
|
|
AppendString(&List, String, Scratch.Arena);
|
|
|
|
AppendString(&List, StrLit("\n"), Scratch.Arena);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case S_Op_GetGlobal:
|
|
|
|
{
|
|
|
|
Data += 1;
|
|
|
|
u64 Pointer = Compiler->FirstValueChunk->Values[S_ReadVariableLength(&Data)].Pointer;
|
|
|
|
token *Token = (token *)Pointer;
|
|
|
|
string String = T_StringFromToken(Compiler->Text, *Token);
|
|
|
|
AppendString(&List, PushFormat(Scratch.Arena, "Get Global: %S\n", String), Scratch.Arena);
|
|
|
|
} break;
|
|
|
|
case S_Op_SetGlobal:
|
|
|
|
{
|
|
|
|
Data += 1;
|
|
|
|
u64 Pointer = Compiler->FirstValueChunk->Values[S_ReadVariableLength(&Data)].Pointer;
|
|
|
|
token *Token = (token *)Pointer;
|
|
|
|
string String = T_StringFromToken(Compiler->Text, *Token);
|
|
|
|
AppendString(&List, PushFormat(Scratch.Arena, "Set Global: %S\n", String), Scratch.Arena);
|
|
|
|
} break;
|
|
|
|
case S_Op_AwaitInput: { AppendString(&List, StrLit("Await Input\n"), Scratch.Arena); } break;
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
if(*Data & S_Op_LineEntry)
|
|
|
|
{
|
|
|
|
Data += 1;
|
|
|
|
u64 Pointer = Compiler->FirstValueChunk->Values[S_ReadVariableLength(&Data)].Pointer;
|
|
|
|
token *Token = (token *)Pointer;
|
|
|
|
string String = Substring(Compiler->Text, Pad(Token->Range, -1));
|
|
|
|
AppendString(&List, PushFormat(Scratch.Arena, "Line Entry: %S\n", String), Scratch.Arena);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
AppendString(&List, StrLit("Unknown Op\n"), Scratch.Arena);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
string Result = JoinStringList(&List, Arena);
|
|
|
|
|
2023-07-19 15:09:41 +00:00
|
|
|
ReleaseScratch(Scratch);
|
2023-08-06 10:35:09 +00:00
|
|
|
return(Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct proc_from_chunks_result
|
|
|
|
{
|
|
|
|
scene_proc *Proc;
|
|
|
|
scene_annotated_bytecode_chunk *NextChunk;
|
|
|
|
};
|
|
|
|
|
|
|
|
static proc_from_chunks_result S_ProcFromChunks(memory_arena *Arena, scene_annotated_bytecode_chunk *First)
|
|
|
|
{
|
|
|
|
Assert(First != 0);
|
|
|
|
string ChunkName = First->Name;
|
2023-07-19 15:09:41 +00:00
|
|
|
|
2023-08-06 10:35:09 +00:00
|
|
|
//- sixten: find required bytes
|
|
|
|
s64 RequiredBytes = 0;
|
|
|
|
scene_annotated_bytecode_chunk *NextChunk = 0;
|
2023-07-19 15:09:41 +00:00
|
|
|
{
|
2023-08-06 10:35:09 +00:00
|
|
|
scene_annotated_bytecode_chunk *Chunk = First;
|
|
|
|
for(; Chunk != 0 && AreEqual(Chunk->Name, ChunkName); Chunk = Chunk->Next)
|
|
|
|
{
|
|
|
|
RequiredBytes += Chunk->Count;
|
|
|
|
}
|
|
|
|
NextChunk= Chunk;
|
|
|
|
}
|
|
|
|
|
|
|
|
scene_proc *Proc = PushStruct(Arena, scene_proc);
|
|
|
|
Proc->Name = ChunkName;
|
|
|
|
Proc->Data = PushArray(Arena, u8, RequiredBytes);
|
|
|
|
Proc->Count = RequiredBytes;
|
|
|
|
|
|
|
|
//- sixten: copy over data from chunks
|
|
|
|
u8 *Dest = Proc->Data;
|
|
|
|
for(scene_annotated_bytecode_chunk *Chunk = First; Chunk != NextChunk; Chunk = Chunk->Next)
|
|
|
|
{
|
|
|
|
Copy(Dest, Chunk->Data, Chunk->Count);
|
|
|
|
Dest += Chunk->Count;
|
|
|
|
}
|
|
|
|
|
|
|
|
//- sixten: fill & return
|
|
|
|
proc_from_chunks_result Result;
|
|
|
|
{
|
|
|
|
Result.Proc = Proc;
|
|
|
|
Result.NextChunk = NextChunk;
|
|
|
|
}
|
|
|
|
return(Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static compiled_scene S_ScriptFromText(memory_arena *Arena, string Text)
|
|
|
|
{
|
|
|
|
compiled_scene Result = {};
|
|
|
|
|
|
|
|
temporary_memory Scratch = GetScratch(&Arena, 1);
|
|
|
|
tokenize_result TokenizeResult = T_TokenizeFromText(Arena, Text, T_IsIrregular);
|
|
|
|
|
|
|
|
// sixten(TODO): append token errors
|
|
|
|
|
|
|
|
//- sixten: tokens -> bytecode
|
|
|
|
scene_compiler Compiler = {};
|
|
|
|
{
|
|
|
|
Compiler.Arena = Scratch.Arena;
|
|
|
|
Compiler.Text = Text;
|
|
|
|
Compiler.TokensBegin = TokenizeResult.Tokens.Tokens;
|
|
|
|
Compiler.TokensEnd = Compiler.TokensBegin+TokenizeResult.Tokens.Count;
|
|
|
|
Compiler.At = Compiler.TokensBegin;
|
2023-07-19 15:09:41 +00:00
|
|
|
};
|
2023-08-06 10:35:09 +00:00
|
|
|
|
|
|
|
S_SetEmissionTarget(&Compiler, StrLit(""));
|
|
|
|
|
|
|
|
for(;Compiler.At < Compiler.TokensEnd;)
|
|
|
|
{
|
|
|
|
S_ParseTopLevelDeclaration(&Compiler);
|
|
|
|
}
|
|
|
|
|
|
|
|
//- sixten: bake compiled chunks
|
|
|
|
for(s64 BucketIndex = 0; BucketIndex < ArrayCount(Compiler.ProcBuckets); BucketIndex += 1)
|
|
|
|
{
|
|
|
|
scene_annotated_bytecode_bucket *Bucket = &Compiler.ProcBuckets[BucketIndex];
|
|
|
|
for(scene_annotated_bytecode_chunk *Chunk = Bucket->First; Chunk != 0;)
|
|
|
|
{
|
|
|
|
proc_from_chunks_result ProcResult = S_ProcFromChunks(Arena, Chunk);
|
|
|
|
s64 Hash = HashString(Chunk->Name);
|
|
|
|
scene_proc_bucket *DestBucket = &Result.Buckets[Hash%ArrayCount(Result.Buckets)];
|
|
|
|
QueuePush(DestBucket->First, DestBucket->Last, ProcResult.Proc);
|
|
|
|
Chunk = ProcResult.NextChunk;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//- sixten: bake value chunks
|
|
|
|
{
|
|
|
|
Result.Values = PushArray(Arena, scene_value, Compiler.ValueCount);
|
|
|
|
Result.ValueCount = Compiler.ValueCount;
|
|
|
|
scene_value *Dest = Result.Values;
|
|
|
|
for(scene_value_chunk *Chunk = Compiler.FirstValueChunk; Chunk != 0; Chunk = Chunk->Next)
|
|
|
|
{
|
|
|
|
Copy(Dest, Chunk->Values, Chunk->Count);
|
|
|
|
Dest += Chunk->Count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// sixten(IMPORTANT): The text is assumed to remain in memory for the duration of the scene.
|
|
|
|
Result.Source = Text;
|
|
|
|
|
|
|
|
ReleaseScratch(Scratch);
|
2023-07-19 15:09:41 +00:00
|
|
|
return(Result);
|
|
|
|
}
|