From ee25688b424090253aa61e63617ea4bace944ebd Mon Sep 17 00:00:00 2001 From: Judah Caruso Date: Sun, 1 Jun 2025 22:19:31 -0600 Subject: [PATCH] fix memory, add vm --- memory/module.jai | 4 +- vm/module.jai | 7 ++ vm/parser.jai | 297 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 vm/module.jai create mode 100644 vm/parser.jai diff --git a/memory/module.jai b/memory/module.jai index f3af797..576f955 100644 --- a/memory/module.jai +++ b/memory/module.jai @@ -63,12 +63,12 @@ align_to :: (ptr: int, align: int = Default_Align) -> int { } init_or_zero :: inline (ptr: *$T, custom_init: (*T) = null) { - init :: initializer_of(T); if custom_init != null { custom_init(ptr); } - #if init != null { + init :: initializer_of(T); + if init != null { inline init(ptr); } else { diff --git a/vm/module.jai b/vm/module.jai new file mode 100644 index 0000000..ee6c130 --- /dev/null +++ b/vm/module.jai @@ -0,0 +1,7 @@ +#module_parameters(RUN_TESTS := false); + +#scope_file; + +#if RUN_TESTS { + test :: #import "jc/test"; +} diff --git a/vm/parser.jai b/vm/parser.jai new file mode 100644 index 0000000..74164fb --- /dev/null +++ b/vm/parser.jai @@ -0,0 +1,297 @@ +Token :: struct { + kind: Kind; + str: string; + + Kind :: enum { + invalid; + end_of_file; + + symbol; + number; + string; + + kw_var; + kw_def; + kw_type; + kw_do; + kw_end; + + equal :: #char "="; + plus :: #char "+"; + minus :: #char "-"; + star :: #char "*"; + f_slash :: #char "/"; + b_slash :: #char "\\"; + + l_paren :: #char "("; + r_paren :: #char ")"; + l_square :: #char "["; + r_square :: #char "]"; + l_brace :: #char "{"; + r_brace :: #char "}"; + comma :: #char ","; + dot :: #char "."; + colon :: #char ":"; + semicolon :: #char ";"; + } +} + +Node :: struct { + kind: Kind; + + Kind :: enum { + invalid; + + decl_start; + var; + decl_end; + + expr_start; + symbol; + literal; + expr_end; + } +} + +Node_Var :: struct { + #as using n: Node; + n.kind = .var; + + symbol: *Node; + type_expr: *Node; + value_expr: *Node; +} + +Node_Symbol :: struct { + #as using n: Node; + n.kind = .symbol; + + str: string; +} + +Node_Literal :: struct { + #as using n: Node; + n.kind = .literal; + + union { + } +} + +Parser :: struct { + allocator: Allocator; + toplevel: [..]*Node; + + previous: Token; + filename: string; + source: string; + offset: int; +} + +init :: (p: *Parser, allocator: Allocator) { + p.allocator = allocator; + p.toplevel.allocator = allocator; +} + +parse_string :: (p: *Parser, source: string) -> bool { + p.source = source; + p.offset = 0; + + while !at_end(p) { + t := peek_token(p); + if t.kind == .invalid || t.kind == .end_of_file { + break; + } + + node := parse_toplevel_declaration(p); + if node == null break; + + array.append(*p.toplevel, node); + } + + return false; +} + + +#scope_file; + +parse_toplevel_declaration :: (p: *Parser) -> *Node { + t, ok := expect_token(p, .kw_var); + if ok == false return null; + + s:, ok = expect_token(p, .symbol); + if ok == false return null; + + type_expr: *Node; + value_expr: *Node; + + // var sym int + // var sym int = value + // var sym = value + + t = peek_token(p); + if t.kind == .equal { + consume_token(p); + value_expr = parse_expression(p); + } + else { + type_expr = parse_type_expression(p); + if type_expr == null return null; + + if peek_token(p).kind == .equal { + consume_token(p); + value_expr = parse_expression(p); + } + } + + symbol := make_node(p, Node_Symbol); + symbol.str = s.str; + + node := make_node(p, Node_Var); + node.symbol = symbol; + node.type_expr = type_expr; + node.value_expr = value_expr; + + return node; +} + +parse_type_expression :: (p: *Parser) -> *Node { + t, ok := expect_token(p, .symbol, .star); + if ok == false return null; + + if t.kind == { + case .symbol; + node := make_node(p, Node_Symbol); + node.str = t.str; + return node; + } + + return null; +} + +parse_expression :: (p: *Parser) -> *Node { + return null; +} + +make_node :: (p: *Parser, $T: Type) -> *T { + return mem.request_memory(T,, allocator = p.allocator); +} + +peek_token :: (p: *Parser) -> Token { + copy := p.*; + return consume_token(*copy); +} + +at_end :: (p: *Parser) -> bool { + return p.offset >= p.source.count; +} + +starts_symbol :: (c: u8) -> bool { + return (c >= "a" && c <= "z") || + (c >= "A" && c <= "Z") || + (c == "_"); +} +continues_symbol :: (c: u8) -> bool { + return starts_symbol(c) || (c >= "0" && c <= "9"); +} + +starts_number :: (c: u8) -> bool { + return (c >= "0" && c <= "9"); +} +continues_number :: (c: u8) -> bool { + return starts_number(c) || c == "."; +} + +consume_token :: (p: *Parser) -> Token { + if at_end(p) return .{ kind = .end_of_file }; + + c := p.source[p.offset]; + while !at_end(p) { + c = p.source[p.offset]; + if c == { + case " "; #through; + case "\n"; #through; + case "\t"; + p.offset += 1; + case; + break; + } + } + + if starts_symbol(c) { + t := Token.{ str = .{ data = p.source.data + p.offset } }; + while !at_end(p) { + c = p.source[p.offset]; + if !continues_symbol(c) break; + p.offset += 1; + } + + t.str.count = (p.source.data + p.offset) - t.str.data; + if t.str == { + case "var"; t.kind = .kw_var; + case "def"; t.kind = .kw_def; + case "do"; t.kind = .kw_do; + case "end"; t.kind = .kw_end; + case "type"; t.kind = .kw_type; + case; t.kind = .symbol; + } + + return t; + } + + if starts_number(c) { + t := Token.{ kind = .number, str = .{ data = p.source.data + p.offset } }; + while !at_end(p) { + c = p.source[p.offset]; + if !continues_number(c) break; + p.offset += 1; + } + + t.str.count = (p.source.data + p.offset) - t.str.data; + return t; + } + + if c == { + case "+"; #through; + case "-"; #through; + case "*"; #through; + case "/"; #through; + case "="; #through; + case "("; #through; + case ")"; #through; + case "["; #through; + case "]"; #through; + case "{"; #through; + case "}"; + s := string.{ data = p.source.data + p.offset, count = 1 }; + p.offset += 1; + return .{ kind = xx c, str = s }; + } + + s := string.{ data = p.source.data + p.offset, count = 1 }; + return .{ kind = .invalid, str = s }; +} + +expect_token :: (p: *Parser, kinds: ..Token.Kind) -> Token, bool { + t := consume_token(p); + for kinds if it == t.kind { + return t, true; + } + + return t, false; +} + +#run { + parser: Parser; + init(*parser, context.allocator); + + ok := parse_string(*parser, #string END + var x = 10 + var y = 20 + END); +} + +mem :: #import "jc/memory"; +array :: #import "jc/array"; + +basic :: #import "Basic"; // @future +strings :: #import "String"; // @future