From 11c936ba7f9b7110076214c526a851c18bd89ff6 Mon Sep 17 00:00:00 2001 From: Niels Bross Date: Wed, 3 Sep 2025 22:31:18 +0200 Subject: [PATCH] Started load directive. --- Lexing.jai | 28 +++++++++++++++++++------ Parsing.jai | 48 +++++++++++++++++++++++++++++++++++++++++++ Semantic_Analysis.jai | 4 +++- module.jai | 12 ++++++++++- test/load_test.ink | 5 +++++ 5 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 test/load_test.ink diff --git a/Lexing.jai b/Lexing.jai index eb297c5..01e357a 100644 --- a/Lexing.jai +++ b/Lexing.jai @@ -101,6 +101,7 @@ Token_Kind :: enum { TOKEN_RETURN; TOKEN_REGISTER; + TOKEN_STRING; TOKEN_STRUCT; TOKEN_SWITCH; @@ -323,10 +324,6 @@ make_float :: (lexer : *Lexer) -> *Token { return token; } -make_string :: () { - -} - new_token :: (lexer : *Lexer, kind : Token_Kind) -> *Token { length := lexer.cursor - lexer.start; token : Token; @@ -352,6 +349,16 @@ make_directive :: (lexer : *Lexer) -> *Token { return make_identifier(lexer, .TOKEN_DIRECTIVE); } +make_string :: (lexer : *Lexer) -> *Token { + token : *Token = new_token(lexer, .TOKEN_STRING); + + name : string = .{ count = token.length, + data = *lexer.input.data[lexer.start] }; + token.string_value = name; + + return token; +} + make_identifier :: (lexer : *Lexer, kind : Token_Kind) -> *Token { token : *Token = new_token(lexer, kind); @@ -423,6 +430,17 @@ scan_next_token :: (lexer : *Lexer) -> *Token { if is_digit(c) return number(lexer); if c == { + case #char "\""; { + c = advance(lexer); + lexer.start = lexer.cursor; + while c != #char "\"" { + c = advance(lexer); + } + lexer.cursor -= 1; + tok := make_string(lexer); + advance(lexer); + return tok; + } case #char "+"; { if match_character(lexer, #char "=") return make_token(lexer, .TOKEN_PLUSEQUALS); return make_token(lexer, .TOKEN_PLUS); @@ -504,8 +522,6 @@ scan_next_token :: (lexer : *Lexer) -> *Token { // return error_token(lexer, tprint("Invalid token: %", s)); } - - lex :: (result : *Compile_Result) { if result.had_error { return; diff --git a/Parsing.jai b/Parsing.jai index 64805a1..bc53a61 100644 --- a/Parsing.jai +++ b/Parsing.jai @@ -1,5 +1,7 @@ #import "Flat_Pool"; +// #load "qpwodkqopwkd.jai"; + /** * TODO: * if parsing @@ -322,6 +324,26 @@ empty_block :: (state : *Parse_State, token : Token, message : string) { record_error(state, token, final_message, false); } +unable_to_open_file :: (state : *Parse_State, path : string, token : Token) { + builder : String_Builder; + init_string_builder(*builder,, temp); + + print_to_builder(*builder, "Unable to open file '%' for reading\n\n", path); + + location := generate_source_location_from_token(state, token); + + indent(*builder, 1); + cyan(*builder); + print_to_builder(*builder, "%\n", print_from_source_location(location)); + indent(*builder, 1); + + loc := location.begin; + print_token_pointer(*builder, loc); + + final_message := builder_to_string(*builder); + record_error(state, token, final_message, false); +} + error_node :: (parse_state : *Parse_State, message : string) -> *AST_Node { node := make_node(parse_state, .Error); node.name = copy_string(message); @@ -624,6 +646,32 @@ directive :: (state : *Parse_State) -> *AST_Node { if_directive.source_location = source_location; return if_directive; + } else if state.current.ident_value == "load" { + advance(state); + + if check(state, .TOKEN_STRING) { + path := state.current.string_value; + advance(state); + + consume(state, .TOKEN_SEMICOLON, "Expected ';' after #load directive"); + result : Compile_Result; + result.allocator = state.result.allocator; + result.environment = state.result.environment; + + result.file = make_file(*result, path); + + if result.file.source.count == 0 { + unable_to_open_file(state, path, state.previous); + advance_to_sync_point(state); + return null; + } + + lex(*result); + + for tok : result.tokens.tokens { + array_add(*state.result.tokens.tokens, tok); + } + } } return null; diff --git a/Semantic_Analysis.jai b/Semantic_Analysis.jai index 00f0575..cd03972 100644 --- a/Semantic_Analysis.jai +++ b/Semantic_Analysis.jai @@ -1783,7 +1783,9 @@ check :: (result : *Compile_Result) { init_semantic_checker(*checker, result.root, result.file.path); - // @Performance: Should have this built in stuff done earlier and only once + // Actually, these are not built-ins, they should be a core lib you import. + // So if we add imports, we can just add this file. + // Maybe we should just do #load add_builtins(*checker); checker.result.file = file; diff --git a/module.jai b/module.jai index a0b44d5..ed8a3ba 100644 --- a/module.jai +++ b/module.jai @@ -4,6 +4,8 @@ #load "Semantic_Analysis.jai"; #load "Codegen.jai"; +#import "File_Utilities"; + add_define :: (env : *Environment, key : string) { for define : env.defines { if define == key { @@ -143,8 +145,11 @@ Token_Stream :: struct { tokens : [..]Token; } -Compile_Result :: struct { +Compile_Result :: struct { file : Input_File; + + environment : Environment; + tokens : Token_Stream; root : *AST_Node; nodes : [..]AST_Node; @@ -192,6 +197,10 @@ record_error :: (result : *Compile_Result, format : string, args : .. Any) { } make_file :: (result : *Compile_Result, path : string) -> Input_File { + if !file_exists(path) { + record_error(result, "Unable to load file: %", path); + return .{}; + } file_string, ok := read_entire_file(path); if !ok { @@ -479,6 +488,7 @@ compile_file :: (compiler : *Shader_Compiler, path : string) -> Compile_Result { result.allocator = make_arena(*result.arena); result.file = make_file(*result, path); + result.environment = compiler.environment; lex(*result); parse(*result); diff --git a/test/load_test.ink b/test/load_test.ink new file mode 100644 index 0000000..83eabcf --- /dev/null +++ b/test/load_test.ink @@ -0,0 +1,5 @@ +#load "../builtins.ink"; + +vertex main :: () { + v2 : float2 = float2(2.0, 2.0); +}