Added scene bytecode generation & file navigation.

main
sixtenhugosson 2023-08-06 12:35:09 +02:00
parent 30e384e0a4
commit a3e2314fd0
34 changed files with 1856 additions and 499 deletions

0
brightness.txt 100644
View File

View File

@ -6,6 +6,7 @@
#include <stdint.h> #include <stdint.h>
#include <intrin.h> #include <intrin.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h>
//- sixten: Base types //- sixten: Base types
@ -72,6 +73,10 @@ typedef intptr_t smm;
#define InvalidCodepath Assert(!"Invalid codepath") #define InvalidCodepath Assert(!"Invalid codepath")
#define InvalidDefaultCase default: { Assert(!"Invalid codepath"); } break #define InvalidDefaultCase default: { Assert(!"Invalid codepath"); } break
//- sixten: Compiler warning helpers
#define UnusedVariable(Var) ((void)(Var))
//- sixten: Array & pointer manipulation //- sixten: Array & pointer manipulation
#define ArrayCount(Array) (sizeof(Array)/sizeof((Array)[0])) #define ArrayCount(Array) (sizeof(Array)/sizeof((Array)[0]))
@ -169,6 +174,9 @@ auto __Temp = (Element)->Next->Prev;\
(Element)->Next->Prev = (Element)->Prev->Next;\ (Element)->Next->Prev = (Element)->Prev->Next;\
(Element)->Prev->Next = __Temp; (Element)->Prev->Next = __Temp;
#define SenDLLIsEmpty(Sentinel)\
((Sentinel)->Next==(Sentinel))
//- sixten: Stringify //- sixten: Stringify
#define _Stringify(x) #x #define _Stringify(x) #x

View File

@ -519,6 +519,12 @@ inline range1_r32 Intersection(range1_r32 A, range1_r32 B)
return(Result); 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) inline range1_s32 Range1S32(s32 A, s32 B)
{ {
range1_s32 Result = {Min(A, B), Max(A, 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); 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) inline range1_s64 Range1S64(s64 A, s64 B)
{ {
range1_s64 Result = {Min(A, B), Max(A, 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); 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) inline range2_r32 Range2R32(v2_r32 A, v2_r32 B)
{ {
range2_r32 Result = {Min(A, B), Max(A, B)}; range2_r32 Result = {Min(A, B), Max(A, B)};

View File

@ -333,18 +333,21 @@ inline b32 InRange(range1_r32 Range, r32 Value);
inline b32 Contains(range1_r32 Range, r32 Value); inline b32 Contains(range1_r32 Range, r32 Value);
inline r32 DimOfRange(range1_r32 Range); inline r32 DimOfRange(range1_r32 Range);
inline range1_r32 Intersection(range1_r32 A, range1_r32 B); 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 range1_s32 Range1S32(s32 A, s32 B);
inline b32 InRange(range1_s32 Range, s32 Value); inline b32 InRange(range1_s32 Range, s32 Value);
inline b32 Contains(range1_s32 Range, s32 Value); inline b32 Contains(range1_s32 Range, s32 Value);
inline s32 DimOfRange(range1_s32 Range); inline s32 DimOfRange(range1_s32 Range);
inline range1_s32 Intersection(range1_s32 A, range1_s32 B); 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 range1_s64 Range1S64(s64 A, s64 B);
inline b32 InRange(range1_s64 Range, s64 Value); inline b32 InRange(range1_s64 Range, s64 Value);
inline b32 Contains(range1_s64 Range, s64 Value); inline b32 Contains(range1_s64 Range, s64 Value);
inline s64 DimOfRange(range1_s64 Range); inline s64 DimOfRange(range1_s64 Range);
inline range1_s64 Intersection(range1_s64 A, range1_s64 B); 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 range2_r32 Range2R32(v2_r32 A, v2_r32 B);
inline b32 InRange(range2_r32 Range, v2_r32 Value); inline b32 InRange(range2_r32 Range, v2_r32 Value);

View File

@ -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) static void ArenaClear(memory_arena *Arena)
{ {
ArenaPopTo(Arena, sizeof(*Arena)); ArenaPopTo(Arena, sizeof(*Arena));

View File

@ -42,6 +42,7 @@ static void ArenaRelease(memory_arena *Arena);
static void *ArenaPushNoClear(memory_arena *Arena, u64 Size); static void *ArenaPushNoClear(memory_arena *Arena, u64 Size);
static void *ArenaPush(memory_arena *Arena, u64 Size); static void *ArenaPush(memory_arena *Arena, u64 Size);
static void ArenaPopTo(memory_arena *Arena, u64 Position); static void ArenaPopTo(memory_arena *Arena, u64 Position);
static void ArenaPop(memory_arena *Arena, u64 Amount);
static void ArenaClear(memory_arena *Arena); static void ArenaClear(memory_arena *Arena);
static void ArenaSetAlign(memory_arena *Arena, u64 Align); static void ArenaSetAlign(memory_arena *Arena, u64 Align);
#define PushArray(Arena, type, Count) (type *)ArenaPush((Arena), sizeof(type)*(Count)) #define PushArray(Arena, type, Count) (type *)ArenaPush((Arena), sizeof(type)*(Count))

View File

@ -294,6 +294,15 @@ static string StringFromCodepoint(memory_arena *Arena, u32 Codepoint)
return(Result); 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 //- sixten: Replacing
static string RemoveAll(memory_arena *Arena, string Text, char ToRemove) static string RemoveAll(memory_arena *Arena, string Text, char ToRemove)
@ -578,7 +587,7 @@ static u32 EncodeUTF8Codepoint(u8 *Dest, u32 Codepoint)
return(Size); return(Size);
} }
static string_decode DecodeUTF16Codepoint(u8 *Data, s64 Count) static string_decode DecodeUTF16Codepoint(u16 *Data, s64 Count)
{ {
string_decode Result = {'#', 1}; string_decode Result = {'#', 1};
if(Data[0] < 0xD800 || 0xDFFF < Data[0]) if(Data[0] < 0xD800 || 0xDFFF < Data[0])
@ -622,7 +631,7 @@ static s64 UTF8IndexFromOffset(string String, s64 Offset)
u8 *StringBegin = String.Data; u8 *StringBegin = String.Data;
u8 *StringEnd = StringBegin+String.Count; u8 *StringEnd = StringBegin+String.Count;
u8 *Byte = StringBegin; u8 *Byte = StringBegin;
for(;Byte < StringEnd && Offset > 1; Offset -= 1) for(;Byte < StringEnd && Offset > 0; Offset -= 1)
{ {
Byte += DecodeUTF8Codepoint(Byte, StringEnd-Byte).Size; Byte += DecodeUTF8Codepoint(Byte, StringEnd-Byte).Size;
} }
@ -682,6 +691,54 @@ static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint)
return(Length); 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 //~ sixten: Text point
static text_point TextPointFromOffset(string String, s64 Offset) static text_point TextPointFromOffset(string String, s64 Offset)

View File

@ -12,6 +12,12 @@ struct string
u8 *Data; u8 *Data;
}; };
struct string16
{
s64 Count;
u16 *Data;
};
typedef string buffer; typedef string buffer;
struct string_node struct string_node
@ -94,6 +100,7 @@ static string PushCString(memory_arena *Arena, char *String);
static s64 ConvertStringToS64(string String); static s64 ConvertStringToS64(string String);
static string ConvertS64ToString(memory_arena *Arena, s64 Value); static string ConvertS64ToString(memory_arena *Arena, s64 Value);
static string StringFromCodepoint(memory_arena *Arena, u32 Codepoint); static string StringFromCodepoint(memory_arena *Arena, u32 Codepoint);
static r64 DoubleFromString(string String);
//- sixten: Replacing //- sixten: Replacing
@ -129,11 +136,14 @@ struct string_decode
static string_decode DecodeUTF8Codepoint(u8 *Data, s64 Count); static string_decode DecodeUTF8Codepoint(u8 *Data, s64 Count);
static u32 EncodeUTF8Codepoint(u8 *Dest, u32 Codepoint); 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 u32 EncodeUTF16Codepoint(u16 *Dest, u32 Codepoint);
static s64 UTF8FromCodepoint(u8 *Out, 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 //~ sixten: Text point
struct text_point struct text_point

View File

@ -10,6 +10,9 @@
#define PLATFORM_SET_CURSOR(name) void name(platform_cursor Cursor) #define PLATFORM_SET_CURSOR(name) void name(platform_cursor Cursor)
#define PLATFORM_TOGGLE_FULLSCREEN(name) void name(void) #define PLATFORM_TOGGLE_FULLSCREEN(name) void name(void)
#define PLATFORM_SHOW_MESSAGE(name) void name(string Message, platform_message_type Type) #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_RESERVE(platform_reserve);
typedef PLATFORM_RELEASE(platform_release); 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_SET_CURSOR(platform_set_cursor);
typedef PLATFORM_TOGGLE_FULLSCREEN(platform_toggle_fullscreen); typedef PLATFORM_TOGGLE_FULLSCREEN(platform_toggle_fullscreen);
typedef PLATFORM_SHOW_MESSAGE(platform_show_message); 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 struct platform_api
{ {
@ -38,6 +44,9 @@ platform_get_file_size *GetFileSize;
platform_set_cursor *SetCursor; platform_set_cursor *SetCursor;
platform_toggle_fullscreen *ToggleFullscreen; platform_toggle_fullscreen *ToggleFullscreen;
platform_show_message *ShowMessage; platform_show_message *ShowMessage;
platform_begin_file_iter *BeginFileIter;
platform_advance_file_iter *AdvanceFileIter;
platform_end_file_iter *EndFileIter;
}; };
#define RegisterPlatformFunctions(PlatformName)\ #define RegisterPlatformFunctions(PlatformName)\
@ -53,4 +62,7 @@ Platform.GetFileSize = PlatformName##_GetFileSize;\
Platform.SetCursor = PlatformName##_SetCursor;\ Platform.SetCursor = PlatformName##_SetCursor;\
Platform.ToggleFullscreen = PlatformName##_ToggleFullscreen;\ Platform.ToggleFullscreen = PlatformName##_ToggleFullscreen;\
Platform.ShowMessage = PlatformName##_ShowMessage;\ Platform.ShowMessage = PlatformName##_ShowMessage;\
Platform.BeginFileIter = PlatformName##_BeginFileIter;\
Platform.AdvanceFileIter = PlatformName##_AdvanceFileIter;\
Platform.EndFileIter = PlatformName##_EndFileIter;\

View File

@ -1,25 +1,37 @@
enum scene_ast_node_type enum scene_operator
{ {
S_AstNode_Invalid, S_Operator_Invalid,
S_AstNode_BlockStatement, S_Operator_Not,
S_AstNode_SceneDecl, S_Operator_Equal,
S_AstNode_Count, 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; inline scene_operator S_OperatorFromString(string String)
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
{ {
scene_ast_node_type Type; scene_operator Result = S_Operator_Invalid;
union if(0) {}
{ else if(AreEqual(String, StrLit("###"))) { Result = S_Operator_Invalid; }
scene_ast_node_invalid InvalidData; else if(AreEqual(String, StrLit("!"))) { Result = S_Operator_Not; }
scene_ast_node_block_statement BlockStatementData; else if(AreEqual(String, StrLit("="))) { Result = S_Operator_Equal; }
scene_ast_node_scene_declaration SceneDeclData; 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);
}

View File

@ -13,7 +13,7 @@ struct debug_settings
b32 ShowWelcomeMessage; b32 ShowWelcomeMessage;
}; };
per_thread debug_settings *DEBUG_DebugSettings = 0; global debug_settings *DEBUG_DebugSettings = 0;
#endif #endif
#include "vn_tokenizer.h" #include "vn_tokenizer.h"
@ -50,6 +50,9 @@ struct vn_state
render_handle BackgroundTexture; render_handle BackgroundTexture;
memory_arena *SceneArena;
compiled_scene CompiledScene;
#if VN_INTERNAL #if VN_INTERNAL
debug_settings DebugSettings; debug_settings DebugSettings;
#endif #endif
@ -107,7 +110,7 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
State->Config = CreateConfig(); State->Config = CreateConfig();
//- sixten: load assets //- 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 //- 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); Config_BindB32(State->Config, StrLit("Dev/ShowWelcomeMessage"), &DEBUG_DebugSettings->ShowWelcomeMessage, 1);
#endif #endif
Config_ReadFile(State->Config, StrLit("config.vn")); 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); UI_Init(&State->UI);
Workspace_Init(&State->Workspace); Workspace_Init(&State->Workspace);
AnimationCurve_Init(&State->AnimationCurveState); AnimationCurve_Init(&State->AnimationCurveState);

View File

@ -87,7 +87,7 @@ static void Config_ReadFile(config *Config, string Path)
//- sixten: read & tokenize input file //- sixten: read & tokenize input file
string Text = Platform_ReadEntireFile(Scratch.Arena, Path); 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; token_array Tokens = TokenizeResult.Tokens;
// sixten: parse context // sixten: parse context
@ -103,7 +103,7 @@ static void Config_ReadFile(config *Config, string Path)
string TokenString = Substring(Text, Token->Range); string TokenString = Substring(Text, Token->Range);
//- sixten: get next name //- 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); Config_ParseListPush(Scratch.Arena, &FullPath, TokenString);
ParseMode = ConfigParseMode_ScanForCurlyOpenOrEquals; ParseMode = ConfigParseMode_ScanForCurlyOpenOrEquals;
@ -112,7 +112,7 @@ static void Config_ReadFile(config *Config, string Path)
} }
//- sixten: scan for curly close //- 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); Config_ParseListPop(&FullPath);
Token += 1; Token += 1;
@ -120,7 +120,7 @@ static void Config_ReadFile(config *Config, string Path)
} }
//- sixten: scan for curly open //- 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; ParseMode = ConfigParseMode_Main;
Token += 1; Token += 1;
@ -128,7 +128,7 @@ static void Config_ReadFile(config *Config, string Path)
} }
//- sixten: scan for equals //- 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; ParseMode = ConfigParseMode_ScanForValue;
Token += 1; Token += 1;
@ -136,7 +136,7 @@ static void Config_ReadFile(config *Config, string Path)
} }
//- sixten: scan for semicolon //- 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; ParseMode = ConfigParseMode_Main;
Token += 1; Token += 1;
@ -144,7 +144,7 @@ static void Config_ReadFile(config *Config, string Path)
} }
//- sixten: scan for boolean value //- 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); string FullName = Config_ParseListJoin(Scratch.Arena, &FullPath);
config_entry *Entry = Config_FindEntryByName(Config, FullName); config_entry *Entry = Config_FindEntryByName(Config, FullName);
@ -161,7 +161,7 @@ static void Config_ReadFile(config *Config, string Path)
} }
//- sixten: scan for integer value //- 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); string FullName = Config_ParseListJoin(Scratch.Arena, &FullPath);
config_entry *Entry = Config_FindEntryByName(Config, FullName); config_entry *Entry = Config_FindEntryByName(Config, FullName);

View File

@ -15,46 +15,51 @@ enum font_id
Font_Count, Font_Count,
}; };
#define FontIcon_None 0x0000 #define FontIcon_None 0x0000
#define FontIcon_Pencil 0xe800 #define FontIcon_Pencil 0xe800
#define FontIcon_Forward 0xe801 #define FontIcon_Forward 0xe801
#define FontIcon_Book 0xe802 #define FontIcon_Book 0xe802
#define FontIcon_FolderOpen 0xe803 #define FontIcon_FolderOpen 0xe803
#define FontIcon_Wrench 0xe804 #define FontIcon_Wrench 0xe804
#define FontIcon_CW 0xe805 #define FontIcon_CW 0xe805
#define FontIcon_CCW 0xe806 #define FontIcon_CCW 0xe806
#define FontIcon_ArrowsCW 0xe807 #define FontIcon_ArrowsCW 0xe807
#define FontIcon_ResizeVertical 0xe808 #define FontIcon_ResizeVertical 0xe808
#define FontIcon_ResizeHorizontal 0xe809 #define FontIcon_ResizeHorizontal 0xe809
#define FontIcon_Play 0xe80a #define FontIcon_Play 0xe80a
#define FontIcon_Stop 0xe80b #define FontIcon_Stop 0xe80b
#define FontIcon_Floppy 0xe80c #define FontIcon_Floppy 0xe80c
#define FontIcon_Pause 0xe80d #define FontIcon_Pause 0xe80d
#define FontIcon_Folder 0xe80e #define FontIcon_Folder 0xe80e
#define FontIcon_Cog 0xe80f #define FontIcon_Cog 0xe80f
#define FontIcon_Attention 0xe810 #define FontIcon_Attention 0xe810
#define FontIcon_Cancel 0xe811 #define FontIcon_Cancel 0xe811
#define FontIcon_Filter 0xf0b0 #define FontIcon_Filter 0xf0b0
#define FontIcon_Menu 0xf0c9 #define FontIcon_Menu 0xf0c9
#define FontIcon_CircleEmpty 0xf10c #define FontIcon_CircleEmpty 0xf10c
#define FontIcon_Circle 0xf111 #define FontIcon_Circle 0xf111
#define FontIcon_Reply 0xf112 #define FontIcon_Reply 0xf112
#define FontIcon_Terminal 0xf120 #define FontIcon_Terminal 0xf120
#define FontIcon_Ellipsis 0xf141 #define FontIcon_Ellipsis 0xf141
#define FontIcon_Document 0xf15b #define FontIcon_Document 0xf15b
#define FontIcon_DocumentText 0xf15c #define FontIcon_DocumentText 0xf15c
#define FontIcon_Eyedropper 0xf1fb #define FontIcon_Eyedropper 0xf1fb
#define FontIcon_WindowMaximize 0xf2d0 #define FontIcon_WindowMaximize 0xf2d0
#define FontIcon_WindowMinimize 0xf2d1 #define FontIcon_WindowMinimize 0xf2d1
#define FontIcon_WindowRestore 0xf2d2 #define FontIcon_WindowRestore 0xf2d2
#define FontIcon_WindowClose 0xf2d4 #define FontIcon_WindowClose 0xf2d4
#define FontIcon_DownDir 0xe812 #define FontIcon_DownDir 0xe812
#define FontIcon_UpDir 0xe813 #define FontIcon_UpDir 0xe813
#define FontIcon_LeftDir 0xe814 #define FontIcon_LeftDir 0xe814
#define FontIcon_RightDir 0xe815 #define FontIcon_RightDir 0xe815
#define FontIcon_TextAlignLeft 0xe816 #define FontIcon_TextAlignLeft 0xe816
#define FontIcon_TextAlignCenter 0xe817 #define FontIcon_TextAlignCenter 0xe817
#define FontIcon_TextAlignRight 0xe818 #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 struct glyph
{ {
@ -72,7 +77,7 @@ struct glyph
r32 Advance; r32 Advance;
}; };
#define DEFAULT_GLYPH_ATLAS_DIM 1024 #define DEFAULT_GLYPH_ATLAS_DIM 1024*4
#define MAX_GLYPH_SIZE 64 #define MAX_GLYPH_SIZE 64
#define STB_TRUETYPE_IMPLEMENTATION #define STB_TRUETYPE_IMPLEMENTATION

View File

@ -24,6 +24,17 @@ struct platform_file_handle
b32 IsValid; b32 IsValid;
}; };
struct platform_file_info
{
string Name;
b32 IsDirectory;
};
struct platform_file_iter
{
u64 U64[1024];
};
enum platform_cursor enum platform_cursor
{ {
PlatformCursor_Arrow, PlatformCursor_Arrow,
@ -77,7 +88,7 @@ enum platform_key
Key_Left, Key_Right, Key_Up, Key_Down, Key_Left, Key_Right, Key_Up, Key_Down,
Key_Space, Key_Space, Key_Return,
Key_PageUp, Key_PageDown, Key_PageUp, Key_PageDown,
Key_Home, Key_End, Key_Home, Key_End,

View File

@ -1,17 +1,20 @@
@table(Name, NameLower, NameCaps, Type, Arguments) platform_functions: @table(Name, NameLower, NameCaps, Type, Arguments) platform_functions:
{ {
{ Reserve reserve RESERVE `void *` `u64 Size` } { Reserve reserve RESERVE `void *` `u64 Size` }
{ Release release RELEASE `void` `void *Pointer` } { Release release RELEASE `void` `void *Pointer` }
{ Commit commit COMMIT `void` `void *Pointer, u64 Size` } { Commit commit COMMIT `void` `void *Pointer, u64 Size` }
{ Decommit decommit DECOMMIT `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` } { OpenFile open_file OPEN_FILE `platform_file_handle` `string Path, platform_access_flags FileAccess` }
{ CloseFile close_file CLOSE_FILE `void` `platform_file_handle Handle` } { 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` } { 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` } { 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` } { GetFileSize get_file_size GET_FILE_SIZE `u64` `platform_file_handle Handle` }
{ SetCursor set_cursor SET_CURSOR `void` `platform_cursor Cursor` } { SetCursor set_cursor SET_CURSOR `void` `platform_cursor Cursor` }
{ ToggleFullscreen toggle_fullscreen TOGGLE_FULLSCREEN `void` `void` } { ToggleFullscreen toggle_fullscreen TOGGLE_FULLSCREEN `void` `void` }
{ ShowMessage show_message SHOW_MESSAGE `void` `string Message, platform_message_type Type` } { 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 @table_gen

View File

@ -1,63 +1,592 @@
//////////////////////////////// #include "generated/vn_scene.meta.h"
//~ sixten: Scene Message Functions #include "generated/vn_scene.meta.c"
static void S_PushMessage(memory_arena *Arena, scene_message_list *Messages, scene_node *Node, scene_message_type Type, string String)
static void S_EmitByte(scene_compiler *Compiler, u8 Byte)
{ {
scene_message *Message = PushStruct(Arena, scene_message); scene_annotated_bytecode_bucket *Bucket = Compiler->CurrentBucket;
Message->Type = Type; scene_annotated_bytecode_chunk *Chunk = Bucket->Last;
Message->Node = Node; if(!Chunk || Chunk->Count >= ArrayCount(Chunk->Data) || !AreEqual(Chunk->Name, Compiler->CurrentName))
Message->String = String; {
QueuePush(Messages->First, Messages->Last, Message); Chunk = PushStruct(Compiler->Arena, scene_annotated_bytecode_chunk);
Messages->Count += 1; Chunk->Name = Compiler->CurrentName;
QueuePush(Bucket->First, Bucket->Last, Chunk);
Bucket->Count += 1;
}
Chunk->Data[Chunk->Count] = Byte;
Chunk->Count += 1;
} }
//////////////////////////////// static u64 S_MakeConstant(scene_compiler *Compiler, scene_value Value)
//~ sixten: Scene Node Functions
static scene_node *S_SceneFromText(memory_arena *Arena, string Filename, string Text)
{ {
tokenize_result TokenizeResult = T_TokenizeFromText(Arena, Filename, Text, TokenGroup_Comment|TokenGroup_Whitespace); scene_value_chunk *Chunk = Compiler->LastValueChunk;
scene_parse_result ParseResult = S_ParseFromTokens(Arena, Filename, Text, TokenizeResult.Tokens); if(!Chunk || Chunk->Count >= ArrayCount(Chunk->Values))
scene_node *Result = ParseResult.Root; {
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); return(Result);
} }
////////////////////////////////
//~ sixten: Tokens -> Syntax Tree static void S_EmitVariableLength(scene_compiler *Compiler, u64 Value)
static scene_parse_result S_ParseFromTokens(memory_arena *Arena, string Filename, string Text, token_array Tokens)
{ {
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); temporary_memory Scratch = GetScratch(&Arena, 1);
//scene_node *Root = {}; u8 *ChunkBegin = Chunk->Data;
u8 *ChunkEnd = ChunkBegin + Chunk->Count;
//- sixten: setup parse context for(u8 *Data = ChunkBegin; Data < ChunkEnd; Data += 1)
scene_parse_context Context = {};
{ {
Context.TokensStart = Tokens.Tokens; switch(*Data)
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")))
{ {
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); 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); return(Result);
} }

View File

@ -1,97 +1,240 @@
/* date = July 9th 2023 11:08 am */ /* date = July 30th 2023 7:45 pm */
#ifndef VN_SCENE_H #ifndef VN_SCENE_H
#define VN_SCENE_H #define VN_SCENE_H
//////////////////////////////// // sixten(IMPORTANT): The arena that the scene is compiled on
//~ sixten: Scene Node Types // is assumed to be the same it runs on, i.e. the interpreter relies
enum scene_node_kind // on the memory addresses being the same during compilation and
{ // runtime.
S_NodeKind_Invalid, // We also assume that the original text and tokenization remains in
S_NodeKind_File, // memory, for the duration of the scene.
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: Scene Messages //~ sixten: Scene Compilation Types
enum scene_message_type typedef u64 scene_line_entry_flag;
enum
{ {
S_MessageType_Invalid, S_LineEntryFlag_NoClear = (1<<0),
S_MessageType_Note,
S_MessageType_Warning,
S_MessageType_Error,
}; };
struct scene_message enum scene_opcode
{ {
scene_message_type Type; S_Op_Invalid = 0,
scene_message *Next;
scene_node *Node; S_Op_Constant,
string String;
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_bytecode_chunk *Next;
scene_message *Last; 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; s64 Count;
}; };
//////////////////////////////// enum scene_value_kind
//~ sixten: Text -> Tokens
struct scene_tokenize_result
{ {
token_array Tokens; S_ValueKind_Number,
scene_message_list Messages; 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 *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 //~ sixten: Compiled Scene Types
struct scene_parse_result struct scene_proc
{ {
scene_node *Root; // sixten: scene data
scene_message_list Messages; 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 //~ sixten: Scene Compiler Functions
static void S_PushMessage(memory_arena *Arena, scene_message_list *Messages, scene_node *Node, scene_message_type Type, string String);; //- 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 #endif //VN_SCENE_H

View File

@ -1,34 +1,35 @@
@table(Name, NameLower, Contents) scene_ast_node_types: @table(Name, Operator) scene_operator_table:
{ {
{ Invalid invalid `` } { Invalid, "###" }
{ BlockStatement block_statement `scene_ast_node *First; scene_ast_node *Last;` } { Not, "!" }
{ SceneDecl scene_declaration `` } { Equal, "=" }
} { Equals, "==" }
{ NotEquals, "!=" }
@table_gen_enum scene_ast_node_type: { GreaterThanOrEquals, ">=" }
{ { LessThanOrEquals, "<=" }
@expand(scene_ast_node_types s) `S_AstNode_$(s.Name),`; { Greater, ">" }
`S_AstNode_Count,`: { Less, "<" }
{ Add, "+" }
{ Minus, "-" }
{ Multiply "*" }
{ Divide, "/" }
} }
@table_gen @table_gen
{ {
`struct scene_ast_node;` `enum scene_operator`;
}
@table_gen
{
@expand(scene_ast_node_types s) `struct scene_ast_node_$(s.NameLower) {$(s.Contents)};`
}
@table_gen
{
`struct scene_ast_node`;
`{`; `{`;
`scene_ast_node_type Type;`; @expand(scene_operator_table s) `S_Operator_$(s.Name),`;
`union`;
`{`;
@expand(scene_ast_node_types s) `scene_ast_node_$(s.NameLower) $(s.Name)Data;`;
`};`;
`};`; `};`;
}
@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);`;;
`}`;
} }

View File

@ -7,12 +7,6 @@ static string T_StringFromToken(string Text, token Token)
return(Result); 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) static void T_TokenChunkListPush(memory_arena *Arena, token_chunk_list *List, token Token, s64 MaxTokenCountPerNode)
{ {
token_chunk_node *Node = List->Last; 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 //~ 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); temporary_memory Scratch = GetScratch(&Arena, 1);
token_chunk_list Tokens = {}; token_chunk_list Tokens = {};
@ -70,14 +64,14 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
//- sixten: scan string & produce tokens //- sixten: scan string & produce tokens
for(;Byte < TextEnd;) for(;Byte < TextEnd;)
{ {
token_flags TokenFlags = 0; token_kind TokenKind = TokenKind_None;
u8 *TokenStart = 0; u8 *TokenStart = 0;
u8 *TokenEnd = 0; u8 *TokenEnd = 0;
//- sixten: whitespace //- 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; TokenStart = Byte;
TokenEnd = Byte; TokenEnd = Byte;
Byte += 1; Byte += 1;
@ -92,18 +86,18 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
} }
//- sixten: newlines //- sixten: newlines
if(TokenFlags == 0 && *Byte == '\n') if(TokenKind == TokenKind_None && *Byte == '\n')
{ {
TokenFlags = TokenFlag_Newline; TokenKind = TokenKind_Newline;
TokenStart = Byte; TokenStart = Byte;
TokenEnd = Byte + 1; TokenEnd = Byte + 1;
Byte += 1; Byte += 1;
} }
//- sixten: single-line comments //- 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; TokenStart = Byte;
TokenEnd = Byte + 2; TokenEnd = Byte + 2;
Byte += 2; Byte += 2;
@ -118,9 +112,9 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
} }
//- sixten: multi-line comments //- 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; TokenStart = Byte;
TokenEnd = Byte + 2; TokenEnd = Byte + 2;
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. // sixten(NOTE): This could potentially be wrong. The TokenEnd += 1 statement could currently make the token include the EOF.
if(Byte == TextEnd) if(Byte == TextEnd)
{ {
TokenFlags |= TokenFlag_BrokenComment; TokenKind = TokenKind_BrokenComment;
break; break;
} }
TokenEnd += 1; TokenEnd += 1;
@ -143,12 +137,12 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
} }
//- sixten: identifiers //- sixten: identifiers
if(TokenFlags == 0 && (('A' <= *Byte && *Byte <= 'Z') || if(TokenKind == TokenKind_None && (('A' <= *Byte && *Byte <= 'Z') ||
('a' <= *Byte && *Byte <= 'z') || ('a' <= *Byte && *Byte <= 'z') ||
(UTF8Lengths[*Byte>>3] > 1) || (UTF8Lengths[*Byte>>3] > 1) ||
*Byte == '_')) *Byte == '_'))
{ {
TokenFlags = TokenFlag_Identifier; TokenKind = TokenKind_Identifier;
TokenStart = Byte; TokenStart = Byte;
TokenEnd = Byte; TokenEnd = Byte;
Byte += UTF8Lengths[*Byte>>3]; Byte += UTF8Lengths[*Byte>>3];
@ -164,14 +158,28 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
break; 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 //- sixten: numerics
if(TokenFlags == 0 && (('0' <= *Byte && *Byte <= '9') || if(TokenKind == TokenKind_None && (('0' <= *Byte && *Byte <= '9') ||
*Byte == '.' || (*Byte == '-' && Byte + 1 < TextEnd && '0' <= Byte[1] && Byte[1] <= '9')))
((*Byte == '+' || *Byte == '-') && Byte + 1 < TextEnd && '0' <= Byte[1] && Byte[1] <= '9')))
{ {
TokenFlags = TokenFlag_Numeric; TokenKind = TokenKind_Numeric;
TokenStart = Byte; TokenStart = Byte;
TokenEnd = Byte; TokenEnd = Byte;
Byte += 1; Byte += 1;
@ -179,9 +187,7 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
{ {
TokenEnd += 1; TokenEnd += 1;
if(Byte == TextEnd || if(Byte == TextEnd ||
!(('A' <= *Byte && *Byte <= 'Z') || !(('0' <= *Byte && *Byte <= '9') ||
('a' <= *Byte && *Byte <= 'z') ||
('0' <= *Byte && *Byte <= '9') ||
*Byte == '_' || *Byte == '.')) *Byte == '_' || *Byte == '.'))
{ {
break; break;
@ -190,9 +196,9 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
} }
//- sixten: string literals //- sixten: string literals
if(TokenFlags == 0 && *Byte == '"') if(TokenKind == TokenKind_None && *Byte == '"')
{ {
TokenFlags = TokenFlag_StringLiteral; TokenKind = TokenKind_StringLiteral;
TokenStart = Byte; TokenStart = Byte;
TokenEnd = Byte; TokenEnd = Byte;
Byte += 1; Byte += 1;
@ -201,7 +207,7 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
TokenEnd += 1; TokenEnd += 1;
if(Byte == TextEnd || *Byte == '\n') if(Byte == TextEnd || *Byte == '\n')
{ {
TokenFlags |= TokenFlag_BrokenStringLiteral; TokenKind = TokenKind_BrokenStringLiteral;
break; break;
} }
if(*Byte == '"') if(*Byte == '"')
@ -213,64 +219,82 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename,
} }
} }
//- sixten: multi-char symbols //- sixten: symbols
if(TokenFlags == 0 && (*Byte == '!' || *Byte == '%' || *Byte == '&' || *Byte == '|' || if(TokenKind == TokenKind_None && (*Byte == '{' || *Byte == '}' || *Byte == '(' || *Byte == ')' ||
*Byte == '/' || *Byte == '=' || *Byte == '?' || *Byte == '^' || *Byte == ',' || *Byte == '.' || *Byte == '@' || *Byte == '#' ||
*Byte == '*' || *Byte == '+' || *Byte == '-' || *Byte == '$' || *Byte == ';' || *Byte == '+' || *Byte == '-' || *Byte == '*' ||
*Byte == '<' || *Byte == '>' || *Byte == '~' || *Byte == '\'')) *Byte == '/'))
{ {
TokenFlags = TokenFlag_Symbol;
TokenStart = Byte; TokenStart = Byte;
TokenEnd = Byte; TokenEnd = Byte+1;
Byte += 1;
for(;Byte <= TextEnd; 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; TokenEnd += 1;
if(Byte == TextEnd || Byte += 1;
!(*Byte == '!' || *Byte == '%' || *Byte == '&' || *Byte == '|' ||
*Byte == '/' || *Byte == '=' || *Byte == '?' || *Byte == '^' ||
*Byte == '*' || *Byte == '+' || *Byte == '-' || *Byte == '$' ||
*Byte == '<' || *Byte == '>' || *Byte == '~' || *Byte == '\''))
{
break;
}
} }
} }
//- sixten: single-char symbols //- sixten: bad character
if(TokenFlags == 0 && (*Byte == '{' || *Byte == '}' || *Byte == '(' || *Byte == ')' || if(TokenKind == TokenKind_None)
*Byte == '[' || *Byte == ']' || *Byte == ',' || *Byte == ';' ||
*Byte == ':' || *Byte == '@' || *Byte == '#'))
{ {
TokenFlags = TokenFlag_Reserved; TokenKind = TokenKind_BadCharacter;
TokenStart = Byte; TokenStart = Byte;
TokenEnd = Byte + 1; TokenEnd = Byte + 1;
Byte += 1; Byte += 1;
} }
//- sixten: bad character
if(TokenFlags == 0)
{
TokenFlags = TokenFlag_BadCharacter;
TokenStart = Byte;
TokenStart = Byte + 1;
Byte += 1;
}
//- sixten: push token //- 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); T_TokenChunkListPush(Scratch.Arena, &Tokens, Token, 4096);
} }
if(TokenFlags & TokenFlag_BrokenComment) if(TokenKind == TokenKind_BrokenComment)
{ {
string Message = StrLit("broken comment"); string Message = StrLit("broken comment");
T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message); T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message);
} }
if(TokenFlags & TokenFlag_BrokenStringLiteral) if(TokenKind == TokenKind_BrokenStringLiteral)
{ {
string Message = StrLit("broken string literal"); string Message = StrLit("broken string literal");
T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message); T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message);

View File

@ -5,44 +5,85 @@
//////////////////////////////// ////////////////////////////////
//~ sixten: Token Types //~ sixten: Token Types
typedef u32 token_flags; enum token_kind
enum
{ {
TokenFlag_Identifier = (1<<0), TokenKind_None,
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),
TokenFlag_BrokenComment = (1<<8), // sixten: labels
TokenFlag_BrokenStringLiteral = (1<<9), TokenKind_Identifier,
TokenFlag_BadCharacter = (1<<10), 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; typedef b32 tokenizer_filter_function(token_kind Kind);
enum
{ inline b32 T_IsComment(token_kind Kind) { return(Kind == TokenKind_Comment); }
TokenGroup_Comment = TokenFlag_Comment, inline b32 T_IsWhitespace(token_kind Kind) { return(Kind == TokenKind_Whitespace ||
TokenGroup_Whitespace = (TokenFlag_Whitespace | Kind == TokenKind_Newline); }
TokenFlag_Newline), inline b32 T_IsIrregular(token_kind Kind) { return(T_IsComment(Kind) ||
TokenGroup_Irregular = (TokenGroup_Comment | T_IsWhitespace(Kind)); }
TokenGroup_Whitespace), inline b32 T_IsRegular(token_kind Kind) { return(!T_IsIrregular(Kind)); }
TokenGroup_Regular = ~TokenGroup_Irregular, inline b32 T_IsInvalid(token_kind Kind) { return(Kind == TokenKind_None ||
TokenGroup_Label = (TokenFlag_Identifier | Kind == TokenKind_BrokenComment ||
TokenFlag_Numeric | Kind == TokenKind_BrokenStringLiteral ||
TokenFlag_StringLiteral | Kind == TokenKind_BadCharacter); }
TokenFlag_Symbol),
TokenGroup_Error = (TokenFlag_BrokenComment |
TokenFlag_BrokenStringLiteral |
TokenFlag_BadCharacter),
};
struct token struct token
{ {
token_flags Flags; token_kind Kind;
range1_s64 Range; range1_s64 Range;
}; };
@ -103,7 +144,6 @@ struct tokenize_result
//////////////////////////////// ////////////////////////////////
//~ sixten: Token Type Functions //~ sixten: Token Type Functions
static string T_StringFromToken(string Text, token Token); 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 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); 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 //~ 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 #endif //VN_TOKENIZER_H

View File

@ -16,6 +16,11 @@ static workspace *Workspace_GetState(void)
return(ThreadLocal_Workspace); return(ThreadLocal_Workspace);
} }
static memory_arena *Workspace_FrameArena(void)
{
return(ThreadLocal_Workspace->FrameArena);
}
//- sixten: Commands //- sixten: Commands
static void Workspace_IssueCommand(workspace_command_sig *Sig, u64 Argument = 0) 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_CreateNewView(Workspace_View_Startup, CurrentPanel);
Workspace->Menu = ToolbarMenu_None; 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_CreateNewView(Workspace_View_TextEditor, CurrentPanel);
Workspace->Menu = ToolbarMenu_None;
}
if(Workspace_BuildMenuItem(FontIcon_None, "Command Palette", "").Clicked)
{
Workspace_CreateNewView(Workspace_View_CommandPalette, CurrentPanel);
Workspace->Menu = ToolbarMenu_None; Workspace->Menu = ToolbarMenu_None;
} }
if(Workspace_BuildMenuItem(FontIcon_Wrench, "Settings", "").Clicked) if(Workspace_BuildMenuItem(FontIcon_Wrench, "Settings", "").Clicked)
@ -755,6 +755,7 @@ static void Workspace_Init(workspace *Workspace)
{ {
Workspace_SetState(Workspace); Workspace_SetState(Workspace);
Workspace->FrameArena = ArenaAllocate(Gigabytes(1));
Workspace->CommandArena = ArenaAllocate(Gigabytes(1)); Workspace->CommandArena = ArenaAllocate(Gigabytes(1));
Workspace->PanelArena = 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_Startup, Workspace->RootPanel);
} }
Workspace_CreateNewView(Workspace_View_TextEditor, Workspace->RootPanel);
// sixten: Setup keybinds // 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_P, PlatformModifier_Ctrl, Workspace_Command_SplitPanelHorizontal);
BIND_COMMAND(Key_L, PlatformModifier_Ctrl, Workspace_Command_SplitPanelVertical); BIND_COMMAND(Key_L, PlatformModifier_Ctrl, Workspace_Command_SplitPanelVertical);
BIND_COMMAND(Key_O, PlatformModifier_Ctrl, Workspace_Command_OpenView, Workspace_View_TextEditor);
#if VN_INTERNAL #if VN_INTERNAL
BIND_COMMAND(Key_U, PlatformModifier_Ctrl|PlatformModifier_Shift, Workspace_Command_ToggleRenderUIDebugRects); BIND_COMMAND(Key_U, PlatformModifier_Ctrl|PlatformModifier_Shift, Workspace_Command_ToggleRenderUIDebugRects);
#endif #endif
@ -783,6 +785,7 @@ static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCom
vn_input *Input, glyph_atlas *GlyphAtlas) vn_input *Input, glyph_atlas *GlyphAtlas)
{ {
Workspace_SetState(Workspace); Workspace_SetState(Workspace);
ArenaClear(Workspace->FrameArena);
Workspace->Input = Input; Workspace->Input = Input;
Workspace->EventList = Input->EventList; Workspace->EventList = Input->EventList;

View File

@ -72,6 +72,9 @@ struct workspace
vn_input *Input; vn_input *Input;
platform_event_list *EventList; platform_event_list *EventList;
// sixten: General Purpose Allocation
memory_arena *FrameArena;
// sixten: Command Allocation // sixten: Command Allocation
memory_arena *CommandArena; memory_arena *CommandArena;
workspace_command *FirstFreeCommand; workspace_command *FirstFreeCommand;
@ -104,6 +107,7 @@ struct workspace
//- sixten: State management //- sixten: State management
static void Workspace_SetState(workspace *Workspace); static void Workspace_SetState(workspace *Workspace);
static workspace *Workspace_GetState(void); static workspace *Workspace_GetState(void);
static memory_arena *Workspace_FrameArena(void);
//- sixten: Commands //- sixten: Commands
static void Workspace_IssueCommand(workspace_command_sig *Sig, u64 Argument); static void Workspace_IssueCommand(workspace_command_sig *Sig, u64 Argument);

View File

@ -86,6 +86,12 @@ WORKSPACE_COMMAND(Workspace_Command_ClosePanel)
Workspace_DeletePanel(Panel); Workspace_DeletePanel(Panel);
} }
WORKSPACE_COMMAND(Workspace_Command_OpenView)
{
workspace *Workspace = Workspace_GetState();
Workspace_CreateNewView((workspace_view_type)Argument, Workspace->CurrentPanel);
}
#if VN_INTERNAL #if VN_INTERNAL
WORKSPACE_COMMAND(Workspace_Command_ToggleRenderUIDebugRects) WORKSPACE_COMMAND(Workspace_Command_ToggleRenderUIDebugRects)
{ {

View File

@ -30,7 +30,7 @@ static void MutableStringReplaceRange(mutable_string *MutString, string ReplaceS
ArenaPopTo(MutString->Arena, sizeof(memory_arena)+NewCount+1); 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); Copy(MutString->String.Data+Range.Min, ReplaceString.Data, ReplaceString.Count);
MutString->String.Count = NewCount; MutString->String.Count = NewCount;
@ -70,7 +70,7 @@ static workspace_text_data Workspace_TextDataFromStringChunkList(memory_arena *A
ArenaClear(Arena); ArenaClear(Arena);
//- sixten: tokenize the text //- 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; token_array Tokens = TokenizeResult.Tokens;
//- sixten: gather all line ranges //- sixten: gather all line ranges
@ -102,6 +102,13 @@ static workspace_text_data Workspace_TextDataFromStringChunkList(memory_arena *A
return(Result); 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) static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
{ {
temporary_memory Scratch = GetScratch(); temporary_memory Scratch = GetScratch();
@ -114,7 +121,7 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
v2 Offset = Box->Parent->Offset; v2 Offset = Box->Parent->Offset;
//- sixten: rendering properties //- sixten: rendering properties
r32 FontSize = 16.0f; r32 FontSize = Editor->FontSize;
r32 LineHeight = FontSize + 4.0f; r32 LineHeight = FontSize + 4.0f;
//- sixten: calculate the dimensions of the glyphs //- 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); v2_r32 LineMarginDim = V2((LineMarginDigitsRequired)*GlyphAdvance, ParentRect.Max.y - ParentRect.Min.y);
//- sixten: tokenize text //- 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_array Tokens = TokenizeResult.Tokens;
token *TokensBegin = Tokens.Tokens; token *TokensBegin = Tokens.Tokens;
token *TokensEnd = TokensBegin + Tokens.Count; 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); s64 TopMostLine = Min((s64)Floor(-Offset.y / LineHeight), LineCount);
for(s64 LinesFound = 0; LinesFound < TopMostLine && VisibleTokensBegin < TokensEnd; VisibleTokensBegin += 1) for(s64 LinesFound = 0; LinesFound < TopMostLine && VisibleTokensBegin < TokensEnd; VisibleTokensBegin += 1)
{ {
if(VisibleTokensBegin->Flags & TokenFlag_Newline) if(VisibleTokensBegin->Kind == TokenKind_Newline)
{ {
LinesFound += 1; LinesFound += 1;
} }
@ -158,7 +165,7 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
s64 LinesOnScreen = Min((s64)Floor(ParentDim.y / LineHeight)+1, LineCount-TopMostLine); s64 LinesOnScreen = Min((s64)Floor(ParentDim.y / LineHeight)+1, LineCount-TopMostLine);
for(s64 LinesFound = 0; LinesFound < LinesOnScreen && VisibleTokensEnd < TokensEnd; VisibleTokensEnd += 1) for(s64 LinesFound = 0; LinesFound < LinesOnScreen && VisibleTokensEnd < TokensEnd; VisibleTokensEnd += 1)
{ {
if(VisibleTokensEnd->Flags & TokenFlag_Newline) if(VisibleTokensEnd->Kind == TokenKind_Newline)
{ {
LinesFound += 1; LinesFound += 1;
} }
@ -197,40 +204,59 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
//- sixten: get color & font from token //- sixten: get color & font from token
font_id Font = Font_Monospace; font_id Font = Font_Monospace;
v4 Color = Color_Magenta; v4 Color = Color_Magenta;
if(Token->Flags & TokenGroup_Comment) { Color = Color_Grey; Font = Font_MonospaceOblique; } if(Token->Kind == TokenKind_Comment) { Color = Color_Grey; Font = Font_MonospaceOblique; }
else if(Token->Flags & TokenFlag_Reserved) { Color = Color_Grey; } else if(Token->Kind > TokenKind_SymbolsBegin && Token->Kind < TokenKind_SymbolsEnd) { Color = Color_Grey; }
else if(Token->Flags & TokenFlag_Symbol) { Color = ColorFromHex(0xbd2d2dff); } else if(Token->Kind == TokenKind_StringLiteral) { Color = ColorFromHex(0xffa900ff); }
else if(Token->Flags & TokenFlag_StringLiteral) { Color = ColorFromHex(0xffa900ff); } else if(Token->Kind == TokenKind_Numeric) { Color = ColorFromHex(0xffa900ff); }
else if(Token->Flags & TokenFlag_Numeric) { Color = ColorFromHex(0xffa900ff); } else if(Token->Kind > TokenKind_KeywordsBegin && Token->Kind < TokenKind_KeywordsEnd)
else if(Token->Flags & TokenFlag_Identifier)
{ {
//- sixten: check for keywords if(Token->Kind == TokenKind_True || Token->Kind == TokenKind_False)
if(AreEqual(TokenString, StrLit("true")) ||
AreEqual(TokenString, StrLit("false")))
{ {
Color = ColorFromHex(0xffa900ff); Color = ColorFromHex(0xffa900ff);
} }
else if(AreEqual(TokenString, StrLit("var")) || else
AreEqual(TokenString, StrLit("proc")) ||
AreEqual(TokenString, StrLit("branch")) ||
AreEqual(TokenString, StrLit("jump")) ||
AreEqual(TokenString, StrLit("if")))
{ {
Color = ColorFromHex(0xf0c674ff); 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 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 else
{ {
if(Token->Flags & TokenFlag_Newline) if(Token->Kind == TokenKind_Newline)
{ {
TokenP.x = BaseTokenP.x; TokenP.x = BaseTokenP.x;
TokenP.y += LineHeight; 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; s64 LineIndex = CursorTextP.Line-1;
string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]); string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]);
s64 ColumnIndex = CursorTextP.Column-1; 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); range1_s64 LineRange = Range1S64(Selection.Min.Line, Selection.Max.Line);
for(s64 LineIndex = TopMostLine; LineIndex < TopMostLine + LinesOnScreen; LineIndex += 1) for(s64 LineIndex = TopMostLine; LineIndex < TopMostLine + LinesOnScreen; LineIndex += 1)
{ {
r32 LineY = Box->Rect.Min.y + LineIndex*LineHeight;
if(Contains(LineRange, LineIndex + 1)) if(Contains(LineRange, LineIndex + 1))
{ {
range1_s64 ColumnRange = Lines->Ranges[LineIndex]; 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), range1_s64 ColumnOffsetRange = Range1S64(UTF8OffsetFromIndex(Line, NormalizedColumnRange.Min),
UTF8OffsetFromIndex(Line, NormalizedColumnRange.Max)); UTF8OffsetFromIndex(Line, NormalizedColumnRange.Max));
r32 LineY = LineIndex*LineHeight;
v4_r32 LineHighlightColor = ColorFromHex(0x66B3CC4C); v4_r32 LineHighlightColor = ColorFromHex(0x66B3CC4C);
range2_r32 LineHighlightBox = Range2R32(V2(LineMarginDim.x+ColumnOffsetRange.Min*GlyphAdvance, LineY), range2_r32 LineHighlightBox = Range2R32(Box->Rect.Min+V2(LineMarginDim.x+ColumnOffsetRange.Min*GlyphAdvance, LineY),
V2(LineMarginDim.x+ColumnOffsetRange.Max*GlyphAdvance, LineY+LineHeight)); Box->Rect.Min+V2(LineMarginDim.x+ColumnOffsetRange.Max*GlyphAdvance, LineY+LineHeight));
PushQuad(Group, LineHighlightBox, LineHighlightColor, LineHighlightColor, LineHighlightColor, LineHighlightColor, 4, 1.4, 0); PushQuad(Group, LineHighlightBox, LineHighlightColor, LineHighlightColor, LineHighlightColor, LineHighlightColor, 4, 1.4, 0);
} }
} }
@ -304,6 +330,190 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
ReleaseScratch(Scratch); 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) static void Workspace_BuildTextEditor(workspace_view *View)
{ {
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data; 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(); temporary_memory Scratch = GetScratch();
//- sixten: rendering properties //- sixten: rendering properties
r32 FontSize = 16.0f; r32 FontSize = Editor->FontSize = 14.0f;
r32 LineHeight = FontSize + 4.0f; r32 LineHeight = FontSize + 4.0f;
//- sixten: calculate the dimensions of the glyphs //- sixten: calculate the dimensions of the glyphs
@ -322,129 +532,197 @@ static void Workspace_BuildTextEditor(workspace_view *View)
s32 LineMarginDigitsRequired = 6; s32 LineMarginDigitsRequired = 6;
r32 LineMarginWidth = (LineMarginDigitsRequired)*GlyphAdvance; r32 LineMarginWidth = (LineMarginDigitsRequired)*GlyphAdvance;
ui_box *EditorBox = 0;
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 1)); b32 InFileListMode = AreEqual(Editor->FileName, StrLit(""));
UI_Scroll(0, &Editor->Offset.y) if(InFileListMode)
{ {
//- sixten: find the container box for the scrollable region //- sixten: build & handle file lister
Editor->ContainerBox = UI_TopParent()->Parent->Parent; workspace_text_editor_lister_action Action = Workspace_BuildTextEditorLister(View, Editor);
if(Action.HasRequestedFile)
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); //- sixten: try to load file
EditorBox->DrawCallback = Workspace_TextEditorDrawCallback; string FullPath = PushFormat(Scratch.Arena, "%S/%S", Action.Path, Action.Name);
EditorBox->DrawCallbackData = Editor; 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;
}
}
} }
else
b32 CursorHasBeenModified = false;
if(Workspace_ViewIsCurrent(View))
{ {
//- 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 UI_SetNextSize(UI_Pixels(Editor->TextDim.x, 1), UI_Pixels(Editor->TextDim.y, 1));
if(Platform_KeyPress(UI_EventList(), Key_Z, PlatformModifier_Ctrl)) EditorBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, "Workspace Text Editor %p", View);
{ EditorBox->DrawCallback = Workspace_TextEditorDrawCallback;
history_node *Node = List->At; EditorBox->DrawCallbackData = Editor;
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;
}
}
} }
//- sixten: select all b32 CursorHasBeenModified = false;
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 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) //- sixten: handle history
{ {
text_action Action = MultiLineTextActionFromEvent(Event); history_list *List = &Editor->History;
if(IsValid(&Action))
//- 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); history_node *Node = List->At;
if(Node != &List->Sentinel)
if(DimOfRange(Op.Range) != 0 || !AreEqual(StrLit(""), Op.ReplaceString))
{ {
//- 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; Line.Count -= 1;
}
//- sixten: remove the pre-existing history if needed
if(List->Sentinel.Prev != List->At) for(u8 *Data = Line.Data; *Data == '\t' && Data < Line.Data+Line.Count; Data += 1)
{ {
// sixten(TODO): instead of just removing the links to the old memory, find some way to manage it. Indent += 1;
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_text_data TextData = Workspace_TextDataFromStringChunkList(Editor->ProcessingArena, Editor->Text.String);
Editor->Tokens = TextData.Tokens;
Editor->Lines = TextData.Lines;
} }
CursorHasBeenModified = true; if(Event->Codepoint == '{')
Editor->EditState.Cursor = Op.NewCursor; {
Editor->EditState.Mark = Op.NewMark; 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);
}
}
} }
} }
} }
}
//- sixten: right-click dropdown
ui_signal Signal = UI_SignalFromBox(EditorBox); {
if(Signal.Dragging) if(Editor->DropdownActive)
{ {
if(Signal.Pressed) 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 //- sixten: translate mouse position to text point
v2 MouseOffset = Signal.MouseP - EditorBox->Rect.Min - V2(LineMarginWidth, 0); 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]); string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]);
s64 ColumnOffset = (s64)(MouseOffset.x / GlyphAdvance); s64 ColumnOffset = (s64)(MouseOffset.x / GlyphAdvance);
s64 ColumnIndex = UTF8IndexFromOffset(Line, ColumnOffset); 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); Editor->EditState.Cursor = Editor->EditState.Mark = OffsetFromTextPoint(Editor->Text.String, Editor->Lines, Point);
} }
//- sixten: translate mouse position to text point if(Signal.Dragging)
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)
{ {
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->DropdownActive = true;
Editor->LastTextPoint.Column = Max(Editor->LastTextPoint.Column, Point.Column); 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); ReleaseScratch(Scratch);
} }

View File

@ -44,6 +44,13 @@ struct workspace_text_data
range1_s64_array Lines; range1_s64_array Lines;
}; };
struct workspace_text_editor_lister_action
{
b32 HasRequestedFile;
string Path;
string Name;
};
struct workspace_view_text_editor struct workspace_view_text_editor
{ {
// sixten: processed text // sixten: processed text
@ -52,12 +59,17 @@ struct workspace_view_text_editor
range1_s64_array Lines; range1_s64_array Lines;
// sixten: text being edited // sixten: text being edited
string FileName;
string FilePath;
mutable_string Text; mutable_string Text;
// sixten: text editing // sixten: text editing
text_edit_state EditState; text_edit_state EditState;
text_point LastTextPoint; text_point LastTextPoint;
// sixten: text rendering
r32 FontSize;
// sixten: history // sixten: history
memory_arena *HistoryArena; memory_arena *HistoryArena;
history_list History; history_list History;
@ -66,6 +78,16 @@ struct workspace_view_text_editor
ui_box *ContainerBox; ui_box *ContainerBox;
v2 TextDim; v2 TextDim;
v2 Offset; v2 Offset;
b32 DropdownActive;
v2 DropdownP;
r32 DropdownTransition;
// sixten: file lister
string Path;
r32 ListerScroll;
u8 ListerInput[256];
s32 ListerInputUsed;
text_edit_state ListerInputEditState;
}; };
//////////////////////////////// ////////////////////////////////

View File

@ -85,6 +85,25 @@ inline string Workspace_GetViewName(workspace_view *View)
case Workspace_View_Startup: { Result = StrLit("Welcome"); } break; case Workspace_View_Startup: { Result = StrLit("Welcome"); } break;
case Workspace_View_Editor: { Result = StrLit("Editor"); } break; case Workspace_View_Editor: { Result = StrLit("Editor"); } break;
case Workspace_View_Settings: { Result = StrLit("Settings"); } 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); return(Result);

Binary file not shown.

View File

@ -167,6 +167,73 @@ static PLATFORM_SET_CURSOR(Win32_SetCursor)
Global_Win32State.Cursor = Cursor; 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) inline u64 Win32_GetWallClock(void)
{ {
LARGE_INTEGER Query; 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_UP) { Key = Key_Up; }
else if(VKCode == VK_DOWN) { Key = Key_Down; } else if(VKCode == VK_DOWN) { Key = Key_Down; }
else if(VKCode == VK_SPACE) { Key = Key_Space; } 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_PRIOR) { Key = Key_PageUp; }
else if(VKCode == VK_NEXT) { Key = Key_PageDown; } else if(VKCode == VK_NEXT) { Key = Key_PageDown; }
else if(VKCode == VK_HOME) { Key = Key_Home; } else if(VKCode == VK_HOME) { Key = Key_Home; }

View File

@ -22,6 +22,13 @@ struct win32_state
platform_cursor Cursor; platform_cursor Cursor;
}; };
struct win32_file_find_data
{
HANDLE Handle;
b32 FindFirstReturned;
WIN32_FIND_DATAW FindData;
};
struct win32_loaded_code struct win32_loaded_code
{ {
HMODULE DLL; HMODULE DLL;

View File

@ -0,0 +1,5 @@
proc main
{
"Hello!";
"Scene test 123" #noclear;
}

7
data/first.vns 100644
View File

@ -0,0 +1,7 @@
proc main
{
for(var idx = 0; idx < 10; idx = idx + 1)
{
print("hello, line, paint, color, design, address, brightness");
}
}

View File

@ -1,31 +1,31 @@
// This just experiments with the scripting language // This just experiments with the scripting language
var times = 0 var times = 0;
proc "Start" proc "Start"
{ {
"so, I actually changed my mind." "so, I actually changed my mind.";
"the editor will not be node based" "the editor will not be node based";
"I realised that it would just be slower to write dialog that way soooo..." "I realised that it would just be slower to write dialog that way soooo...";
"instead, I present to you the.........." "instead, I present to you the..........";
"vn scene - scripting language" "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 branch
{ {
"Return to start" "Return to start"
{ {
jump "Start" jump "Start";
} }
if(times >= 10) if(times >= 10)
{ {
"SUPER EPIC SECRET" "SUPER EPIC SECRET"
{ {
jump "Epic Scene" jump "Epic Scene";
} }
} }
} }
@ -33,9 +33,9 @@ proc "Start"
proc "Epic Scene" proc "Epic Scene"
{ {
"woah... so epic" "woah... so epic";
@s "oh, right. almost forgot to mention that you can talk as different characters." @s "oh, right. almost forgot to mention that you can talk as different characters.";
@s "you know... " @s "you know... ";
wait wait;
@s #noclear "the usual" @s #noclear "the usual";
} }

37
data/vns.txt 100644
View File

@ -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 ")";

Binary file not shown.