Added scene bytecode generation & file navigation.
parent
30e384e0a4
commit
a3e2314fd0
|
@ -6,6 +6,7 @@
|
|||
#include <stdint.h>
|
||||
#include <intrin.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//- sixten: Base types
|
||||
|
||||
|
@ -72,6 +73,10 @@ typedef intptr_t smm;
|
|||
#define InvalidCodepath Assert(!"Invalid codepath")
|
||||
#define InvalidDefaultCase default: { Assert(!"Invalid codepath"); } break
|
||||
|
||||
//- sixten: Compiler warning helpers
|
||||
|
||||
#define UnusedVariable(Var) ((void)(Var))
|
||||
|
||||
//- sixten: Array & pointer manipulation
|
||||
|
||||
#define ArrayCount(Array) (sizeof(Array)/sizeof((Array)[0]))
|
||||
|
@ -169,6 +174,9 @@ auto __Temp = (Element)->Next->Prev;\
|
|||
(Element)->Next->Prev = (Element)->Prev->Next;\
|
||||
(Element)->Prev->Next = __Temp;
|
||||
|
||||
#define SenDLLIsEmpty(Sentinel)\
|
||||
((Sentinel)->Next==(Sentinel))
|
||||
|
||||
//- sixten: Stringify
|
||||
|
||||
#define _Stringify(x) #x
|
||||
|
|
|
@ -519,6 +519,12 @@ inline range1_r32 Intersection(range1_r32 A, range1_r32 B)
|
|||
return(Result);
|
||||
}
|
||||
|
||||
inline range1_r32 Pad(range1_r32 Range, r32 Value)
|
||||
{
|
||||
range1_r32 Result = Range1R32(Range.Min-Value, Range.Max+Value);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline range1_s32 Range1S32(s32 A, s32 B)
|
||||
{
|
||||
range1_s32 Result = {Min(A, B), Max(A, B)};
|
||||
|
@ -549,6 +555,12 @@ inline range1_s32 Intersection(range1_s32 A, range1_s32 B)
|
|||
return(Result);
|
||||
}
|
||||
|
||||
inline range1_s32 Pad(range1_s32 Range, s32 Value)
|
||||
{
|
||||
range1_s32 Result = Range1S32(Range.Min-Value, Range.Max+Value);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline range1_s64 Range1S64(s64 A, s64 B)
|
||||
{
|
||||
range1_s64 Result = {Min(A, B), Max(A, B)};
|
||||
|
@ -579,6 +591,12 @@ inline range1_s64 Intersection(range1_s64 A, range1_s64 B)
|
|||
return(Result);
|
||||
}
|
||||
|
||||
inline range1_s64 Pad(range1_s64 Range, s64 Value)
|
||||
{
|
||||
range1_s64 Result = Range1S64(Range.Min-Value, Range.Max+Value);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline range2_r32 Range2R32(v2_r32 A, v2_r32 B)
|
||||
{
|
||||
range2_r32 Result = {Min(A, B), Max(A, B)};
|
||||
|
|
|
@ -333,18 +333,21 @@ inline b32 InRange(range1_r32 Range, r32 Value);
|
|||
inline b32 Contains(range1_r32 Range, r32 Value);
|
||||
inline r32 DimOfRange(range1_r32 Range);
|
||||
inline range1_r32 Intersection(range1_r32 A, range1_r32 B);
|
||||
inline range1_r32 Pad(range1_r32 Range, r32 Value);
|
||||
|
||||
inline range1_s32 Range1S32(s32 A, s32 B);
|
||||
inline b32 InRange(range1_s32 Range, s32 Value);
|
||||
inline b32 Contains(range1_s32 Range, s32 Value);
|
||||
inline s32 DimOfRange(range1_s32 Range);
|
||||
inline range1_s32 Intersection(range1_s32 A, range1_s32 B);
|
||||
inline range1_s32 Pad(range1_s32 Range, s32 Value);
|
||||
|
||||
inline range1_s64 Range1S64(s64 A, s64 B);
|
||||
inline b32 InRange(range1_s64 Range, s64 Value);
|
||||
inline b32 Contains(range1_s64 Range, s64 Value);
|
||||
inline s64 DimOfRange(range1_s64 Range);
|
||||
inline range1_s64 Intersection(range1_s64 A, range1_s64 B);
|
||||
inline range1_s64 Pad(range1_s64 Range, s64 Value);
|
||||
|
||||
inline range2_r32 Range2R32(v2_r32 A, v2_r32 B);
|
||||
inline b32 InRange(range2_r32 Range, v2_r32 Value);
|
||||
|
|
|
@ -115,6 +115,11 @@ static void ArenaPopTo(memory_arena *Arena, u64 Position)
|
|||
}
|
||||
}
|
||||
|
||||
static void ArenaPop(memory_arena *Arena, u64 Amount)
|
||||
{
|
||||
ArenaPopTo(Arena, Max(Arena->Position-Amount, (s64)sizeof(memory_arena)));
|
||||
}
|
||||
|
||||
static void ArenaClear(memory_arena *Arena)
|
||||
{
|
||||
ArenaPopTo(Arena, sizeof(*Arena));
|
||||
|
|
|
@ -42,6 +42,7 @@ static void ArenaRelease(memory_arena *Arena);
|
|||
static void *ArenaPushNoClear(memory_arena *Arena, u64 Size);
|
||||
static void *ArenaPush(memory_arena *Arena, u64 Size);
|
||||
static void ArenaPopTo(memory_arena *Arena, u64 Position);
|
||||
static void ArenaPop(memory_arena *Arena, u64 Amount);
|
||||
static void ArenaClear(memory_arena *Arena);
|
||||
static void ArenaSetAlign(memory_arena *Arena, u64 Align);
|
||||
#define PushArray(Arena, type, Count) (type *)ArenaPush((Arena), sizeof(type)*(Count))
|
||||
|
|
|
@ -294,6 +294,15 @@ static string StringFromCodepoint(memory_arena *Arena, u32 Codepoint)
|
|||
return(Result);
|
||||
}
|
||||
|
||||
static r64 DoubleFromString(string String)
|
||||
{
|
||||
temporary_memory Scratch = GetScratch();
|
||||
string NullTerminated = PushString(Scratch.Arena, String);
|
||||
r64 Result = strtod((char *)NullTerminated.Data, 0);
|
||||
ReleaseScratch(Scratch);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
//- sixten: Replacing
|
||||
|
||||
static string RemoveAll(memory_arena *Arena, string Text, char ToRemove)
|
||||
|
@ -578,7 +587,7 @@ static u32 EncodeUTF8Codepoint(u8 *Dest, u32 Codepoint)
|
|||
return(Size);
|
||||
}
|
||||
|
||||
static string_decode DecodeUTF16Codepoint(u8 *Data, s64 Count)
|
||||
static string_decode DecodeUTF16Codepoint(u16 *Data, s64 Count)
|
||||
{
|
||||
string_decode Result = {'#', 1};
|
||||
if(Data[0] < 0xD800 || 0xDFFF < Data[0])
|
||||
|
@ -622,7 +631,7 @@ static s64 UTF8IndexFromOffset(string String, s64 Offset)
|
|||
u8 *StringBegin = String.Data;
|
||||
u8 *StringEnd = StringBegin+String.Count;
|
||||
u8 *Byte = StringBegin;
|
||||
for(;Byte < StringEnd && Offset > 1; Offset -= 1)
|
||||
for(;Byte < StringEnd && Offset > 0; Offset -= 1)
|
||||
{
|
||||
Byte += DecodeUTF8Codepoint(Byte, StringEnd-Byte).Size;
|
||||
}
|
||||
|
@ -682,6 +691,54 @@ static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint)
|
|||
return(Length);
|
||||
}
|
||||
|
||||
static string String8FromString16(memory_arena *Arena, string16 String)
|
||||
{
|
||||
s64 AllocGuess = String.Count*3+1;
|
||||
u8 *Memory = PushArray(Arena, u8, AllocGuess);
|
||||
u16 *StringBegin = String.Data;
|
||||
u16 *StringEnd = StringBegin+String.Count;
|
||||
u16 *Source = StringBegin;
|
||||
u8 *Dest = Memory;
|
||||
for(;Source < StringEnd;)
|
||||
{
|
||||
string_decode Decode = DecodeUTF16Codepoint(Source, StringEnd-Source);
|
||||
Dest += EncodeUTF8Codepoint(Dest, Decode.Codepoint);
|
||||
Source += Decode.Size;
|
||||
}
|
||||
*Dest = 0;
|
||||
s64 AllocUsed = Dest-Memory;
|
||||
s64 AllocUnused = AllocGuess-AllocUsed;
|
||||
Assert(AllocUnused >= 0);
|
||||
ArenaPop(Arena, AllocUnused);
|
||||
|
||||
string Result = MakeString(Memory, AllocUsed);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static string16 String16FromString8(memory_arena *Arena, string String)
|
||||
{
|
||||
s64 AllocGuess = String.Count*2+1;
|
||||
u16 *Memory = PushArray(Arena, u16, AllocGuess);
|
||||
u8 *StringBegin = String.Data;
|
||||
u8 *StringEnd = StringBegin+String.Count;
|
||||
u8 *Source = StringBegin;
|
||||
u16 *Dest = Memory;
|
||||
for(;Source < StringEnd;)
|
||||
{
|
||||
string_decode Decode = DecodeUTF8Codepoint(Source, StringEnd-Source);
|
||||
Dest += EncodeUTF16Codepoint(Dest, Decode.Codepoint);
|
||||
Source += Decode.Size;
|
||||
}
|
||||
*Dest = 0;
|
||||
s64 AllocUsed = Dest-Memory;
|
||||
s64 AllocUnused = AllocGuess-AllocUsed;
|
||||
Assert(AllocUnused >= 0);
|
||||
ArenaPop(Arena, AllocUnused);
|
||||
|
||||
string16 Result = {AllocUsed, Memory};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
//~ sixten: Text point
|
||||
|
||||
static text_point TextPointFromOffset(string String, s64 Offset)
|
||||
|
|
|
@ -12,6 +12,12 @@ struct string
|
|||
u8 *Data;
|
||||
};
|
||||
|
||||
struct string16
|
||||
{
|
||||
s64 Count;
|
||||
u16 *Data;
|
||||
};
|
||||
|
||||
typedef string buffer;
|
||||
|
||||
struct string_node
|
||||
|
@ -94,6 +100,7 @@ static string PushCString(memory_arena *Arena, char *String);
|
|||
static s64 ConvertStringToS64(string String);
|
||||
static string ConvertS64ToString(memory_arena *Arena, s64 Value);
|
||||
static string StringFromCodepoint(memory_arena *Arena, u32 Codepoint);
|
||||
static r64 DoubleFromString(string String);
|
||||
|
||||
//- sixten: Replacing
|
||||
|
||||
|
@ -129,11 +136,14 @@ struct string_decode
|
|||
static string_decode DecodeUTF8Codepoint(u8 *Data, s64 Count);
|
||||
static u32 EncodeUTF8Codepoint(u8 *Dest, u32 Codepoint);
|
||||
|
||||
static string_decode DecodeUTF16Codepoint(u8 *Data, s64 Count);
|
||||
static string_decode DecodeUTF16Codepoint(u16 *Data, s64 Count);
|
||||
static u32 EncodeUTF16Codepoint(u16 *Dest, u32 Codepoint);
|
||||
|
||||
static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint);
|
||||
|
||||
static string String8FromString16(memory_arena *Arena, string16 String);
|
||||
static string16 String16FromString8(memory_arena *Arena, string String);
|
||||
|
||||
//~ sixten: Text point
|
||||
|
||||
struct text_point
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
#define PLATFORM_SET_CURSOR(name) void name(platform_cursor Cursor)
|
||||
#define PLATFORM_TOGGLE_FULLSCREEN(name) void name(void)
|
||||
#define PLATFORM_SHOW_MESSAGE(name) void name(string Message, platform_message_type Type)
|
||||
#define PLATFORM_BEGIN_FILE_ITER(name) platform_file_iter * name(memory_arena *Arena, string Path)
|
||||
#define PLATFORM_ADVANCE_FILE_ITER(name) b32 name(memory_arena *Arena, platform_file_iter *Iter, platform_file_info *OutInfo)
|
||||
#define PLATFORM_END_FILE_ITER(name) void name(platform_file_iter *Iter)
|
||||
|
||||
typedef PLATFORM_RESERVE(platform_reserve);
|
||||
typedef PLATFORM_RELEASE(platform_release);
|
||||
|
@ -23,6 +26,9 @@ typedef PLATFORM_GET_FILE_SIZE(platform_get_file_size);
|
|||
typedef PLATFORM_SET_CURSOR(platform_set_cursor);
|
||||
typedef PLATFORM_TOGGLE_FULLSCREEN(platform_toggle_fullscreen);
|
||||
typedef PLATFORM_SHOW_MESSAGE(platform_show_message);
|
||||
typedef PLATFORM_BEGIN_FILE_ITER(platform_begin_file_iter);
|
||||
typedef PLATFORM_ADVANCE_FILE_ITER(platform_advance_file_iter);
|
||||
typedef PLATFORM_END_FILE_ITER(platform_end_file_iter);
|
||||
|
||||
struct platform_api
|
||||
{
|
||||
|
@ -38,6 +44,9 @@ platform_get_file_size *GetFileSize;
|
|||
platform_set_cursor *SetCursor;
|
||||
platform_toggle_fullscreen *ToggleFullscreen;
|
||||
platform_show_message *ShowMessage;
|
||||
platform_begin_file_iter *BeginFileIter;
|
||||
platform_advance_file_iter *AdvanceFileIter;
|
||||
platform_end_file_iter *EndFileIter;
|
||||
};
|
||||
|
||||
#define RegisterPlatformFunctions(PlatformName)\
|
||||
|
@ -53,4 +62,7 @@ Platform.GetFileSize = PlatformName##_GetFileSize;\
|
|||
Platform.SetCursor = PlatformName##_SetCursor;\
|
||||
Platform.ToggleFullscreen = PlatformName##_ToggleFullscreen;\
|
||||
Platform.ShowMessage = PlatformName##_ShowMessage;\
|
||||
Platform.BeginFileIter = PlatformName##_BeginFileIter;\
|
||||
Platform.AdvanceFileIter = PlatformName##_AdvanceFileIter;\
|
||||
Platform.EndFileIter = PlatformName##_EndFileIter;\
|
||||
|
||||
|
|
|
@ -1,25 +1,37 @@
|
|||
enum scene_ast_node_type
|
||||
enum scene_operator
|
||||
{
|
||||
S_AstNode_Invalid,
|
||||
S_AstNode_BlockStatement,
|
||||
S_AstNode_SceneDecl,
|
||||
S_AstNode_Count,
|
||||
S_Operator_Invalid,
|
||||
S_Operator_Not,
|
||||
S_Operator_Equal,
|
||||
S_Operator_Equals,
|
||||
S_Operator_NotEquals,
|
||||
S_Operator_GreaterThanOrEquals,
|
||||
S_Operator_LessThanOrEquals,
|
||||
S_Operator_Greater,
|
||||
S_Operator_Less,
|
||||
S_Operator_Add,
|
||||
S_Operator_Minus,
|
||||
S_Operator_Multiply,
|
||||
S_Operator_Divide,
|
||||
};
|
||||
|
||||
struct scene_ast_node;
|
||||
|
||||
struct scene_ast_node_invalid {};
|
||||
struct scene_ast_node_block_statement {scene_ast_node *First; scene_ast_node *Last;};
|
||||
struct scene_ast_node_scene_declaration {};
|
||||
|
||||
struct scene_ast_node
|
||||
inline scene_operator S_OperatorFromString(string String)
|
||||
{
|
||||
scene_ast_node_type Type;
|
||||
union
|
||||
{
|
||||
scene_ast_node_invalid InvalidData;
|
||||
scene_ast_node_block_statement BlockStatementData;
|
||||
scene_ast_node_scene_declaration SceneDeclData;
|
||||
};
|
||||
};
|
||||
scene_operator Result = S_Operator_Invalid;
|
||||
if(0) {}
|
||||
else if(AreEqual(String, StrLit("###"))) { Result = S_Operator_Invalid; }
|
||||
else if(AreEqual(String, StrLit("!"))) { Result = S_Operator_Not; }
|
||||
else if(AreEqual(String, StrLit("="))) { Result = S_Operator_Equal; }
|
||||
else if(AreEqual(String, StrLit("=="))) { Result = S_Operator_Equals; }
|
||||
else if(AreEqual(String, StrLit("!="))) { Result = S_Operator_NotEquals; }
|
||||
else if(AreEqual(String, StrLit(">="))) { Result = S_Operator_GreaterThanOrEquals; }
|
||||
else if(AreEqual(String, StrLit("<="))) { Result = S_Operator_LessThanOrEquals; }
|
||||
else if(AreEqual(String, StrLit(">"))) { Result = S_Operator_Greater; }
|
||||
else if(AreEqual(String, StrLit("<"))) { Result = S_Operator_Less; }
|
||||
else if(AreEqual(String, StrLit("+"))) { Result = S_Operator_Add; }
|
||||
else if(AreEqual(String, StrLit("-"))) { Result = S_Operator_Minus; }
|
||||
else if(AreEqual(String, StrLit("*"))) { Result = S_Operator_Multiply; }
|
||||
else if(AreEqual(String, StrLit("/"))) { Result = S_Operator_Divide; }
|
||||
return(Result);
|
||||
}
|
||||
|
||||
|
|
12
code/vn.cpp
12
code/vn.cpp
|
@ -13,7 +13,7 @@ struct debug_settings
|
|||
b32 ShowWelcomeMessage;
|
||||
};
|
||||
|
||||
per_thread debug_settings *DEBUG_DebugSettings = 0;
|
||||
global debug_settings *DEBUG_DebugSettings = 0;
|
||||
#endif
|
||||
|
||||
#include "vn_tokenizer.h"
|
||||
|
@ -50,6 +50,9 @@ struct vn_state
|
|||
|
||||
render_handle BackgroundTexture;
|
||||
|
||||
memory_arena *SceneArena;
|
||||
compiled_scene CompiledScene;
|
||||
|
||||
#if VN_INTERNAL
|
||||
debug_settings DebugSettings;
|
||||
#endif
|
||||
|
@ -107,7 +110,7 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
|
|||
State->Config = CreateConfig();
|
||||
|
||||
//- sixten: load assets
|
||||
State->BackgroundTexture = CreateTextureFromPath(RenderCommands, StrLit("data/backgrounds/Futon_Room.png"));
|
||||
//State->BackgroundTexture = CreateTextureFromPath(RenderCommands, StrLit("data/backgrounds/Futon_Room.png"));
|
||||
|
||||
//- sixten: setup config binds and load current config
|
||||
{
|
||||
|
@ -120,9 +123,14 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
|
|||
Config_BindB32(State->Config, StrLit("Dev/ShowWelcomeMessage"), &DEBUG_DebugSettings->ShowWelcomeMessage, 1);
|
||||
#endif
|
||||
|
||||
|
||||
Config_ReadFile(State->Config, StrLit("config.vn"));
|
||||
}
|
||||
|
||||
//- sixten: load startup scene
|
||||
State->SceneArena = ArenaAllocate(Gigabytes(1));
|
||||
State->CompiledScene = S_ScriptFromText(State->SceneArena, Platform_ReadEntireFile(State->SceneArena, StrLit("data/compiler_test.vns")));
|
||||
|
||||
UI_Init(&State->UI);
|
||||
Workspace_Init(&State->Workspace);
|
||||
AnimationCurve_Init(&State->AnimationCurveState);
|
||||
|
|
|
@ -87,7 +87,7 @@ static void Config_ReadFile(config *Config, string Path)
|
|||
|
||||
//- sixten: read & tokenize input file
|
||||
string Text = Platform_ReadEntireFile(Scratch.Arena, Path);
|
||||
tokenize_result TokenizeResult = T_TokenizeFromText(Scratch.Arena, Path, Text, TokenGroup_Whitespace|TokenGroup_Comment);
|
||||
tokenize_result TokenizeResult = T_TokenizeFromText(Scratch.Arena, Text, T_IsIrregular);
|
||||
token_array Tokens = TokenizeResult.Tokens;
|
||||
|
||||
// sixten: parse context
|
||||
|
@ -103,7 +103,7 @@ static void Config_ReadFile(config *Config, string Path)
|
|||
string TokenString = Substring(Text, Token->Range);
|
||||
|
||||
//- sixten: get next name
|
||||
if(ParseMode == ConfigParseMode_Main && Token->Flags & TokenFlag_Identifier)
|
||||
if(ParseMode == ConfigParseMode_Main && Token->Kind & TokenKind_Identifier)
|
||||
{
|
||||
Config_ParseListPush(Scratch.Arena, &FullPath, TokenString);
|
||||
ParseMode = ConfigParseMode_ScanForCurlyOpenOrEquals;
|
||||
|
@ -112,7 +112,7 @@ static void Config_ReadFile(config *Config, string Path)
|
|||
}
|
||||
|
||||
//- sixten: scan for curly close
|
||||
if(ParseMode == ConfigParseMode_Main && Token->Flags & TokenFlag_Reserved && AreEqual(TokenString, StrLit("}")))
|
||||
if(ParseMode == ConfigParseMode_Main && Token->Kind == TokenKind_CurlyClose)
|
||||
{
|
||||
Config_ParseListPop(&FullPath);
|
||||
Token += 1;
|
||||
|
@ -120,7 +120,7 @@ static void Config_ReadFile(config *Config, string Path)
|
|||
}
|
||||
|
||||
//- sixten: scan for curly open
|
||||
if(ParseMode == ConfigParseMode_ScanForCurlyOpenOrEquals && Token->Flags & TokenFlag_Reserved && AreEqual(TokenString, StrLit("{")))
|
||||
if(ParseMode == ConfigParseMode_ScanForCurlyOpenOrEquals && Token->Kind == TokenKind_CurlyOpen)
|
||||
{
|
||||
ParseMode = ConfigParseMode_Main;
|
||||
Token += 1;
|
||||
|
@ -128,7 +128,7 @@ static void Config_ReadFile(config *Config, string Path)
|
|||
}
|
||||
|
||||
//- sixten: scan for equals
|
||||
if(ParseMode == ConfigParseMode_ScanForCurlyOpenOrEquals && Token->Flags & TokenFlag_Symbol && AreEqual(TokenString, StrLit("=")))
|
||||
if(ParseMode == ConfigParseMode_ScanForCurlyOpenOrEquals && Token->Kind & TokenKind_Equal)
|
||||
{
|
||||
ParseMode = ConfigParseMode_ScanForValue;
|
||||
Token += 1;
|
||||
|
@ -136,7 +136,7 @@ static void Config_ReadFile(config *Config, string Path)
|
|||
}
|
||||
|
||||
//- sixten: scan for semicolon
|
||||
if(ParseMode == ConfigParseMode_ScanForSemicolon && Token->Flags & TokenFlag_Reserved && AreEqual(TokenString, StrLit(";")))
|
||||
if(ParseMode == ConfigParseMode_ScanForSemicolon && Token->Kind == TokenKind_Semicolon)
|
||||
{
|
||||
ParseMode = ConfigParseMode_Main;
|
||||
Token += 1;
|
||||
|
@ -144,7 +144,7 @@ static void Config_ReadFile(config *Config, string Path)
|
|||
}
|
||||
|
||||
//- sixten: scan for boolean value
|
||||
if(ParseMode == ConfigParseMode_ScanForValue && Token->Flags & TokenFlag_Identifier && (AreEqual(TokenString, StrLit("true")) || AreEqual(TokenString, StrLit("false"))))
|
||||
if(ParseMode == ConfigParseMode_ScanForValue && (Token->Kind == TokenKind_True || Token->Kind == TokenKind_False))
|
||||
{
|
||||
string FullName = Config_ParseListJoin(Scratch.Arena, &FullPath);
|
||||
config_entry *Entry = Config_FindEntryByName(Config, FullName);
|
||||
|
@ -161,7 +161,7 @@ static void Config_ReadFile(config *Config, string Path)
|
|||
}
|
||||
|
||||
//- sixten: scan for integer value
|
||||
if(ParseMode == ConfigParseMode_ScanForValue && Token->Flags & TokenFlag_Numeric)
|
||||
if(ParseMode == ConfigParseMode_ScanForValue && Token->Kind & TokenKind_Numeric)
|
||||
{
|
||||
string FullName = Config_ParseListJoin(Scratch.Arena, &FullPath);
|
||||
config_entry *Entry = Config_FindEntryByName(Config, FullName);
|
||||
|
|
|
@ -15,46 +15,51 @@ enum font_id
|
|||
Font_Count,
|
||||
};
|
||||
|
||||
#define FontIcon_None 0x0000
|
||||
#define FontIcon_Pencil 0xe800
|
||||
#define FontIcon_Forward 0xe801
|
||||
#define FontIcon_Book 0xe802
|
||||
#define FontIcon_FolderOpen 0xe803
|
||||
#define FontIcon_Wrench 0xe804
|
||||
#define FontIcon_CW 0xe805
|
||||
#define FontIcon_CCW 0xe806
|
||||
#define FontIcon_ArrowsCW 0xe807
|
||||
#define FontIcon_ResizeVertical 0xe808
|
||||
#define FontIcon_ResizeHorizontal 0xe809
|
||||
#define FontIcon_Play 0xe80a
|
||||
#define FontIcon_Stop 0xe80b
|
||||
#define FontIcon_Floppy 0xe80c
|
||||
#define FontIcon_Pause 0xe80d
|
||||
#define FontIcon_Folder 0xe80e
|
||||
#define FontIcon_Cog 0xe80f
|
||||
#define FontIcon_Attention 0xe810
|
||||
#define FontIcon_Cancel 0xe811
|
||||
#define FontIcon_Filter 0xf0b0
|
||||
#define FontIcon_Menu 0xf0c9
|
||||
#define FontIcon_CircleEmpty 0xf10c
|
||||
#define FontIcon_Circle 0xf111
|
||||
#define FontIcon_Reply 0xf112
|
||||
#define FontIcon_Terminal 0xf120
|
||||
#define FontIcon_Ellipsis 0xf141
|
||||
#define FontIcon_Document 0xf15b
|
||||
#define FontIcon_DocumentText 0xf15c
|
||||
#define FontIcon_Eyedropper 0xf1fb
|
||||
#define FontIcon_WindowMaximize 0xf2d0
|
||||
#define FontIcon_WindowMinimize 0xf2d1
|
||||
#define FontIcon_WindowRestore 0xf2d2
|
||||
#define FontIcon_WindowClose 0xf2d4
|
||||
#define FontIcon_DownDir 0xe812
|
||||
#define FontIcon_UpDir 0xe813
|
||||
#define FontIcon_LeftDir 0xe814
|
||||
#define FontIcon_RightDir 0xe815
|
||||
#define FontIcon_TextAlignLeft 0xe816
|
||||
#define FontIcon_TextAlignCenter 0xe817
|
||||
#define FontIcon_TextAlignRight 0xe818
|
||||
#define FontIcon_None 0x0000
|
||||
#define FontIcon_Pencil 0xe800
|
||||
#define FontIcon_Forward 0xe801
|
||||
#define FontIcon_Book 0xe802
|
||||
#define FontIcon_FolderOpen 0xe803
|
||||
#define FontIcon_Wrench 0xe804
|
||||
#define FontIcon_CW 0xe805
|
||||
#define FontIcon_CCW 0xe806
|
||||
#define FontIcon_ArrowsCW 0xe807
|
||||
#define FontIcon_ResizeVertical 0xe808
|
||||
#define FontIcon_ResizeHorizontal 0xe809
|
||||
#define FontIcon_Play 0xe80a
|
||||
#define FontIcon_Stop 0xe80b
|
||||
#define FontIcon_Floppy 0xe80c
|
||||
#define FontIcon_Pause 0xe80d
|
||||
#define FontIcon_Folder 0xe80e
|
||||
#define FontIcon_Cog 0xe80f
|
||||
#define FontIcon_Attention 0xe810
|
||||
#define FontIcon_Cancel 0xe811
|
||||
#define FontIcon_Filter 0xf0b0
|
||||
#define FontIcon_Menu 0xf0c9
|
||||
#define FontIcon_CircleEmpty 0xf10c
|
||||
#define FontIcon_Circle 0xf111
|
||||
#define FontIcon_Reply 0xf112
|
||||
#define FontIcon_Terminal 0xf120
|
||||
#define FontIcon_Ellipsis 0xf141
|
||||
#define FontIcon_Document 0xf15b
|
||||
#define FontIcon_DocumentText 0xf15c
|
||||
#define FontIcon_Eyedropper 0xf1fb
|
||||
#define FontIcon_WindowMaximize 0xf2d0
|
||||
#define FontIcon_WindowMinimize 0xf2d1
|
||||
#define FontIcon_WindowRestore 0xf2d2
|
||||
#define FontIcon_WindowClose 0xf2d4
|
||||
#define FontIcon_DownDir 0xe812
|
||||
#define FontIcon_UpDir 0xe813
|
||||
#define FontIcon_LeftDir 0xe814
|
||||
#define FontIcon_RightDir 0xe815
|
||||
#define FontIcon_TextAlignLeft 0xe816
|
||||
#define FontIcon_TextAlignCenter 0xe817
|
||||
#define FontIcon_TextAlignRight 0xe818
|
||||
#define FontIcon_DocumentInverted 0xf15b
|
||||
#define FontIcon_DocumentInvertedText 0xf15c
|
||||
#define FontIcon_DocumentFileImage 0xf1c5
|
||||
#define FontIcon_DocumentFileAudio 0xf1c7
|
||||
#define FontIcon_DocumentFileCode 0xf1c9
|
||||
|
||||
struct glyph
|
||||
{
|
||||
|
@ -72,7 +77,7 @@ struct glyph
|
|||
r32 Advance;
|
||||
};
|
||||
|
||||
#define DEFAULT_GLYPH_ATLAS_DIM 1024
|
||||
#define DEFAULT_GLYPH_ATLAS_DIM 1024*4
|
||||
#define MAX_GLYPH_SIZE 64
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
|
|
|
@ -24,6 +24,17 @@ struct platform_file_handle
|
|||
b32 IsValid;
|
||||
};
|
||||
|
||||
struct platform_file_info
|
||||
{
|
||||
string Name;
|
||||
b32 IsDirectory;
|
||||
};
|
||||
|
||||
struct platform_file_iter
|
||||
{
|
||||
u64 U64[1024];
|
||||
};
|
||||
|
||||
enum platform_cursor
|
||||
{
|
||||
PlatformCursor_Arrow,
|
||||
|
@ -77,7 +88,7 @@ enum platform_key
|
|||
|
||||
Key_Left, Key_Right, Key_Up, Key_Down,
|
||||
|
||||
Key_Space,
|
||||
Key_Space, Key_Return,
|
||||
|
||||
Key_PageUp, Key_PageDown,
|
||||
Key_Home, Key_End,
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
@table(Name, NameLower, NameCaps, Type, Arguments) platform_functions:
|
||||
{
|
||||
{ Reserve reserve RESERVE `void *` `u64 Size` }
|
||||
{ Release release RELEASE `void` `void *Pointer` }
|
||||
{ Commit commit COMMIT `void` `void *Pointer, u64 Size` }
|
||||
{ Decommit decommit DECOMMIT `void` `void *Pointer, u64 Size` }
|
||||
{ OpenFile open_file OPEN_FILE `platform_file_handle` `string Path, platform_access_flags FileAccess` }
|
||||
{ CloseFile close_file CLOSE_FILE `void` `platform_file_handle Handle` }
|
||||
{ ReadFile read_file READ_FILE `void` `platform_file_handle Handle, void *Dest, u64 Offset, u64 Size` }
|
||||
{ WriteFile write_file WRITE_FILE `void` `platform_file_handle Handle, void *Source, u64 Offset, u64 Size` }
|
||||
{ GetFileSize get_file_size GET_FILE_SIZE `u64` `platform_file_handle Handle` }
|
||||
{ SetCursor set_cursor SET_CURSOR `void` `platform_cursor Cursor` }
|
||||
{ ToggleFullscreen toggle_fullscreen TOGGLE_FULLSCREEN `void` `void` }
|
||||
{ ShowMessage show_message SHOW_MESSAGE `void` `string Message, platform_message_type Type` }
|
||||
{ Reserve reserve RESERVE `void *` `u64 Size` }
|
||||
{ Release release RELEASE `void` `void *Pointer` }
|
||||
{ Commit commit COMMIT `void` `void *Pointer, u64 Size` }
|
||||
{ Decommit decommit DECOMMIT `void` `void *Pointer, u64 Size` }
|
||||
{ OpenFile open_file OPEN_FILE `platform_file_handle` `string Path, platform_access_flags FileAccess` }
|
||||
{ CloseFile close_file CLOSE_FILE `void` `platform_file_handle Handle` }
|
||||
{ ReadFile read_file READ_FILE `void` `platform_file_handle Handle, void *Dest, u64 Offset, u64 Size` }
|
||||
{ WriteFile write_file WRITE_FILE `void` `platform_file_handle Handle, void *Source, u64 Offset, u64 Size` }
|
||||
{ GetFileSize get_file_size GET_FILE_SIZE `u64` `platform_file_handle Handle` }
|
||||
{ SetCursor set_cursor SET_CURSOR `void` `platform_cursor Cursor` }
|
||||
{ ToggleFullscreen toggle_fullscreen TOGGLE_FULLSCREEN `void` `void` }
|
||||
{ ShowMessage show_message SHOW_MESSAGE `void` `string Message, platform_message_type Type` }
|
||||
{ BeginFileIter begin_file_iter BEGIN_FILE_ITER `platform_file_iter *` `memory_arena *Arena, string Path` }
|
||||
{ AdvanceFileIter advance_file_iter ADVANCE_FILE_ITER `b32` `memory_arena *Arena, platform_file_iter *Iter, platform_file_info *OutInfo` }
|
||||
{ EndFileIter end_file_iter END_FILE_ITER `void` `platform_file_iter *Iter` }
|
||||
}
|
||||
|
||||
@table_gen
|
||||
|
|
|
@ -1,63 +1,592 @@
|
|||
////////////////////////////////
|
||||
//~ sixten: Scene Message Functions
|
||||
static void S_PushMessage(memory_arena *Arena, scene_message_list *Messages, scene_node *Node, scene_message_type Type, string String)
|
||||
#include "generated/vn_scene.meta.h"
|
||||
#include "generated/vn_scene.meta.c"
|
||||
|
||||
static void S_EmitByte(scene_compiler *Compiler, u8 Byte)
|
||||
{
|
||||
scene_message *Message = PushStruct(Arena, scene_message);
|
||||
Message->Type = Type;
|
||||
Message->Node = Node;
|
||||
Message->String = String;
|
||||
QueuePush(Messages->First, Messages->Last, Message);
|
||||
Messages->Count += 1;
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ sixten: Scene Node Functions
|
||||
static scene_node *S_SceneFromText(memory_arena *Arena, string Filename, string Text)
|
||||
static u64 S_MakeConstant(scene_compiler *Compiler, scene_value Value)
|
||||
{
|
||||
tokenize_result TokenizeResult = T_TokenizeFromText(Arena, Filename, Text, TokenGroup_Comment|TokenGroup_Whitespace);
|
||||
scene_parse_result ParseResult = S_ParseFromTokens(Arena, Filename, Text, TokenizeResult.Tokens);
|
||||
scene_node *Result = ParseResult.Root;
|
||||
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;
|
||||
return(Result);
|
||||
}
|
||||
////////////////////////////////
|
||||
//~ sixten: Tokens -> Syntax Tree
|
||||
static scene_parse_result S_ParseFromTokens(memory_arena *Arena, string Filename, string Text, token_array Tokens)
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
S_ParseError(Compiler, "Expected top-level declaration (proc or var)..");
|
||||
}
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
S_SetEmissionTarget(Compiler, T_StringFromToken(Compiler->Text, NameToken));
|
||||
|
||||
for(;Compiler->At < Compiler->TokensEnd;)
|
||||
{
|
||||
if(Compiler->At[0].Kind == TokenKind_CurlyClose)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
S_ParseError(Compiler, "Unknown tag.");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
//scene_node *Root = {};
|
||||
|
||||
//- sixten: setup parse context
|
||||
scene_parse_context Context = {};
|
||||
u8 *ChunkBegin = Chunk->Data;
|
||||
u8 *ChunkEnd = ChunkBegin + Chunk->Count;
|
||||
for(u8 *Data = ChunkBegin; Data < ChunkEnd; Data += 1)
|
||||
{
|
||||
Context.TokensStart = Tokens.Tokens;
|
||||
Context.TokensEnd = Context.TokensStart + Tokens.Count;
|
||||
Context.Token = Context.TokensStart;
|
||||
}
|
||||
|
||||
//- sixten: parse top-level
|
||||
for(;Context.Token < Context.TokensEnd;)
|
||||
{
|
||||
string TokenString = PushString(Scratch.Arena, T_StringFromToken(Text, *Context.Token));
|
||||
|
||||
if(T_TokenMatches(*Context.Token, TokenFlag_Identifier, Text, StrLit("proc")))
|
||||
switch(*Data)
|
||||
{
|
||||
Context.Token += 1;
|
||||
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;
|
||||
|
||||
goto TokenConsumed;
|
||||
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;
|
||||
}
|
||||
//- sixten: token was not consumed, something has gone wrong
|
||||
{
|
||||
Context.Token += 1;
|
||||
}
|
||||
TokenConsumed:;
|
||||
}
|
||||
|
||||
string Result = JoinStringList(&List, Arena);
|
||||
|
||||
ReleaseScratch(Scratch);
|
||||
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;
|
||||
|
||||
scene_parse_result Result =
|
||||
//- sixten: find required bytes
|
||||
s64 RequiredBytes = 0;
|
||||
scene_annotated_bytecode_chunk *NextChunk = 0;
|
||||
{
|
||||
0
|
||||
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;
|
||||
};
|
||||
|
||||
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);
|
||||
return(Result);
|
||||
}
|
273
code/vn_scene.h
273
code/vn_scene.h
|
@ -1,97 +1,240 @@
|
|||
/* date = July 9th 2023 11:08 am */
|
||||
/* date = July 30th 2023 7:45 pm */
|
||||
|
||||
#ifndef VN_SCENE_H
|
||||
#define VN_SCENE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ sixten: Scene Node Types
|
||||
enum scene_node_kind
|
||||
{
|
||||
S_NodeKind_Invalid,
|
||||
S_NodeKind_File,
|
||||
S_NodeKind_Proc,
|
||||
S_NodeKind_Text,
|
||||
S_NodeKind_Branch,
|
||||
S_NodeKind_Count,
|
||||
};
|
||||
|
||||
struct scene_node
|
||||
{
|
||||
scene_node *Next;
|
||||
scene_node *Prev;
|
||||
scene_node *First;
|
||||
scene_node *Last;
|
||||
scene_node *Parent;
|
||||
|
||||
scene_node *FirstTag;
|
||||
scene_node *LastTag;
|
||||
|
||||
scene_node_kind Kind;
|
||||
string String;
|
||||
|
||||
u64 SourceOffset;
|
||||
};
|
||||
// sixten(IMPORTANT): The arena that the scene is compiled on
|
||||
// is assumed to be the same it runs on, i.e. the interpreter relies
|
||||
// on the memory addresses being the same during compilation and
|
||||
// runtime.
|
||||
// We also assume that the original text and tokenization remains in
|
||||
// memory, for the duration of the scene.
|
||||
|
||||
////////////////////////////////
|
||||
//~ sixten: Scene Messages
|
||||
enum scene_message_type
|
||||
//~ sixten: Scene Compilation Types
|
||||
typedef u64 scene_line_entry_flag;
|
||||
enum
|
||||
{
|
||||
S_MessageType_Invalid,
|
||||
S_MessageType_Note,
|
||||
S_MessageType_Warning,
|
||||
S_MessageType_Error,
|
||||
S_LineEntryFlag_NoClear = (1<<0),
|
||||
};
|
||||
|
||||
struct scene_message
|
||||
enum scene_opcode
|
||||
{
|
||||
scene_message_type Type;
|
||||
scene_message *Next;
|
||||
scene_node *Node;
|
||||
string String;
|
||||
S_Op_Invalid = 0,
|
||||
|
||||
S_Op_Constant,
|
||||
|
||||
S_Op_Nil,
|
||||
S_Op_True,
|
||||
S_Op_False,
|
||||
|
||||
S_Op_Add,
|
||||
S_Op_Subtract,
|
||||
S_Op_Multiply,
|
||||
S_Op_Divide,
|
||||
|
||||
S_Op_Equal,
|
||||
S_Op_Greater,
|
||||
S_Op_Less,
|
||||
|
||||
S_Op_Negate,
|
||||
S_Op_Not,
|
||||
|
||||
S_Op_DefineGlobal,
|
||||
S_Op_GetGlobal,
|
||||
S_Op_SetGlobal,
|
||||
|
||||
S_Op_AwaitInput,
|
||||
|
||||
S_Op_LineEntry = 0x80, // sixten(NOTE): All opcoodes above are reserved.
|
||||
};
|
||||
|
||||
struct scene_message_list
|
||||
struct scene_bytecode_chunk
|
||||
{
|
||||
scene_message *First;
|
||||
scene_message *Last;
|
||||
scene_bytecode_chunk *Next;
|
||||
s64 Count;
|
||||
u8 Data[4096];
|
||||
};
|
||||
|
||||
struct scene_annotated_bytecode_chunk
|
||||
{
|
||||
scene_annotated_bytecode_chunk *Next;
|
||||
string Name;
|
||||
s64 Count;
|
||||
u8 Data[4096];
|
||||
};
|
||||
|
||||
struct scene_annotated_bytecode_bucket
|
||||
{
|
||||
scene_annotated_bytecode_chunk *First;
|
||||
scene_annotated_bytecode_chunk *Last;
|
||||
s64 Count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ sixten: Text -> Tokens
|
||||
struct scene_tokenize_result
|
||||
enum scene_value_kind
|
||||
{
|
||||
token_array Tokens;
|
||||
scene_message_list Messages;
|
||||
S_ValueKind_Number,
|
||||
S_ValueKind_Boolean,
|
||||
S_ValueKind_Pointer,
|
||||
};
|
||||
|
||||
struct scene_parse_context
|
||||
struct scene_value
|
||||
{
|
||||
token *TokensStart;
|
||||
scene_value_kind Kind;
|
||||
union
|
||||
{
|
||||
r64 Number;
|
||||
b32 Boolean;
|
||||
u64 Pointer;
|
||||
};
|
||||
};
|
||||
|
||||
struct scene_value_chunk
|
||||
{
|
||||
scene_value_chunk *Next;
|
||||
s64 Count;
|
||||
scene_value Values[512];
|
||||
};
|
||||
|
||||
enum scene_precedence
|
||||
{
|
||||
S_Precedence_None,
|
||||
S_Precedence_Assignment,
|
||||
S_Precedence_Or,
|
||||
S_Precedence_And,
|
||||
S_Precedence_Equality,
|
||||
S_Precedence_Comparison,
|
||||
S_Precedence_Term,
|
||||
S_Precedence_Factor,
|
||||
S_Precedence_Unary,
|
||||
S_Precedence_Call,
|
||||
S_Precedence_Primary,
|
||||
};
|
||||
|
||||
typedef void scene_parse_function(struct scene_compiler *Compiler, b32 CanAssign);
|
||||
|
||||
struct scene_parse_rule
|
||||
{
|
||||
scene_parse_function *PrefixRule;
|
||||
scene_parse_function *InfixRule;
|
||||
scene_precedence Precedence;
|
||||
};
|
||||
|
||||
struct scene_compiler
|
||||
{
|
||||
memory_arena *Arena;
|
||||
|
||||
string Text;
|
||||
token *TokensBegin;
|
||||
token *TokensEnd;
|
||||
token *Token;
|
||||
token *At;
|
||||
|
||||
scene_annotated_bytecode_bucket GlobalScope;
|
||||
scene_annotated_bytecode_bucket ProcBuckets[32];
|
||||
|
||||
scene_annotated_bytecode_bucket *CurrentBucket;
|
||||
string CurrentName;
|
||||
|
||||
scene_value_chunk *FirstValueChunk;
|
||||
scene_value_chunk *LastValueChunk;
|
||||
s64 ValueCount;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ sixten: Tokens -> Syntax Tree
|
||||
struct scene_parse_result
|
||||
//~ sixten: Compiled Scene Types
|
||||
struct scene_proc
|
||||
{
|
||||
scene_node *Root;
|
||||
scene_message_list Messages;
|
||||
// sixten: scene data
|
||||
string Name;
|
||||
u8 *Data;
|
||||
s64 Count;
|
||||
|
||||
// sixten: hash link
|
||||
scene_proc *Next;
|
||||
};
|
||||
|
||||
struct scene_proc_bucket
|
||||
{
|
||||
scene_proc *First;
|
||||
scene_proc *Last;
|
||||
};
|
||||
|
||||
struct compiled_scene
|
||||
{
|
||||
scene_proc_bucket Buckets[16];
|
||||
scene_value *Values;
|
||||
s64 ValueCount;
|
||||
string Source;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ sixten: Scene Message Functions
|
||||
static void S_PushMessage(memory_arena *Arena, scene_message_list *Messages, scene_node *Node, scene_message_type Type, string String);;
|
||||
//~ sixten: Scene Compiler Functions
|
||||
//- sixten: value helpers
|
||||
inline scene_value S_MakeNumber(r64 Value)
|
||||
{
|
||||
scene_value Result;
|
||||
Result.Kind = S_ValueKind_Number;
|
||||
Result.Number = Value;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline scene_value S_MakeBoolean(b32 Value)
|
||||
{
|
||||
scene_value Result;
|
||||
Result.Kind = S_ValueKind_Boolean;
|
||||
Result.Boolean = Value;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline scene_value S_MakePointer(void *Value)
|
||||
{
|
||||
scene_value Result;
|
||||
Result.Kind = S_ValueKind_Pointer;
|
||||
Result.Pointer = PointerToU64(Value);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
//- sixten: error messaging
|
||||
static void S_ParseError(scene_compiler *Compiler, char *Message) { InvalidCodepath; }
|
||||
|
||||
//- sixten: bytecode helpers
|
||||
static void S_EmitByte(scene_compiler *Compiler, u8 Byte);
|
||||
static u64 S_MakeConstant(scene_compiler *Compiler, scene_value Value);
|
||||
static void S_EmitVariableLength(scene_compiler *Compiler, u64 Value);
|
||||
static u64 S_ReadVariableLength(u8 **BytePtr);
|
||||
static void S_EmitConstant(scene_compiler *Compiler, scene_value Value);
|
||||
static void S_SetEmissionTarget(scene_compiler *Compiler, string Target);
|
||||
static scene_annotated_bytecode_chunk *S_FindBytecodeChunkByName(scene_compiler *Compiler, string Name);
|
||||
|
||||
//- sixten: parsing helpers
|
||||
static void S_AdvanceCompiler(scene_compiler *Compiler);
|
||||
static scene_parse_rule S_ParseRuleFromToken(scene_compiler *Compiler, token Token);
|
||||
static b32 S_MatchToken(scene_compiler *Compiler, token Token, token_kind Kind);
|
||||
static token S_ConsumeToken(scene_compiler *Compiler, token_kind Kind, char *Message);
|
||||
|
||||
//- sixten: parsing
|
||||
static void S_ParseTopLevelDeclaration(scene_compiler *Compiler);
|
||||
static void S_ParseProcedure(scene_compiler *Compiler);
|
||||
static void S_ParseDeclaration(scene_compiler *Compiler);
|
||||
static void S_ParseVariableDeclaration(scene_compiler *Compiler);
|
||||
static void S_ParseVariable(scene_compiler *Compiler, b32 CanAssign);
|
||||
static void S_ParseNamedVariable(scene_compiler *Compiler, token *Token, b32 CanAssign);
|
||||
static void S_ParseLineEntry(scene_compiler *Compiler);
|
||||
static void S_ParseStatement(scene_compiler *Compiler);
|
||||
static void S_ParseExpression(scene_compiler *Compiler);
|
||||
static void S_ParseLiteral(scene_compiler *Compiler, b32 CanAssign);
|
||||
static void S_ParseNumber(scene_compiler *Compiler, b32 CanAssign);
|
||||
static void S_ParseGrouping(scene_compiler *Compiler, b32 CanAssign);
|
||||
static void S_ParseUnary(scene_compiler *Compiler, b32 CanAssign);
|
||||
static void S_ParseBinary(scene_compiler *Compiler, b32 CanAssign);
|
||||
static void S_ParsePrecedence(scene_compiler *Compiler, scene_precedence Precedence);
|
||||
|
||||
//- sixten: debugging
|
||||
static string S_DisassembleBytecode(scene_compiler *Compiler, scene_annotated_bytecode_chunk *Chunk, memory_arena *Arena);
|
||||
|
||||
//- sixten: api
|
||||
static compiled_scene S_ScriptFromText(memory_arena *Arena, string Text);
|
||||
|
||||
////////////////////////////////
|
||||
//~ sixten: Scene Node Functions
|
||||
static scene_node *S_PushNode(memory_arena *Arena, scene_node_kind Kind, string String);
|
||||
static scene_node *S_SceneFromText(memory_arena *Arena, string Text);
|
||||
|
||||
////////////////////////////////
|
||||
//~ sixten: Tokens -> Syntax Tree
|
||||
static scene_node *S_ParseProc(scene_parse_context *Context, string ProcName);
|
||||
static scene_parse_result S_ParseFromTokens(memory_arena *Arena, string Filename, string Text, token_array Tokens);
|
||||
|
||||
#endif //VN_SCENE_H
|
||||
|
|
|
@ -1,34 +1,35 @@
|
|||
@table(Name, NameLower, Contents) scene_ast_node_types:
|
||||
@table(Name, Operator) scene_operator_table:
|
||||
{
|
||||
{ Invalid invalid `` }
|
||||
{ BlockStatement block_statement `scene_ast_node *First; scene_ast_node *Last;` }
|
||||
{ SceneDecl scene_declaration `` }
|
||||
}
|
||||
|
||||
@table_gen_enum scene_ast_node_type:
|
||||
{
|
||||
@expand(scene_ast_node_types s) `S_AstNode_$(s.Name),`;
|
||||
`S_AstNode_Count,`:
|
||||
{ Invalid, "###" }
|
||||
{ Not, "!" }
|
||||
{ Equal, "=" }
|
||||
{ Equals, "==" }
|
||||
{ NotEquals, "!=" }
|
||||
{ GreaterThanOrEquals, ">=" }
|
||||
{ LessThanOrEquals, "<=" }
|
||||
{ Greater, ">" }
|
||||
{ Less, "<" }
|
||||
{ Add, "+" }
|
||||
{ Minus, "-" }
|
||||
{ Multiply "*" }
|
||||
{ Divide, "/" }
|
||||
}
|
||||
|
||||
@table_gen
|
||||
{
|
||||
`struct scene_ast_node;`
|
||||
}
|
||||
|
||||
@table_gen
|
||||
{
|
||||
@expand(scene_ast_node_types s) `struct scene_ast_node_$(s.NameLower) {$(s.Contents)};`
|
||||
}
|
||||
|
||||
@table_gen
|
||||
{
|
||||
`struct scene_ast_node`;
|
||||
`enum scene_operator`;
|
||||
`{`;
|
||||
`scene_ast_node_type Type;`;
|
||||
`union`;
|
||||
`{`;
|
||||
@expand(scene_ast_node_types s) `scene_ast_node_$(s.NameLower) $(s.Name)Data;`;
|
||||
`};`;
|
||||
@expand(scene_operator_table s) `S_Operator_$(s.Name),`;
|
||||
`};`;
|
||||
}
|
||||
|
||||
@table_gen
|
||||
{
|
||||
`inline scene_operator S_OperatorFromString(string String)`;
|
||||
`{`;
|
||||
`scene_operator Result = S_Operator_Invalid;`;
|
||||
`if(0) {}`;
|
||||
@expand(scene_operator_table s) `else if(AreEqual(String, StrLit("$(s.Operator)")))$(=>40) { Result = S_Operator_$(s.Name); }`;
|
||||
`return(Result);`;;
|
||||
`}`;
|
||||
}
|
|
@ -7,12 +7,6 @@ static string T_StringFromToken(string Text, token Token)
|
|||
return(Result);
|
||||
}
|
||||
|
||||
static b32 T_TokenMatches(token Token, token_flags Flags, string Text, string String)
|
||||
{
|
||||
b32 Result = (Token.Flags & Flags && AreEqual(T_StringFromToken(Text, Token), String));
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static void T_TokenChunkListPush(memory_arena *Arena, token_chunk_list *List, token Token, s64 MaxTokenCountPerNode)
|
||||
{
|
||||
token_chunk_node *Node = List->Last;
|
||||
|
@ -58,7 +52,7 @@ static void T_MessageListPush(memory_arena *Arena, tokenizer_message_list *List,
|
|||
////////////////////////////////
|
||||
//~ sixten: Text -> Token Functions
|
||||
|
||||
static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename, string Text, token_flags ExcludeFilter)
|
||||
static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Text, tokenizer_filter_function *ExcludeFilter)
|
||||
{
|
||||
temporary_memory Scratch = GetScratch(&Arena, 1);
|
||||
token_chunk_list Tokens = {};
|
||||
|
@ -70,14 +64,14 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
|
|||
//- sixten: scan string & produce tokens
|
||||
for(;Byte < TextEnd;)
|
||||
{
|
||||
token_flags TokenFlags = 0;
|
||||
token_kind TokenKind = TokenKind_None;
|
||||
u8 *TokenStart = 0;
|
||||
u8 *TokenEnd = 0;
|
||||
|
||||
//- sixten: whitespace
|
||||
if(TokenFlags == 0 && (*Byte == ' ' || *Byte == '\t' || *Byte == '\v' || *Byte == '\r'))
|
||||
if(TokenKind == TokenKind_None && (*Byte == ' ' || *Byte == '\t' || *Byte == '\v' || *Byte == '\r'))
|
||||
{
|
||||
TokenFlags = TokenFlag_Whitespace;
|
||||
TokenKind = TokenKind_Whitespace;
|
||||
TokenStart = Byte;
|
||||
TokenEnd = Byte;
|
||||
Byte += 1;
|
||||
|
@ -92,18 +86,18 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
|
|||
}
|
||||
|
||||
//- sixten: newlines
|
||||
if(TokenFlags == 0 && *Byte == '\n')
|
||||
if(TokenKind == TokenKind_None && *Byte == '\n')
|
||||
{
|
||||
TokenFlags = TokenFlag_Newline;
|
||||
TokenKind = TokenKind_Newline;
|
||||
TokenStart = Byte;
|
||||
TokenEnd = Byte + 1;
|
||||
Byte += 1;
|
||||
}
|
||||
|
||||
//- sixten: single-line comments
|
||||
if(TokenFlags == 0 && (Byte[0] == '/' && Byte[1] == '/'))
|
||||
if(TokenKind == TokenKind_None && (Byte[0] == '/' && Byte[1] == '/'))
|
||||
{
|
||||
TokenFlags = TokenFlag_Comment;
|
||||
TokenKind = TokenKind_Comment;;
|
||||
TokenStart = Byte;
|
||||
TokenEnd = Byte + 2;
|
||||
Byte += 2;
|
||||
|
@ -118,9 +112,9 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
|
|||
}
|
||||
|
||||
//- sixten: multi-line comments
|
||||
if(TokenFlags == 0 && (Byte+1 < TextEnd && Byte[0] == '/' && Byte[1] == '*'))
|
||||
if(TokenKind == TokenKind_None && (Byte+1 < TextEnd && Byte[0] == '/' && Byte[1] == '*'))
|
||||
{
|
||||
TokenFlags = TokenFlag_Comment;
|
||||
TokenKind = TokenKind_Comment;
|
||||
TokenStart = Byte;
|
||||
TokenEnd = Byte + 2;
|
||||
Byte += 2;
|
||||
|
@ -129,7 +123,7 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
|
|||
// sixten(NOTE): This could potentially be wrong. The TokenEnd += 1 statement could currently make the token include the EOF.
|
||||
if(Byte == TextEnd)
|
||||
{
|
||||
TokenFlags |= TokenFlag_BrokenComment;
|
||||
TokenKind = TokenKind_BrokenComment;
|
||||
break;
|
||||
}
|
||||
TokenEnd += 1;
|
||||
|
@ -143,12 +137,12 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
|
|||
}
|
||||
|
||||
//- sixten: identifiers
|
||||
if(TokenFlags == 0 && (('A' <= *Byte && *Byte <= 'Z') ||
|
||||
('a' <= *Byte && *Byte <= 'z') ||
|
||||
(UTF8Lengths[*Byte>>3] > 1) ||
|
||||
*Byte == '_'))
|
||||
if(TokenKind == TokenKind_None && (('A' <= *Byte && *Byte <= 'Z') ||
|
||||
('a' <= *Byte && *Byte <= 'z') ||
|
||||
(UTF8Lengths[*Byte>>3] > 1) ||
|
||||
*Byte == '_'))
|
||||
{
|
||||
TokenFlags = TokenFlag_Identifier;
|
||||
TokenKind = TokenKind_Identifier;
|
||||
TokenStart = Byte;
|
||||
TokenEnd = Byte;
|
||||
Byte += UTF8Lengths[*Byte>>3];
|
||||
|
@ -164,14 +158,28 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string String = MakeString(TokenStart, TokenEnd-TokenStart);
|
||||
if(0) {}
|
||||
else if(AreEqual(String, StrLit("and"))) { TokenKind = TokenKind_And; }
|
||||
else if(AreEqual(String, StrLit("branch"))) { TokenKind = TokenKind_Branch; }
|
||||
else if(AreEqual(String, StrLit("else"))) { TokenKind = TokenKind_Else; }
|
||||
else if(AreEqual(String, StrLit("false"))) { TokenKind = TokenKind_False; }
|
||||
else if(AreEqual(String, StrLit("for"))) { TokenKind = TokenKind_For; }
|
||||
else if(AreEqual(String, StrLit("if"))) { TokenKind = TokenKind_If; }
|
||||
else if(AreEqual(String, StrLit("jump"))) { TokenKind = TokenKind_Jump; }
|
||||
else if(AreEqual(String, StrLit("or"))) { TokenKind = TokenKind_Or; }
|
||||
else if(AreEqual(String, StrLit("proc"))) { TokenKind = TokenKind_Proc; }
|
||||
else if(AreEqual(String, StrLit("true"))) { TokenKind = TokenKind_True; }
|
||||
else if(AreEqual(String, StrLit("var"))) { TokenKind = TokenKind_Var; }
|
||||
else if(AreEqual(String, StrLit("while"))) { TokenKind = TokenKind_While; }
|
||||
}
|
||||
|
||||
//- sixten: numerics
|
||||
if(TokenFlags == 0 && (('0' <= *Byte && *Byte <= '9') ||
|
||||
*Byte == '.' ||
|
||||
((*Byte == '+' || *Byte == '-') && Byte + 1 < TextEnd && '0' <= Byte[1] && Byte[1] <= '9')))
|
||||
if(TokenKind == TokenKind_None && (('0' <= *Byte && *Byte <= '9') ||
|
||||
(*Byte == '-' && Byte + 1 < TextEnd && '0' <= Byte[1] && Byte[1] <= '9')))
|
||||
{
|
||||
TokenFlags = TokenFlag_Numeric;
|
||||
TokenKind = TokenKind_Numeric;
|
||||
TokenStart = Byte;
|
||||
TokenEnd = Byte;
|
||||
Byte += 1;
|
||||
|
@ -179,9 +187,7 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
|
|||
{
|
||||
TokenEnd += 1;
|
||||
if(Byte == TextEnd ||
|
||||
!(('A' <= *Byte && *Byte <= 'Z') ||
|
||||
('a' <= *Byte && *Byte <= 'z') ||
|
||||
('0' <= *Byte && *Byte <= '9') ||
|
||||
!(('0' <= *Byte && *Byte <= '9') ||
|
||||
*Byte == '_' || *Byte == '.'))
|
||||
{
|
||||
break;
|
||||
|
@ -190,9 +196,9 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
|
|||
}
|
||||
|
||||
//- sixten: string literals
|
||||
if(TokenFlags == 0 && *Byte == '"')
|
||||
if(TokenKind == TokenKind_None && *Byte == '"')
|
||||
{
|
||||
TokenFlags = TokenFlag_StringLiteral;
|
||||
TokenKind = TokenKind_StringLiteral;
|
||||
TokenStart = Byte;
|
||||
TokenEnd = Byte;
|
||||
Byte += 1;
|
||||
|
@ -201,7 +207,7 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
|
|||
TokenEnd += 1;
|
||||
if(Byte == TextEnd || *Byte == '\n')
|
||||
{
|
||||
TokenFlags |= TokenFlag_BrokenStringLiteral;
|
||||
TokenKind = TokenKind_BrokenStringLiteral;
|
||||
break;
|
||||
}
|
||||
if(*Byte == '"')
|
||||
|
@ -213,64 +219,82 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
|
|||
}
|
||||
}
|
||||
|
||||
//- sixten: multi-char symbols
|
||||
if(TokenFlags == 0 && (*Byte == '!' || *Byte == '%' || *Byte == '&' || *Byte == '|' ||
|
||||
*Byte == '/' || *Byte == '=' || *Byte == '?' || *Byte == '^' ||
|
||||
*Byte == '*' || *Byte == '+' || *Byte == '-' || *Byte == '$' ||
|
||||
*Byte == '<' || *Byte == '>' || *Byte == '~' || *Byte == '\''))
|
||||
//- sixten: symbols
|
||||
if(TokenKind == TokenKind_None && (*Byte == '{' || *Byte == '}' || *Byte == '(' || *Byte == ')' ||
|
||||
*Byte == ',' || *Byte == '.' || *Byte == '@' || *Byte == '#' ||
|
||||
*Byte == ';' || *Byte == '+' || *Byte == '-' || *Byte == '*' ||
|
||||
*Byte == '/'))
|
||||
{
|
||||
TokenFlags = TokenFlag_Symbol;
|
||||
TokenStart = Byte;
|
||||
TokenEnd = Byte;
|
||||
Byte += 1;
|
||||
for(;Byte <= TextEnd; Byte += 1)
|
||||
TokenEnd = Byte+1;
|
||||
|
||||
switch(*Byte)
|
||||
{
|
||||
case '{': { TokenKind = TokenKind_CurlyOpen; } break;
|
||||
case '}': { TokenKind = TokenKind_CurlyClose; } break;
|
||||
case '(': { TokenKind = TokenKind_ParenthesisOpen; } break;
|
||||
case ')': { TokenKind = TokenKind_ParenthesisClose; } break;
|
||||
case ',': { TokenKind = TokenKind_Comma; } break;
|
||||
case '.': { TokenKind = TokenKind_Dot; } break;
|
||||
case '@': { TokenKind = TokenKind_At; } break;
|
||||
case '#': { TokenKind = TokenKind_PoundSign; } break;
|
||||
case ';': { TokenKind = TokenKind_Semicolon; } break;
|
||||
case '+': { TokenKind = TokenKind_Plus; } break;
|
||||
case '-': { TokenKind = TokenKind_Minus; } break;
|
||||
case '*': { TokenKind = TokenKind_Star; } break;
|
||||
case '/': { TokenKind = TokenKind_Slash; } break;
|
||||
InvalidDefaultCase;
|
||||
}
|
||||
|
||||
Byte += 1;
|
||||
}
|
||||
if(TokenKind == TokenKind_None && (*Byte == '!' || *Byte == '=' || *Byte == '>' || *Byte == '<'))
|
||||
{
|
||||
TokenStart = Byte;
|
||||
TokenEnd = Byte+1;
|
||||
|
||||
switch(*Byte)
|
||||
{
|
||||
case '!': { TokenKind = TokenKind_Bang; } break;
|
||||
case '=': { TokenKind = TokenKind_Equal; } break;
|
||||
case '>': { TokenKind = TokenKind_Greater; } break;
|
||||
case '<': { TokenKind = TokenKind_Less; } break;
|
||||
InvalidDefaultCase;
|
||||
}
|
||||
|
||||
Byte += 1;
|
||||
|
||||
if(Byte < TextEnd && (*Byte == '='))
|
||||
{
|
||||
TokenKind = (token_kind)(TokenKind + 1);
|
||||
TokenEnd += 1;
|
||||
if(Byte == TextEnd ||
|
||||
!(*Byte == '!' || *Byte == '%' || *Byte == '&' || *Byte == '|' ||
|
||||
*Byte == '/' || *Byte == '=' || *Byte == '?' || *Byte == '^' ||
|
||||
*Byte == '*' || *Byte == '+' || *Byte == '-' || *Byte == '$' ||
|
||||
*Byte == '<' || *Byte == '>' || *Byte == '~' || *Byte == '\''))
|
||||
{
|
||||
break;
|
||||
}
|
||||
Byte += 1;
|
||||
}
|
||||
}
|
||||
|
||||
//- sixten: single-char symbols
|
||||
if(TokenFlags == 0 && (*Byte == '{' || *Byte == '}' || *Byte == '(' || *Byte == ')' ||
|
||||
*Byte == '[' || *Byte == ']' || *Byte == ',' || *Byte == ';' ||
|
||||
*Byte == ':' || *Byte == '@' || *Byte == '#'))
|
||||
//- sixten: bad character
|
||||
if(TokenKind == TokenKind_None)
|
||||
{
|
||||
TokenFlags = TokenFlag_Reserved;
|
||||
TokenKind = TokenKind_BadCharacter;
|
||||
TokenStart = Byte;
|
||||
TokenEnd = Byte + 1;
|
||||
Byte += 1;
|
||||
}
|
||||
|
||||
//- sixten: bad character
|
||||
if(TokenFlags == 0)
|
||||
{
|
||||
TokenFlags = TokenFlag_BadCharacter;
|
||||
TokenStart = Byte;
|
||||
TokenStart = Byte + 1;
|
||||
Byte += 1;
|
||||
}
|
||||
|
||||
//- sixten: push token
|
||||
if(TokenFlags != 0 && !(TokenFlags & ExcludeFilter) && TokenStart != 0 && TokenEnd > TokenStart)
|
||||
if(TokenKind != 0 && (!ExcludeFilter || (ExcludeFilter && !ExcludeFilter(TokenKind))) && TokenStart != 0 && TokenEnd > TokenStart)
|
||||
{
|
||||
token Token = {TokenFlags, {TokenStart - TextStart, TokenEnd - TextStart}};
|
||||
token Token = {TokenKind, {TokenStart - TextStart, TokenEnd - TextStart}};
|
||||
T_TokenChunkListPush(Scratch.Arena, &Tokens, Token, 4096);
|
||||
}
|
||||
|
||||
if(TokenFlags & TokenFlag_BrokenComment)
|
||||
if(TokenKind == TokenKind_BrokenComment)
|
||||
{
|
||||
string Message = StrLit("broken comment");
|
||||
T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message);
|
||||
}
|
||||
|
||||
if(TokenFlags & TokenFlag_BrokenStringLiteral)
|
||||
if(TokenKind == TokenKind_BrokenStringLiteral)
|
||||
{
|
||||
string Message = StrLit("broken string literal");
|
||||
T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message);
|
||||
|
|
|
@ -5,44 +5,85 @@
|
|||
|
||||
////////////////////////////////
|
||||
//~ sixten: Token Types
|
||||
typedef u32 token_flags;
|
||||
enum
|
||||
enum token_kind
|
||||
{
|
||||
TokenFlag_Identifier = (1<<0),
|
||||
TokenFlag_Numeric = (1<<1),
|
||||
TokenFlag_StringLiteral = (1<<2),
|
||||
TokenFlag_Symbol = (1<<3),
|
||||
TokenFlag_Reserved = (1<<4),
|
||||
TokenFlag_Comment = (1<<5),
|
||||
TokenFlag_Whitespace = (1<<6),
|
||||
TokenFlag_Newline = (1<<7),
|
||||
TokenKind_None,
|
||||
|
||||
TokenFlag_BrokenComment = (1<<8),
|
||||
TokenFlag_BrokenStringLiteral = (1<<9),
|
||||
TokenFlag_BadCharacter = (1<<10),
|
||||
// sixten: labels
|
||||
TokenKind_Identifier,
|
||||
TokenKind_Numeric,
|
||||
TokenKind_StringLiteral,
|
||||
|
||||
// sixten: symbols
|
||||
TokenKind_SymbolsBegin,
|
||||
// sixten: (single char)
|
||||
TokenKind_CurlyOpen,
|
||||
TokenKind_CurlyClose,
|
||||
TokenKind_ParenthesisOpen,
|
||||
TokenKind_ParenthesisClose,
|
||||
TokenKind_Comma,
|
||||
TokenKind_Dot,
|
||||
TokenKind_At,
|
||||
TokenKind_PoundSign,
|
||||
TokenKind_Semicolon,
|
||||
TokenKind_Plus,
|
||||
TokenKind_Minus,
|
||||
TokenKind_Star,
|
||||
TokenKind_Slash,
|
||||
// sixten: (one or two chars)
|
||||
TokenKind_Bang,
|
||||
TokenKind_BangEqual,
|
||||
TokenKind_Equal,
|
||||
TokenKind_EqualEqual,
|
||||
TokenKind_Greater,
|
||||
TokenKind_GreaterEqual,
|
||||
TokenKind_Less,
|
||||
TokenKind_LessEqual,
|
||||
TokenKind_SymbolsEnd,
|
||||
|
||||
// sixten: keywords
|
||||
TokenKind_KeywordsBegin,
|
||||
TokenKind_And,
|
||||
TokenKind_Branch,
|
||||
TokenKind_Else,
|
||||
TokenKind_False,
|
||||
TokenKind_For,
|
||||
TokenKind_If,
|
||||
TokenKind_Jump,
|
||||
TokenKind_Or,
|
||||
TokenKind_Proc,
|
||||
TokenKind_True,
|
||||
TokenKind_Var,
|
||||
TokenKind_While,
|
||||
TokenKind_KeywordsEnd,
|
||||
|
||||
// sixten: whitespace
|
||||
TokenKind_Whitespace,
|
||||
TokenKind_Newline,
|
||||
TokenKind_Comment,
|
||||
|
||||
// sixten: invalid kinds
|
||||
TokenKind_BrokenComment,
|
||||
TokenKind_BrokenStringLiteral,
|
||||
TokenKind_BadCharacter,
|
||||
};
|
||||
|
||||
typedef u32 token_group;
|
||||
enum
|
||||
{
|
||||
TokenGroup_Comment = TokenFlag_Comment,
|
||||
TokenGroup_Whitespace = (TokenFlag_Whitespace |
|
||||
TokenFlag_Newline),
|
||||
TokenGroup_Irregular = (TokenGroup_Comment |
|
||||
TokenGroup_Whitespace),
|
||||
TokenGroup_Regular = ~TokenGroup_Irregular,
|
||||
TokenGroup_Label = (TokenFlag_Identifier |
|
||||
TokenFlag_Numeric |
|
||||
TokenFlag_StringLiteral |
|
||||
TokenFlag_Symbol),
|
||||
TokenGroup_Error = (TokenFlag_BrokenComment |
|
||||
TokenFlag_BrokenStringLiteral |
|
||||
TokenFlag_BadCharacter),
|
||||
};
|
||||
typedef b32 tokenizer_filter_function(token_kind Kind);
|
||||
|
||||
inline b32 T_IsComment(token_kind Kind) { return(Kind == TokenKind_Comment); }
|
||||
inline b32 T_IsWhitespace(token_kind Kind) { return(Kind == TokenKind_Whitespace ||
|
||||
Kind == TokenKind_Newline); }
|
||||
inline b32 T_IsIrregular(token_kind Kind) { return(T_IsComment(Kind) ||
|
||||
T_IsWhitespace(Kind)); }
|
||||
inline b32 T_IsRegular(token_kind Kind) { return(!T_IsIrregular(Kind)); }
|
||||
inline b32 T_IsInvalid(token_kind Kind) { return(Kind == TokenKind_None ||
|
||||
Kind == TokenKind_BrokenComment ||
|
||||
Kind == TokenKind_BrokenStringLiteral ||
|
||||
Kind == TokenKind_BadCharacter); }
|
||||
|
||||
struct token
|
||||
{
|
||||
token_flags Flags;
|
||||
token_kind Kind;
|
||||
range1_s64 Range;
|
||||
};
|
||||
|
||||
|
@ -103,7 +144,6 @@ struct tokenize_result
|
|||
////////////////////////////////
|
||||
//~ sixten: Token Type Functions
|
||||
static string T_StringFromToken(string Text, token Token);
|
||||
static b32 T_TokenMatches(token Token, token_flags Flags, string Text, string String);
|
||||
static void T_TokenChunkListPush(memory_arena *Arena, token_chunk_list *List, token Token, s64 MaxTokenCountPerNode);
|
||||
static token_array T_TokenArrayFromChunkList(memory_arena *Arena, token_chunk_list *List);
|
||||
|
||||
|
@ -113,6 +153,6 @@ static void T_MessageListPush(memory_arena *Arena, tokenizer_message_list *List,
|
|||
|
||||
////////////////////////////////
|
||||
//~ sixten: Text -> Token Functions
|
||||
static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename, string Text, token_flags ExcludeFilter = 0);
|
||||
static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Text, tokenizer_filter_function *ExcludeFilter = 0);
|
||||
|
||||
#endif //VN_TOKENIZER_H
|
||||
|
|
|
@ -16,6 +16,11 @@ static workspace *Workspace_GetState(void)
|
|||
return(ThreadLocal_Workspace);
|
||||
}
|
||||
|
||||
static memory_arena *Workspace_FrameArena(void)
|
||||
{
|
||||
return(ThreadLocal_Workspace->FrameArena);
|
||||
}
|
||||
|
||||
//- sixten: Commands
|
||||
static void Workspace_IssueCommand(workspace_command_sig *Sig, u64 Argument = 0)
|
||||
{
|
||||
|
@ -225,14 +230,9 @@ static void Workspace_BuildToolbar()
|
|||
Workspace_CreateNewView(Workspace_View_Startup, CurrentPanel);
|
||||
Workspace->Menu = ToolbarMenu_None;
|
||||
}
|
||||
if(Workspace_BuildMenuItem(FontIcon_None, "Editor", "").Clicked)
|
||||
if(Workspace_BuildMenuItem(FontIcon_Pencil, "Script Editor", "Ctrl + O").Clicked)
|
||||
{
|
||||
Workspace_CreateNewView(Workspace_View_Editor, CurrentPanel);
|
||||
Workspace->Menu = ToolbarMenu_None;
|
||||
}
|
||||
if(Workspace_BuildMenuItem(FontIcon_None, "Command Palette", "").Clicked)
|
||||
{
|
||||
Workspace_CreateNewView(Workspace_View_CommandPalette, CurrentPanel);
|
||||
Workspace_CreateNewView(Workspace_View_TextEditor, CurrentPanel);
|
||||
Workspace->Menu = ToolbarMenu_None;
|
||||
}
|
||||
if(Workspace_BuildMenuItem(FontIcon_Wrench, "Settings", "").Clicked)
|
||||
|
@ -755,6 +755,7 @@ static void Workspace_Init(workspace *Workspace)
|
|||
{
|
||||
Workspace_SetState(Workspace);
|
||||
|
||||
Workspace->FrameArena = ArenaAllocate(Gigabytes(1));
|
||||
Workspace->CommandArena = ArenaAllocate(Gigabytes(1));
|
||||
Workspace->PanelArena = ArenaAllocate(Gigabytes(1));
|
||||
|
||||
|
@ -764,7 +765,6 @@ static void Workspace_Init(workspace *Workspace)
|
|||
{
|
||||
Workspace_CreateNewView(Workspace_View_Startup, Workspace->RootPanel);
|
||||
}
|
||||
Workspace_CreateNewView(Workspace_View_TextEditor, Workspace->RootPanel);
|
||||
|
||||
// sixten: Setup keybinds
|
||||
{
|
||||
|
@ -772,6 +772,8 @@ static void Workspace_Init(workspace *Workspace)
|
|||
BIND_COMMAND(Key_P, PlatformModifier_Ctrl, Workspace_Command_SplitPanelHorizontal);
|
||||
BIND_COMMAND(Key_L, PlatformModifier_Ctrl, Workspace_Command_SplitPanelVertical);
|
||||
|
||||
BIND_COMMAND(Key_O, PlatformModifier_Ctrl, Workspace_Command_OpenView, Workspace_View_TextEditor);
|
||||
|
||||
#if VN_INTERNAL
|
||||
BIND_COMMAND(Key_U, PlatformModifier_Ctrl|PlatformModifier_Shift, Workspace_Command_ToggleRenderUIDebugRects);
|
||||
#endif
|
||||
|
@ -783,6 +785,7 @@ static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCom
|
|||
vn_input *Input, glyph_atlas *GlyphAtlas)
|
||||
{
|
||||
Workspace_SetState(Workspace);
|
||||
ArenaClear(Workspace->FrameArena);
|
||||
|
||||
Workspace->Input = Input;
|
||||
Workspace->EventList = Input->EventList;
|
||||
|
|
|
@ -72,6 +72,9 @@ struct workspace
|
|||
vn_input *Input;
|
||||
platform_event_list *EventList;
|
||||
|
||||
// sixten: General Purpose Allocation
|
||||
memory_arena *FrameArena;
|
||||
|
||||
// sixten: Command Allocation
|
||||
memory_arena *CommandArena;
|
||||
workspace_command *FirstFreeCommand;
|
||||
|
@ -104,6 +107,7 @@ struct workspace
|
|||
//- sixten: State management
|
||||
static void Workspace_SetState(workspace *Workspace);
|
||||
static workspace *Workspace_GetState(void);
|
||||
static memory_arena *Workspace_FrameArena(void);
|
||||
|
||||
//- sixten: Commands
|
||||
static void Workspace_IssueCommand(workspace_command_sig *Sig, u64 Argument);
|
||||
|
|
|
@ -86,6 +86,12 @@ WORKSPACE_COMMAND(Workspace_Command_ClosePanel)
|
|||
Workspace_DeletePanel(Panel);
|
||||
}
|
||||
|
||||
WORKSPACE_COMMAND(Workspace_Command_OpenView)
|
||||
{
|
||||
workspace *Workspace = Workspace_GetState();
|
||||
Workspace_CreateNewView((workspace_view_type)Argument, Workspace->CurrentPanel);
|
||||
}
|
||||
|
||||
#if VN_INTERNAL
|
||||
WORKSPACE_COMMAND(Workspace_Command_ToggleRenderUIDebugRects)
|
||||
{
|
||||
|
|
|
@ -30,7 +30,7 @@ static void MutableStringReplaceRange(mutable_string *MutString, string ReplaceS
|
|||
ArenaPopTo(MutString->Arena, sizeof(memory_arena)+NewCount+1);
|
||||
}
|
||||
|
||||
Move(MutString->String.Data+Range.Min+ReplaceString.Count, MutString->String.Data+Range.Max, MutString->String.Count-DimOfRange(Range));
|
||||
Move(MutString->String.Data+Range.Min+ReplaceString.Count, MutString->String.Data+Range.Max, MutString->String.Count-Range.Min-DimOfRange(Range));
|
||||
Copy(MutString->String.Data+Range.Min, ReplaceString.Data, ReplaceString.Count);
|
||||
|
||||
MutString->String.Count = NewCount;
|
||||
|
@ -70,7 +70,7 @@ static workspace_text_data Workspace_TextDataFromStringChunkList(memory_arena *A
|
|||
ArenaClear(Arena);
|
||||
|
||||
//- sixten: tokenize the text
|
||||
tokenize_result TokenizeResult = T_TokenizeFromText(Arena, StrLit("*scratch*"), Text);
|
||||
tokenize_result TokenizeResult = T_TokenizeFromText(Arena, Text);
|
||||
token_array Tokens = TokenizeResult.Tokens;
|
||||
|
||||
//- sixten: gather all line ranges
|
||||
|
@ -102,6 +102,13 @@ static workspace_text_data Workspace_TextDataFromStringChunkList(memory_arena *A
|
|||
return(Result);
|
||||
}
|
||||
|
||||
static void Workspace_TextEditorApplyChanges(workspace_view_text_editor *Editor)
|
||||
{
|
||||
workspace_text_data TextData = Workspace_TextDataFromStringChunkList(Editor->ProcessingArena, Editor->Text.String);
|
||||
Editor->Tokens = TextData.Tokens;
|
||||
Editor->Lines = TextData.Lines;
|
||||
}
|
||||
|
||||
static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
|
||||
{
|
||||
temporary_memory Scratch = GetScratch();
|
||||
|
@ -114,7 +121,7 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
|
|||
v2 Offset = Box->Parent->Offset;
|
||||
|
||||
//- sixten: rendering properties
|
||||
r32 FontSize = 16.0f;
|
||||
r32 FontSize = Editor->FontSize;
|
||||
r32 LineHeight = FontSize + 4.0f;
|
||||
|
||||
//- sixten: calculate the dimensions of the glyphs
|
||||
|
@ -137,7 +144,7 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
|
|||
v2_r32 LineMarginDim = V2((LineMarginDigitsRequired)*GlyphAdvance, ParentRect.Max.y - ParentRect.Min.y);
|
||||
|
||||
//- sixten: tokenize text
|
||||
tokenize_result TokenizeResult = T_TokenizeFromText(Scratch.Arena, StrLit("nobody cares"), Editor->Text.String);
|
||||
tokenize_result TokenizeResult = T_TokenizeFromText(Scratch.Arena, Editor->Text.String);
|
||||
token_array Tokens = TokenizeResult.Tokens;
|
||||
token *TokensBegin = Tokens.Tokens;
|
||||
token *TokensEnd = TokensBegin + Tokens.Count;
|
||||
|
@ -147,7 +154,7 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
|
|||
s64 TopMostLine = Min((s64)Floor(-Offset.y / LineHeight), LineCount);
|
||||
for(s64 LinesFound = 0; LinesFound < TopMostLine && VisibleTokensBegin < TokensEnd; VisibleTokensBegin += 1)
|
||||
{
|
||||
if(VisibleTokensBegin->Flags & TokenFlag_Newline)
|
||||
if(VisibleTokensBegin->Kind == TokenKind_Newline)
|
||||
{
|
||||
LinesFound += 1;
|
||||
}
|
||||
|
@ -158,7 +165,7 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
|
|||
s64 LinesOnScreen = Min((s64)Floor(ParentDim.y / LineHeight)+1, LineCount-TopMostLine);
|
||||
for(s64 LinesFound = 0; LinesFound < LinesOnScreen && VisibleTokensEnd < TokensEnd; VisibleTokensEnd += 1)
|
||||
{
|
||||
if(VisibleTokensEnd->Flags & TokenFlag_Newline)
|
||||
if(VisibleTokensEnd->Kind == TokenKind_Newline)
|
||||
{
|
||||
LinesFound += 1;
|
||||
}
|
||||
|
@ -197,40 +204,59 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
|
|||
//- sixten: get color & font from token
|
||||
font_id Font = Font_Monospace;
|
||||
v4 Color = Color_Magenta;
|
||||
if(Token->Flags & TokenGroup_Comment) { Color = Color_Grey; Font = Font_MonospaceOblique; }
|
||||
else if(Token->Flags & TokenFlag_Reserved) { Color = Color_Grey; }
|
||||
else if(Token->Flags & TokenFlag_Symbol) { Color = ColorFromHex(0xbd2d2dff); }
|
||||
else if(Token->Flags & TokenFlag_StringLiteral) { Color = ColorFromHex(0xffa900ff); }
|
||||
else if(Token->Flags & TokenFlag_Numeric) { Color = ColorFromHex(0xffa900ff); }
|
||||
else if(Token->Flags & TokenFlag_Identifier)
|
||||
if(Token->Kind == TokenKind_Comment) { Color = Color_Grey; Font = Font_MonospaceOblique; }
|
||||
else if(Token->Kind > TokenKind_SymbolsBegin && Token->Kind < TokenKind_SymbolsEnd) { Color = Color_Grey; }
|
||||
else if(Token->Kind == TokenKind_StringLiteral) { Color = ColorFromHex(0xffa900ff); }
|
||||
else if(Token->Kind == TokenKind_Numeric) { Color = ColorFromHex(0xffa900ff); }
|
||||
else if(Token->Kind > TokenKind_KeywordsBegin && Token->Kind < TokenKind_KeywordsEnd)
|
||||
{
|
||||
//- sixten: check for keywords
|
||||
if(AreEqual(TokenString, StrLit("true")) ||
|
||||
AreEqual(TokenString, StrLit("false")))
|
||||
if(Token->Kind == TokenKind_True || Token->Kind == TokenKind_False)
|
||||
{
|
||||
Color = ColorFromHex(0xffa900ff);
|
||||
}
|
||||
else if(AreEqual(TokenString, StrLit("var")) ||
|
||||
AreEqual(TokenString, StrLit("proc")) ||
|
||||
AreEqual(TokenString, StrLit("branch")) ||
|
||||
AreEqual(TokenString, StrLit("jump")) ||
|
||||
AreEqual(TokenString, StrLit("if")))
|
||||
else
|
||||
{
|
||||
Color = ColorFromHex(0xf0c674ff);
|
||||
}
|
||||
}
|
||||
else if(Token->Kind == TokenKind_Identifier)
|
||||
{
|
||||
Color = Theme_TextColor;
|
||||
}
|
||||
|
||||
//- sixten: render & advance by token
|
||||
if(!(T_IsWhitespace(Token->Kind)))
|
||||
{
|
||||
if(Token->Kind == TokenKind_Comment)
|
||||
{
|
||||
//- sixten: advance to newline and push text
|
||||
// sixten(TODO): proper multiline comment rendering.
|
||||
u8 *TextBegin = TokenString.Data;
|
||||
u8 *TextEnd = TextBegin+TokenString.Count;
|
||||
u8 *Marker = TextBegin;
|
||||
for(u8 *Byte = TextBegin; Byte <= TextEnd; Byte += 1)
|
||||
{
|
||||
if(*Byte == '\n' || Byte == TextEnd)
|
||||
{
|
||||
PushText(Group, Atlas, Font, TokenP, FontSize, Color, MakeString(Marker, Byte-Marker));
|
||||
Marker = Byte+1;
|
||||
|
||||
if(*Byte == '\n' && Byte != TextEnd)
|
||||
{
|
||||
TokenP.x = BaseTokenP.x;
|
||||
TokenP.y += LineHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Color = Theme_TextColor;
|
||||
TokenP.x += PushText(Group, Atlas, Font, TokenP, FontSize, Color, TokenString);
|
||||
}
|
||||
}
|
||||
//- sixten: render & advance by token
|
||||
if(!(Token->Flags & TokenGroup_Whitespace))
|
||||
{
|
||||
TokenP.x += PushText(Group, Atlas, Font, TokenP, FontSize, Color, TokenString);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Token->Flags & TokenFlag_Newline)
|
||||
if(Token->Kind == TokenKind_Newline)
|
||||
{
|
||||
TokenP.x = BaseTokenP.x;
|
||||
TokenP.y += LineHeight;
|
||||
|
@ -250,8 +276,8 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
|
|||
}
|
||||
}
|
||||
|
||||
//- sixten: render cursor
|
||||
{
|
||||
//- sixten: render cursor
|
||||
s64 LineIndex = CursorTextP.Line-1;
|
||||
string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]);
|
||||
s64 ColumnIndex = CursorTextP.Column-1;
|
||||
|
@ -272,7 +298,6 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
|
|||
range1_s64 LineRange = Range1S64(Selection.Min.Line, Selection.Max.Line);
|
||||
for(s64 LineIndex = TopMostLine; LineIndex < TopMostLine + LinesOnScreen; LineIndex += 1)
|
||||
{
|
||||
r32 LineY = Box->Rect.Min.y + LineIndex*LineHeight;
|
||||
if(Contains(LineRange, LineIndex + 1))
|
||||
{
|
||||
range1_s64 ColumnRange = Lines->Ranges[LineIndex];
|
||||
|
@ -294,9 +319,10 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
|
|||
range1_s64 ColumnOffsetRange = Range1S64(UTF8OffsetFromIndex(Line, NormalizedColumnRange.Min),
|
||||
UTF8OffsetFromIndex(Line, NormalizedColumnRange.Max));
|
||||
|
||||
r32 LineY = LineIndex*LineHeight;
|
||||
v4_r32 LineHighlightColor = ColorFromHex(0x66B3CC4C);
|
||||
range2_r32 LineHighlightBox = Range2R32(V2(LineMarginDim.x+ColumnOffsetRange.Min*GlyphAdvance, LineY),
|
||||
V2(LineMarginDim.x+ColumnOffsetRange.Max*GlyphAdvance, LineY+LineHeight));
|
||||
range2_r32 LineHighlightBox = Range2R32(Box->Rect.Min+V2(LineMarginDim.x+ColumnOffsetRange.Min*GlyphAdvance, LineY),
|
||||
Box->Rect.Min+V2(LineMarginDim.x+ColumnOffsetRange.Max*GlyphAdvance, LineY+LineHeight));
|
||||
PushQuad(Group, LineHighlightBox, LineHighlightColor, LineHighlightColor, LineHighlightColor, LineHighlightColor, 4, 1.4, 0);
|
||||
}
|
||||
}
|
||||
|
@ -304,6 +330,190 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
|
|||
ReleaseScratch(Scratch);
|
||||
}
|
||||
|
||||
static b32 Workspace_BuildTextEditorListerItem(string Text, u32 Icon)
|
||||
{
|
||||
b32 Result = false;
|
||||
UI_SetNextLayoutAxis(Axis2_X);
|
||||
ui_box *Container = UI_MakeBoxF(UI_BoxFlag_DrawBorder |
|
||||
UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_Clickable |
|
||||
UI_BoxFlag_HotAnimation |
|
||||
UI_BoxFlag_ActiveAnimation|
|
||||
UI_BoxFlag_DrawDropShadow,
|
||||
"File Lister %S", Text);
|
||||
UI_Parent(Container)
|
||||
{
|
||||
UI_Width(UI_Em(2, 1)) UI_Font(Font_Icons) UI_LabelF("%U", Icon);
|
||||
UI_Width(UI_TextContent(0, 1)) UI_Label(Text);
|
||||
}
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(Container);
|
||||
if(Signal.Clicked)
|
||||
{
|
||||
Result = true;
|
||||
}
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static workspace_text_editor_lister_action Workspace_BuildTextEditorLister(workspace_view *View, workspace_view_text_editor *Editor)
|
||||
{
|
||||
workspace_text_editor_lister_action ListerAction = {};
|
||||
temporary_memory Scratch = GetScratch();
|
||||
UI_Size(UI_Percent(1, 1), UI_Percent(1, 1)) UI_Scroll(0, &Editor->ListerScroll)
|
||||
{
|
||||
UI_Height(UI_Em(2, 1))
|
||||
{
|
||||
//- sixten: filename input field
|
||||
if(Workspace_ViewIsCurrent(View))
|
||||
{
|
||||
for(platform_event *Event = UI_EventList()->First; Event != 0; Event = Event->Next)
|
||||
{
|
||||
if((Event->Type == PlatformEvent_Press || Event->Type == PlatformEvent_Text) && (Event->Codepoint != '/' && Event->Codepoint != '\\'))
|
||||
{
|
||||
text_action Action = SingleLineTextActionFromEvent(Event);
|
||||
if(IsValid(&Action))
|
||||
{
|
||||
text_op Op = TextOpFromAction(Scratch.Arena, MakeString(Editor->ListerInput, Editor->ListerInputUsed), &Editor->ListerInputEditState, &Action);
|
||||
|
||||
string Left = MakeString(Editor->ListerInput, Op.Range.Min);
|
||||
string Right = MakeString(Editor->ListerInput + Op.Range.Max, Editor->ListerInputUsed - Op.Range.Max);
|
||||
|
||||
u64 NewStringSize = Left.Count + Right.Count + Op.ReplaceString.Count;
|
||||
char *NewString = PushArray(Scratch.Arena, char, NewStringSize);
|
||||
Copy(NewString, Left.Data, Left.Count);
|
||||
Copy(NewString + Left.Count, Op.ReplaceString.Data, Op.ReplaceString.Count);
|
||||
Copy(NewString + Left.Count + Op.ReplaceString.Count, Right.Data, Right.Count);
|
||||
|
||||
Editor->ListerInputUsed = Minimum(ArrayCount(Editor->ListerInput), NewStringSize);
|
||||
Copy(Editor->ListerInput, NewString, Editor->ListerInputUsed);
|
||||
|
||||
Editor->ListerInputEditState.Cursor = Minimum(Op.NewCursor, Editor->ListerInputUsed);
|
||||
Editor->ListerInputEditState.Mark = Minimum(Op.NewMark, Editor->ListerInputUsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- sixten: build navbar
|
||||
UI_Row(UI_BoxFlag_DrawBorder)
|
||||
{
|
||||
UI_SetNextBackgroundColor(ColorFromHex(0x2D5790FF));
|
||||
UI_SetNextWidth(UI_TextContent(20, 1));
|
||||
UI_MakeBox(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawText, Editor->Path);
|
||||
|
||||
UI_SetNextWidth(UI_TextContent(15, 1));
|
||||
UI_Label(MakeString(Editor->ListerInput, Editor->ListerInputUsed));
|
||||
|
||||
UI_Padding(UI_Percent(1, 0));
|
||||
|
||||
UI_SetNextWidth(UI_TextContent(20, 1));
|
||||
if(UI_ButtonF("Open/Create").Clicked || Platform_KeyPress(UI_EventList(), Key_Return))
|
||||
{
|
||||
ListerAction.HasRequestedFile = true;
|
||||
ListerAction.Name = MakeString(Editor->ListerInput, Editor->ListerInputUsed);
|
||||
ListerAction.Path = Editor->Path;
|
||||
}
|
||||
}
|
||||
|
||||
//- sixten: display "parent directory button"
|
||||
s64 LastSlash = LastIndexOf(Editor->Path, '/');
|
||||
if(LastSlash != -1)
|
||||
{
|
||||
if(Workspace_BuildTextEditorListerItem(StrLit("Parent Directory"), FontIcon_Reply))
|
||||
{
|
||||
Editor->Path = Prefix(Editor->Path, LastSlash);
|
||||
Editor->ListerInputUsed = 0;
|
||||
}
|
||||
}
|
||||
platform_file_info FileInfo;
|
||||
platform_file_iter *FileIter;
|
||||
|
||||
string Name = MakeString(Editor->ListerInput, Editor->ListerInputUsed);
|
||||
string FullPath = PushFormat(Scratch.Arena, "%S/%S", Editor->Path, Name);
|
||||
|
||||
//- sixten: display directories
|
||||
{
|
||||
FileIter = Platform.BeginFileIter(Scratch.Arena, FullPath);
|
||||
for(;Platform.AdvanceFileIter(Scratch.Arena, FileIter, &FileInfo);)
|
||||
{
|
||||
if(FileInfo.IsDirectory)
|
||||
{
|
||||
if(Workspace_BuildTextEditorListerItem(FileInfo.Name, FontIcon_Folder))
|
||||
{
|
||||
Editor->Path = PushFormat(View->Arena, "%S/%S", Editor->Path, FileInfo.Name);
|
||||
Editor->ListerInputUsed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Platform.EndFileIter(FileIter);
|
||||
|
||||
//- sixten: display files
|
||||
{
|
||||
FileIter = Platform.BeginFileIter(Scratch.Arena, FullPath);
|
||||
for(;Platform.AdvanceFileIter(Scratch.Arena, FileIter, &FileInfo);)
|
||||
{
|
||||
if(!FileInfo.IsDirectory)
|
||||
{
|
||||
if(Workspace_BuildTextEditorListerItem(FileInfo.Name, FontIcon_Document))
|
||||
{
|
||||
ListerAction.HasRequestedFile = true;
|
||||
ListerAction.Name = PushString(View->Arena, FileInfo.Name);
|
||||
ListerAction.Path = Editor->Path;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Platform.EndFileIter(FileIter);
|
||||
}
|
||||
}
|
||||
ReleaseScratch(Scratch);
|
||||
return(ListerAction);
|
||||
}
|
||||
|
||||
static b32 Workspace_ProcessTextEditorEvent(workspace_view_text_editor *Editor, platform_event *Event)
|
||||
{
|
||||
b32 CursorHasBeenModified = false;
|
||||
temporary_memory Scratch = GetScratch();
|
||||
text_action Action = MultiLineTextActionFromEvent(Event);
|
||||
if(IsValid(&Action))
|
||||
{
|
||||
text_op Op = TextOpFromAction(Scratch.Arena, Editor->Text.String, &Editor->EditState, &Action, &Editor->Lines, Editor->LastTextPoint.Column - 1);
|
||||
|
||||
if(DimOfRange(Op.Range) != 0 || !AreEqual(StrLit(""), Op.ReplaceString))
|
||||
{
|
||||
//- sixten: append to the history
|
||||
{
|
||||
history_list *List = &Editor->History;
|
||||
|
||||
//- sixten: remove the pre-existing history if needed
|
||||
if(List->Sentinel.Prev != List->At)
|
||||
{
|
||||
// sixten(TODO): instead of just removing the links to the old memory, find some way to manage it.
|
||||
List->Sentinel.Prev->Next = List->At;
|
||||
List->Sentinel.Prev = List->At;
|
||||
}
|
||||
|
||||
range1_s64 Selection = Range1S64(Editor->EditState.Cursor, Editor->EditState.Mark);
|
||||
AppendToHistory(Editor->HistoryArena, List,
|
||||
HistoryEntry(Editor->HistoryArena, Op.ReplaceString, Op.Range),
|
||||
HistoryEntry(Editor->HistoryArena, Substring(Editor->Text.String, Op.Range), Range1S64(Op.Range.Min, Op.Range.Min+Op.ReplaceString.Count)));
|
||||
|
||||
List->At = List->Sentinel.Prev;
|
||||
}
|
||||
//- sixten: apply the text action
|
||||
MutableStringReplaceRange(&Editor->Text, Op.ReplaceString, Op.Range);
|
||||
Workspace_TextEditorApplyChanges(Editor);
|
||||
}
|
||||
|
||||
CursorHasBeenModified = true;
|
||||
Editor->EditState.Cursor = Op.NewCursor;
|
||||
Editor->EditState.Mark = Op.NewMark;
|
||||
}
|
||||
ReleaseScratch(Scratch);
|
||||
return(CursorHasBeenModified);
|
||||
}
|
||||
|
||||
static void Workspace_BuildTextEditor(workspace_view *View)
|
||||
{
|
||||
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
|
||||
|
@ -311,7 +521,7 @@ static void Workspace_BuildTextEditor(workspace_view *View)
|
|||
temporary_memory Scratch = GetScratch();
|
||||
|
||||
//- sixten: rendering properties
|
||||
r32 FontSize = 16.0f;
|
||||
r32 FontSize = Editor->FontSize = 14.0f;
|
||||
r32 LineHeight = FontSize + 4.0f;
|
||||
|
||||
//- sixten: calculate the dimensions of the glyphs
|
||||
|
@ -322,129 +532,197 @@ static void Workspace_BuildTextEditor(workspace_view *View)
|
|||
s32 LineMarginDigitsRequired = 6;
|
||||
r32 LineMarginWidth = (LineMarginDigitsRequired)*GlyphAdvance;
|
||||
|
||||
ui_box *EditorBox = 0;
|
||||
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 1));
|
||||
UI_Scroll(0, &Editor->Offset.y)
|
||||
|
||||
b32 InFileListMode = AreEqual(Editor->FileName, StrLit(""));
|
||||
if(InFileListMode)
|
||||
{
|
||||
//- sixten: find the container box for the scrollable region
|
||||
Editor->ContainerBox = UI_TopParent()->Parent->Parent;
|
||||
|
||||
UI_SetNextSize(UI_Pixels(Editor->TextDim.x, 1), UI_Pixels(Editor->TextDim.y, 1));
|
||||
EditorBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, "Workspace Text Editor %p", View);
|
||||
EditorBox->DrawCallback = Workspace_TextEditorDrawCallback;
|
||||
EditorBox->DrawCallbackData = Editor;
|
||||
//- sixten: build & handle file lister
|
||||
workspace_text_editor_lister_action Action = Workspace_BuildTextEditorLister(View, Editor);
|
||||
if(Action.HasRequestedFile)
|
||||
{
|
||||
//- sixten: try to load file
|
||||
string FullPath = PushFormat(Scratch.Arena, "%S/%S", Action.Path, Action.Name);
|
||||
platform_file_handle File = Platform.OpenFile(FullPath, PlatformAccess_Read);
|
||||
|
||||
if(File.IsValid)
|
||||
{
|
||||
s64 FileSize = Platform.GetFileSize(File);
|
||||
string ReplaceString = MakeString(PushArray(Scratch.Arena, u8, FileSize+1), FileSize);
|
||||
Platform.ReadFile(File, ReplaceString.Data, 0, ReplaceString.Count);
|
||||
|
||||
ReplaceString = RemoveAll(Scratch.Arena, ReplaceString, '\r');
|
||||
|
||||
MutableStringReplaceRange(&Editor->Text, ReplaceString, Range1S64(0, 0));
|
||||
Workspace_TextEditorApplyChanges(Editor);
|
||||
Editor->FileName = Action.Name;
|
||||
Editor->FilePath = Action.Path;
|
||||
|
||||
Platform.CloseFile(File);
|
||||
}
|
||||
else
|
||||
{
|
||||
Editor->FileName = Action.Name;
|
||||
Editor->FilePath = Action.Path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b32 CursorHasBeenModified = false;
|
||||
|
||||
if(Workspace_ViewIsCurrent(View))
|
||||
else
|
||||
{
|
||||
//- sixten: handle history
|
||||
//- sixten: build & handle the text editor
|
||||
ui_box *EditorBox = 0;
|
||||
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 1));
|
||||
UI_Scroll(0, &Editor->Offset.y)
|
||||
{
|
||||
history_list *List = &Editor->History;
|
||||
//- sixten: find the container box for the scrollable region
|
||||
Editor->ContainerBox = UI_TopParent()->Parent->Parent;
|
||||
|
||||
//- sixten: undo
|
||||
if(Platform_KeyPress(UI_EventList(), Key_Z, PlatformModifier_Ctrl))
|
||||
{
|
||||
history_node *Node = List->At;
|
||||
if(Node != &List->Sentinel)
|
||||
{
|
||||
//- sixten: get entry & apply
|
||||
history_entry Entry = Node->Backward;
|
||||
MutableStringReplaceRange(&Editor->Text, Entry.ReplaceString, Entry.Range);
|
||||
workspace_text_data TextData = Workspace_TextDataFromStringChunkList(Editor->ProcessingArena, Editor->Text.String);
|
||||
Editor->Tokens = TextData.Tokens;
|
||||
Editor->Lines = TextData.Lines;
|
||||
Editor->EditState.Cursor = Editor->EditState.Mark = Entry.Range.Min+Entry.ReplaceString.Count;
|
||||
CursorHasBeenModified = true;
|
||||
|
||||
List->At = Node->Prev;
|
||||
}
|
||||
}
|
||||
|
||||
//- sixten: redo
|
||||
if(Platform_KeyPress(UI_EventList(), Key_Y, PlatformModifier_Ctrl))
|
||||
{
|
||||
history_node *Node = List->At->Next;
|
||||
if(Node != &List->Sentinel)
|
||||
{
|
||||
//- sixten: get entry & apply
|
||||
history_entry Entry = Node->Forward;
|
||||
MutableStringReplaceRange(&Editor->Text, Entry.ReplaceString, Entry.Range);
|
||||
workspace_text_data TextData = Workspace_TextDataFromStringChunkList(Editor->ProcessingArena, Editor->Text.String);
|
||||
Editor->Tokens = TextData.Tokens;
|
||||
Editor->Lines = TextData.Lines;
|
||||
Editor->EditState.Cursor = Editor->EditState.Mark = Entry.Range.Min+Entry.ReplaceString.Count;
|
||||
CursorHasBeenModified = true;
|
||||
|
||||
List->At = Node;
|
||||
}
|
||||
}
|
||||
UI_SetNextSize(UI_Pixels(Editor->TextDim.x, 1), UI_Pixels(Editor->TextDim.y, 1));
|
||||
EditorBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, "Workspace Text Editor %p", View);
|
||||
EditorBox->DrawCallback = Workspace_TextEditorDrawCallback;
|
||||
EditorBox->DrawCallbackData = Editor;
|
||||
}
|
||||
|
||||
//- sixten: select all
|
||||
if(Platform_KeyPress(UI_EventList(), Key_A, PlatformModifier_Ctrl))
|
||||
{
|
||||
Editor->EditState.Mark = 0;
|
||||
Editor->EditState.Cursor = Editor->Text.String.Count;
|
||||
}
|
||||
b32 CursorHasBeenModified = false;
|
||||
|
||||
//- sixten: keyboard input -> text op
|
||||
for(platform_event *Event = UI_EventList()->First;
|
||||
Event != 0;
|
||||
Event = Event->Next)
|
||||
if(Workspace_ViewIsCurrent(View))
|
||||
{
|
||||
if(Event->Type == PlatformEvent_Press || Event->Type == PlatformEvent_Text)
|
||||
//- sixten: handle history
|
||||
{
|
||||
text_action Action = MultiLineTextActionFromEvent(Event);
|
||||
if(IsValid(&Action))
|
||||
history_list *List = &Editor->History;
|
||||
|
||||
//- sixten: undo
|
||||
if(Platform_KeyPress(UI_EventList(), Key_Z, PlatformModifier_Ctrl))
|
||||
{
|
||||
text_op Op = TextOpFromAction(Scratch.Arena, Editor->Text.String, &Editor->EditState, &Action, &Editor->Lines, Editor->LastTextPoint.Column - 1);
|
||||
|
||||
if(DimOfRange(Op.Range) != 0 || !AreEqual(StrLit(""), Op.ReplaceString))
|
||||
history_node *Node = List->At;
|
||||
if(Node != &List->Sentinel)
|
||||
{
|
||||
//- sixten: append to the history
|
||||
//- sixten: get entry & apply
|
||||
history_entry Entry = Node->Backward;
|
||||
MutableStringReplaceRange(&Editor->Text, Entry.ReplaceString, Entry.Range);
|
||||
Workspace_TextEditorApplyChanges(Editor);
|
||||
Editor->EditState.Cursor = Editor->EditState.Mark = Entry.Range.Min+Entry.ReplaceString.Count;
|
||||
CursorHasBeenModified = true;
|
||||
|
||||
List->At = Node->Prev;
|
||||
}
|
||||
}
|
||||
|
||||
//- sixten: redo
|
||||
if(Platform_KeyPress(UI_EventList(), Key_Y, PlatformModifier_Ctrl))
|
||||
{
|
||||
history_node *Node = List->At->Next;
|
||||
if(Node != &List->Sentinel)
|
||||
{
|
||||
//- sixten: get entry & apply
|
||||
history_entry Entry = Node->Forward;
|
||||
MutableStringReplaceRange(&Editor->Text, Entry.ReplaceString, Entry.Range);
|
||||
Workspace_TextEditorApplyChanges(Editor);
|
||||
Editor->EditState.Cursor = Editor->EditState.Mark = Entry.Range.Min+Entry.ReplaceString.Count;
|
||||
CursorHasBeenModified = true;
|
||||
|
||||
List->At = Node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- sixten: select all
|
||||
if(Platform_KeyPress(UI_EventList(), Key_A, PlatformModifier_Ctrl))
|
||||
{
|
||||
Editor->EditState.Mark = 0;
|
||||
Editor->EditState.Cursor = Editor->Text.String.Count;
|
||||
}
|
||||
|
||||
//- sixten: keyboard input -> text op
|
||||
for(platform_event *Event = UI_EventList()->First;
|
||||
Event != 0;
|
||||
Event = Event->Next)
|
||||
{
|
||||
if(Event->Type == PlatformEvent_Press || Event->Type == PlatformEvent_Text)
|
||||
{
|
||||
//- sixten: auto-indent
|
||||
s64 Indent = 0;
|
||||
if(Event->Codepoint == '\n')
|
||||
{
|
||||
string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[Editor->LastTextPoint.Line-1]);
|
||||
if(Line.Data[Line.Count-1] == '\n')
|
||||
{
|
||||
history_list *List = &Editor->History;
|
||||
|
||||
//- sixten: remove the pre-existing history if needed
|
||||
if(List->Sentinel.Prev != List->At)
|
||||
{
|
||||
// sixten(TODO): instead of just removing the links to the old memory, find some way to manage it.
|
||||
List->Sentinel.Prev->Next = List->At;
|
||||
List->Sentinel.Prev = List->At;
|
||||
}
|
||||
|
||||
range1_s64 Selection = Range1S64(Editor->EditState.Cursor, Editor->EditState.Mark);
|
||||
AppendToHistory(Editor->HistoryArena, List,
|
||||
HistoryEntry(Editor->HistoryArena, Op.ReplaceString, Op.Range),
|
||||
HistoryEntry(Editor->HistoryArena, Substring(Editor->Text.String, Op.Range), Range1S64(Op.Range.Min, Op.Range.Min+Op.ReplaceString.Count)));
|
||||
|
||||
List->At = List->Sentinel.Prev;
|
||||
Line.Count -= 1;
|
||||
}
|
||||
|
||||
for(u8 *Data = Line.Data; *Data == '\t' && Data < Line.Data+Line.Count; Data += 1)
|
||||
{
|
||||
Indent += 1;
|
||||
}
|
||||
//- sixten: apply the text action
|
||||
MutableStringReplaceRange(&Editor->Text, Op.ReplaceString, Op.Range);
|
||||
workspace_text_data TextData = Workspace_TextDataFromStringChunkList(Editor->ProcessingArena, Editor->Text.String);
|
||||
Editor->Tokens = TextData.Tokens;
|
||||
Editor->Lines = TextData.Lines;
|
||||
}
|
||||
|
||||
CursorHasBeenModified = true;
|
||||
Editor->EditState.Cursor = Op.NewCursor;
|
||||
Editor->EditState.Mark = Op.NewMark;
|
||||
if(Event->Codepoint == '{')
|
||||
{
|
||||
platform_event FakeEvent = {};
|
||||
FakeEvent.Codepoint = '}';
|
||||
FakeEvent.Type = PlatformEvent_Text;
|
||||
CursorHasBeenModified |= Workspace_ProcessTextEditorEvent(Editor, &FakeEvent);
|
||||
FakeEvent.Key = Key_Left;;
|
||||
FakeEvent.Type = PlatformEvent_Press;
|
||||
CursorHasBeenModified |= Workspace_ProcessTextEditorEvent(Editor, &FakeEvent);
|
||||
}
|
||||
|
||||
CursorHasBeenModified |= Workspace_ProcessTextEditorEvent(Editor, Event);
|
||||
|
||||
//- sixten: apply indent
|
||||
{
|
||||
platform_event FakeTab = {};
|
||||
FakeTab.Codepoint = '\t';
|
||||
FakeTab.Type = PlatformEvent_Text;
|
||||
|
||||
for(s64 IndentIndex = 0; IndentIndex < Indent; IndentIndex += 1)
|
||||
{
|
||||
CursorHasBeenModified |= Workspace_ProcessTextEditorEvent(Editor, &FakeTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(EditorBox);
|
||||
if(Signal.Dragging)
|
||||
{
|
||||
if(Signal.Pressed)
|
||||
|
||||
//- sixten: right-click dropdown
|
||||
{
|
||||
if(Editor->DropdownActive)
|
||||
{
|
||||
UI_Tooltip
|
||||
{
|
||||
UI_SetNextFixedP(Editor->DropdownP);
|
||||
UI_SetNextWidth(UI_Em(20, 1));
|
||||
UI_SetNextHeight(UI_ChildrenSum(AnimationCurve_AnimateValueDirect(1, 0.2, &Editor->DropdownTransition), 1));
|
||||
UI_SetNextCornerRadius(4);
|
||||
UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_DrawDropShadow |
|
||||
UI_BoxFlag_Clip |
|
||||
UI_BoxFlag_FloatingX |
|
||||
UI_BoxFlag_FloatingY, StrLit("Text Editor Dropdown")))
|
||||
UI_Width(UI_Percent(1, 1)) UI_Height(UI_Em(1.66, 1))
|
||||
UI_BackgroundColor(V4(0.25, 0.25, 0.25, 1))
|
||||
UI_BorderColor(V4(0.45, 0.45, 0.45, 1))
|
||||
UI_CornerRadius(2)
|
||||
{
|
||||
UI_ButtonF("Hello");
|
||||
UI_ButtonF("Line");
|
||||
UI_ButtonF("Paint");
|
||||
UI_ButtonF("Color");
|
||||
UI_ButtonF("Design");
|
||||
UI_ButtonF("Address");
|
||||
UI_ButtonF("Brightness");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(EditorBox);
|
||||
|
||||
if(Signal.Pressed || (Signal.PressedRight && (Editor->EditState.Cursor == Editor->EditState.Mark)))
|
||||
{
|
||||
//- sixten: translate mouse position to text point
|
||||
v2 MouseOffset = Signal.MouseP - EditorBox->Rect.Min - V2(LineMarginWidth, 0);
|
||||
s64 LineIndex = (s64)(MouseOffset.y / LineHeight);
|
||||
s64 LineIndex = Clamp((s64)(MouseOffset.y / LineHeight), 0, Editor->Lines.Count);
|
||||
|
||||
string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]);
|
||||
s64 ColumnOffset = (s64)(MouseOffset.x / GlyphAdvance);
|
||||
s64 ColumnIndex = UTF8IndexFromOffset(Line, ColumnOffset);
|
||||
|
@ -453,33 +731,44 @@ static void Workspace_BuildTextEditor(workspace_view *View)
|
|||
Editor->EditState.Cursor = Editor->EditState.Mark = OffsetFromTextPoint(Editor->Text.String, Editor->Lines, Point);
|
||||
}
|
||||
|
||||
//- sixten: translate mouse position to text point
|
||||
v2 MouseOffset = Signal.MouseP - EditorBox->Rect.Min - V2(LineMarginWidth, 0);
|
||||
s64 LineIndex = (s64)(MouseOffset.y / LineHeight);
|
||||
string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]);
|
||||
s64 ColumnOffset = (s64)(MouseOffset.x / GlyphAdvance);
|
||||
s64 ColumnIndex = UTF8IndexFromOffset(Line, ColumnOffset);
|
||||
|
||||
text_point Point = {LineIndex + 1, ColumnIndex + 1};
|
||||
Editor->EditState.Cursor = OffsetFromTextPoint(Editor->Text.String, Editor->Lines, Point);
|
||||
|
||||
CursorHasBeenModified = true;
|
||||
}
|
||||
|
||||
//- sixten: update eventual text point extents
|
||||
if(CursorHasBeenModified)
|
||||
{
|
||||
text_point Point = TextPointFromOffset(Editor->Text.String, Editor->EditState.Cursor);
|
||||
if(Editor->LastTextPoint.Line == Point.Line)
|
||||
if(Signal.Dragging)
|
||||
{
|
||||
Editor->LastTextPoint = Point;
|
||||
//- sixten: translate mouse position to text point
|
||||
v2 MouseOffset = Signal.MouseP - EditorBox->Rect.Min - V2(LineMarginWidth, 0);
|
||||
s64 LineIndex = Clamp((s64)(MouseOffset.y / LineHeight), 0, Editor->Lines.Count);
|
||||
string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]);
|
||||
s64 ColumnOffset = (s64)(MouseOffset.x / GlyphAdvance);
|
||||
s64 ColumnIndex = UTF8IndexFromOffset(Line, ColumnOffset);
|
||||
|
||||
text_point Point = {LineIndex + 1, ColumnIndex + 1};
|
||||
Editor->EditState.Cursor = OffsetFromTextPoint(Editor->Text.String, Editor->Lines, Point);
|
||||
|
||||
CursorHasBeenModified = true;
|
||||
|
||||
Editor->DropdownActive = false;
|
||||
}
|
||||
else
|
||||
|
||||
if(Signal.PressedRight)
|
||||
{
|
||||
Editor->LastTextPoint.Line = Point.Line;
|
||||
Editor->LastTextPoint.Column = Max(Editor->LastTextPoint.Column, Point.Column);
|
||||
Editor->DropdownActive = true;
|
||||
Editor->DropdownP = UI_MouseP();
|
||||
Editor->DropdownTransition = 0;
|
||||
}
|
||||
|
||||
//- sixten: update eventual text point extents
|
||||
if(CursorHasBeenModified)
|
||||
{
|
||||
text_point Point = TextPointFromOffset(Editor->Text.String, Editor->EditState.Cursor);
|
||||
if(Editor->LastTextPoint.Line == Point.Line)
|
||||
{
|
||||
Editor->LastTextPoint = Point;
|
||||
}
|
||||
else
|
||||
{
|
||||
Editor->LastTextPoint.Line = Point.Line;
|
||||
Editor->LastTextPoint.Column = Max(Editor->LastTextPoint.Column, Point.Column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseScratch(Scratch);
|
||||
}
|
|
@ -44,6 +44,13 @@ struct workspace_text_data
|
|||
range1_s64_array Lines;
|
||||
};
|
||||
|
||||
struct workspace_text_editor_lister_action
|
||||
{
|
||||
b32 HasRequestedFile;
|
||||
string Path;
|
||||
string Name;
|
||||
};
|
||||
|
||||
struct workspace_view_text_editor
|
||||
{
|
||||
// sixten: processed text
|
||||
|
@ -52,12 +59,17 @@ struct workspace_view_text_editor
|
|||
range1_s64_array Lines;
|
||||
|
||||
// sixten: text being edited
|
||||
string FileName;
|
||||
string FilePath;
|
||||
mutable_string Text;
|
||||
|
||||
// sixten: text editing
|
||||
text_edit_state EditState;
|
||||
text_point LastTextPoint;
|
||||
|
||||
// sixten: text rendering
|
||||
r32 FontSize;
|
||||
|
||||
// sixten: history
|
||||
memory_arena *HistoryArena;
|
||||
history_list History;
|
||||
|
@ -66,6 +78,16 @@ struct workspace_view_text_editor
|
|||
ui_box *ContainerBox;
|
||||
v2 TextDim;
|
||||
v2 Offset;
|
||||
b32 DropdownActive;
|
||||
v2 DropdownP;
|
||||
r32 DropdownTransition;
|
||||
|
||||
// sixten: file lister
|
||||
string Path;
|
||||
r32 ListerScroll;
|
||||
u8 ListerInput[256];
|
||||
s32 ListerInputUsed;
|
||||
text_edit_state ListerInputEditState;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
|
|
@ -85,6 +85,25 @@ inline string Workspace_GetViewName(workspace_view *View)
|
|||
case Workspace_View_Startup: { Result = StrLit("Welcome"); } break;
|
||||
case Workspace_View_Editor: { Result = StrLit("Editor"); } break;
|
||||
case Workspace_View_Settings: { Result = StrLit("Settings"); } break;
|
||||
case Workspace_View_TextEditor:
|
||||
{
|
||||
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
|
||||
if(AreEqual(Editor->FileName, StrLit("")))
|
||||
{
|
||||
Result = StrLit("Open File");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Editor->History.At == &Editor->History.Sentinel)
|
||||
{
|
||||
Result = PushString(Workspace_FrameArena(), Editor->FileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = PushFormat(Workspace_FrameArena(), "* %S", Editor->FileName);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
return(Result);
|
||||
|
|
Binary file not shown.
|
@ -167,6 +167,73 @@ static PLATFORM_SET_CURSOR(Win32_SetCursor)
|
|||
Global_Win32State.Cursor = Cursor;
|
||||
}
|
||||
|
||||
static PLATFORM_BEGIN_FILE_ITER(Win32_BeginFileIter)
|
||||
{
|
||||
win32_file_find_data *FileFindData = PushStruct(Arena, win32_file_find_data);
|
||||
temporary_memory Scratch = GetScratch(&Arena, 1);
|
||||
Path = PushFormat(Scratch.Arena, "%S/%S*", Global_Win32State.ContentsPath, Path);
|
||||
string16 Path16 = String16FromString8(Scratch.Arena, Path);
|
||||
FileFindData->Handle = FindFirstFileW((WCHAR *)Path16.Data, &FileFindData->FindData);
|
||||
ReleaseScratch(Scratch);
|
||||
platform_file_iter *Iter = (platform_file_iter *)FileFindData;
|
||||
return(Iter);
|
||||
}
|
||||
|
||||
static PLATFORM_ADVANCE_FILE_ITER(Win32_AdvanceFileIter)
|
||||
{
|
||||
b32 Result = false;
|
||||
win32_file_find_data *FileFindData = (win32_file_find_data *)Iter;
|
||||
WIN32_FIND_DATAW FindData = {};
|
||||
s64 InvalidCount = 0;
|
||||
for(;;)
|
||||
{
|
||||
if(FileFindData->FindFirstReturned)
|
||||
{
|
||||
Result = FindNextFileW(FileFindData->Handle, &FindData);
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = (FileFindData->Handle != 0 && FileFindData->Handle != INVALID_HANDLE_VALUE);
|
||||
FindData = FileFindData->FindData;
|
||||
FileFindData->FindFirstReturned = true;
|
||||
}
|
||||
|
||||
b32 NameIsInvalid = (FindData.cFileName[0] == '.' && (FindData.cFileName[1] == 0 || FindData.cFileName[1] == '.'));
|
||||
if(NameIsInvalid && InvalidCount < 10)
|
||||
{
|
||||
InvalidCount += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(Result != 0)
|
||||
{
|
||||
string16 Name16 = {};
|
||||
Name16.Data = (u16 *)FindData.cFileName;
|
||||
for(u16 Index = 0; Index < MAX_PATH; Index += 1)
|
||||
{
|
||||
if(FindData.cFileName[Index] == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Name16.Count += 1;
|
||||
}
|
||||
|
||||
*OutInfo = {};
|
||||
OutInfo->Name = String8FromString16(Arena, Name16);
|
||||
OutInfo->IsDirectory = FindData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static PLATFORM_END_FILE_ITER(Win32_EndFileIter)
|
||||
{
|
||||
win32_file_find_data *FileFindData = (win32_file_find_data *)Iter;
|
||||
FindClose(FileFindData->Handle);
|
||||
}
|
||||
|
||||
inline u64 Win32_GetWallClock(void)
|
||||
{
|
||||
LARGE_INTEGER Query;
|
||||
|
@ -440,6 +507,7 @@ static LRESULT Win32_WindowCallback(HWND Window, UINT Message, WPARAM WParam, LP
|
|||
else if(VKCode == VK_UP) { Key = Key_Up; }
|
||||
else if(VKCode == VK_DOWN) { Key = Key_Down; }
|
||||
else if(VKCode == VK_SPACE) { Key = Key_Space; }
|
||||
else if(VKCode == VK_RETURN) { Key = Key_Return; }
|
||||
else if(VKCode == VK_PRIOR) { Key = Key_PageUp; }
|
||||
else if(VKCode == VK_NEXT) { Key = Key_PageDown; }
|
||||
else if(VKCode == VK_HOME) { Key = Key_Home; }
|
||||
|
|
|
@ -22,6 +22,13 @@ struct win32_state
|
|||
platform_cursor Cursor;
|
||||
};
|
||||
|
||||
struct win32_file_find_data
|
||||
{
|
||||
HANDLE Handle;
|
||||
b32 FindFirstReturned;
|
||||
WIN32_FIND_DATAW FindData;
|
||||
};
|
||||
|
||||
struct win32_loaded_code
|
||||
{
|
||||
HMODULE DLL;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
proc main
|
||||
{
|
||||
"Hello!";
|
||||
"Scene test 123" #noclear;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
proc main
|
||||
{
|
||||
for(var idx = 0; idx < 10; idx = idx + 1)
|
||||
{
|
||||
print("hello, line, paint, color, design, address, brightness");
|
||||
}
|
||||
}
|
|
@ -1,31 +1,31 @@
|
|||
// This just experiments with the scripting language
|
||||
|
||||
var times = 0
|
||||
var times = 0;
|
||||
|
||||
proc "Start"
|
||||
{
|
||||
"so, I actually changed my mind."
|
||||
"the editor will not be node based"
|
||||
"I realised that it would just be slower to write dialog that way soooo..."
|
||||
"instead, I present to you the.........."
|
||||
"vn scene - scripting language"
|
||||
"so, I actually changed my mind.";
|
||||
"the editor will not be node based";
|
||||
"I realised that it would just be slower to write dialog that way soooo...";
|
||||
"instead, I present to you the..........";
|
||||
"vn scene - scripting language";
|
||||
|
||||
"btw something happens if you go through this dialog 10 times"
|
||||
"btw something happens if you go through this dialog 10 times";
|
||||
|
||||
times += 1
|
||||
times += 1;
|
||||
|
||||
branch
|
||||
{
|
||||
"Return to start"
|
||||
{
|
||||
jump "Start"
|
||||
jump "Start";
|
||||
}
|
||||
|
||||
if(times >= 10)
|
||||
{
|
||||
"SUPER EPIC SECRET"
|
||||
{
|
||||
jump "Epic Scene"
|
||||
jump "Epic Scene";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +33,9 @@ proc "Start"
|
|||
|
||||
proc "Epic Scene"
|
||||
{
|
||||
"woah... so epic"
|
||||
@s "oh, right. almost forgot to mention that you can talk as different characters."
|
||||
@s "you know... "
|
||||
wait
|
||||
@s #noclear "the usual"
|
||||
"woah... so epic";
|
||||
@s "oh, right. almost forgot to mention that you can talk as different characters.";
|
||||
@s "you know... ";
|
||||
wait;
|
||||
@s #noclear "the usual";
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
program -> declaration* EOF;
|
||||
|
||||
declaration -> proc_decl |
|
||||
var_decl |
|
||||
statement;
|
||||
|
||||
proc_decl -> "proc" IDENTIFIER block;
|
||||
var_decl -> "var" IDENTIFIER ("=" expression)? ";";
|
||||
|
||||
statement -> expression_statement |
|
||||
for_statement |
|
||||
if_statement |
|
||||
block;
|
||||
|
||||
expression_statement -> expression ";";
|
||||
for_statement -> "for" "(" (var_decl|expression_statement|";")
|
||||
expression? ";" expression? ")" statement;
|
||||
if_statement -> "if" "(" expression ")" statement
|
||||
("else" statement)?;
|
||||
block -> "{" declaration* "}";
|
||||
|
||||
expression -> assignment;
|
||||
|
||||
assignment -> (call ".")? IDENTIFIER "=" assignment |
|
||||
logic_or;
|
||||
|
||||
logic_or -> logic_and ("or" logic_and)*;
|
||||
logic_and -> equality ("and" equality)*;
|
||||
equality -> comparison (("!=" | "==") comparison)*;
|
||||
comparison -> term ((">" | ">=" < "<" | "<=") term)*;
|
||||
term -> factor (("-" | "+") factor)*;
|
||||
factor -> unary (("/" | "*") unary)*;
|
||||
|
||||
unary -> ("!" | "-") unary | call;
|
||||
call -> primary "(" arguments? ")";
|
||||
primary -> "true" | "false" | NUMBER | STRING |
|
||||
IDENTIFIER | "(" expression ")";
|
BIN
fonts/icons.ttf
BIN
fonts/icons.ttf
Binary file not shown.
Loading…
Reference in New Issue