diff --git a/ast.odin b/ast.odin index 6c7c70e..b871840 100644 --- a/ast.odin +++ b/ast.odin @@ -25,6 +25,7 @@ NodeKind :: enum { Use, If, + VariableDeclaration, } Node :: struct { @@ -116,6 +117,7 @@ node_print :: proc(node: ^Node, indent := 0) { } if node == nil { fmt.println("nil") + return } fmt.printf("{}: {} ", node.kind, "TODO") @@ -195,3 +197,21 @@ node_create_if :: proc(range: TextRange, condition, then, else_: ^Node) -> (ret: return } +node_create_variable :: proc(range: TextRange, name, type_, value: ^Node, is_const: bool) -> (ret: ^Node) { + fmt.printf("Creating variable declaration for {} with value {}\n", name.value.([dynamic]u8), value) + ret = new(Node) + ret^ = { + kind = .VariableDeclaration, + range = range, + children = { name, type_, value }, + value = is_const, + } + + //if value != nil { + // fmt.printf("Appending value to variable declaration\n") + // append(&ret.children, value) + //} + + return +} + diff --git a/lexer.odin b/lexer.odin index 633171d..d6f7fc5 100644 --- a/lexer.odin +++ b/lexer.odin @@ -181,6 +181,7 @@ lexer_next :: proc(lexer: ^Lexer) -> (ret: Token) { case '?': ret = token_create(.Question, crange) case ':': ret = token_create(.Colon, crange) case '.': ret = token_create(.Dot, crange) + case ',': ret = token_create(.Comma, crange) case ';': ret = token_create(.Semicolon, crange) case '"': ret = lexer_read_string(lexer, .String, '\"') @@ -276,6 +277,7 @@ lexer_read_identifier :: proc(lexer: ^Lexer) -> Token { else if compare_dyn_arr_string(&str, "ret") { return token_create(.Ret, crange) } else if compare_dyn_arr_string(&str, "static") { return token_create(.Static, crange) } else if compare_dyn_arr_string(&str, "defer") { return token_create(.Defer, crange) } + else if compare_dyn_arr_string(&str, "let") { return token_create(.Let, crange) } else if compare_dyn_arr_string(&str, "and") { return token_create(.And, crange) } else if compare_dyn_arr_string(&str, "or") { return token_create(.Or, crange) } diff --git a/parser.odin b/parser.odin index d6ea77e..07c5098 100644 --- a/parser.odin +++ b/parser.odin @@ -53,9 +53,17 @@ parser_parse_block :: proc(parser: ^Parser, end: TokenKind) -> (ret: ^Node) { range := parser.tok.range statements : [dynamic]^Node for parser.tok.kind != end && parser.tok.kind != .EOF { - stmt := parser_parse_statement(parser) - if stmt != nil { - append(&statements, stmt) + if accept(parser, .Let) { + ret := parser_parse_definitions(parser) + expect(parser, .Semicolon) + for stmt in ret { + append(&statements, stmt) + } + } else { + stmt := parser_parse_statement(parser) + if stmt != nil { + append(&statements, stmt) + } } } expect(parser, end) @@ -80,6 +88,76 @@ parser_parse_statement :: proc(parser: ^Parser) -> (ret: ^Node) { return } +@(private = "file") +parser_parse_type :: proc(parser: ^Parser) -> (ret: ^Node) { + // FIXME: Add more types + range := parser.tok.range + if parser.tok.kind == .Identifier { + ret = node_create_value(.Identifier, range, parser.tok.value.([dynamic]u8)) + parser_next(parser) + } else { + append(&g_message_list, message_create( + .Error, + fmt.aprintf("Expected type, got {} at {}", parser.tok.kind, "TODO"), + parser.tok.range)) + ret = nil + } + return +} + +@(private = "file") +parser_parse_definitions :: proc(parser: ^Parser, end := TokenKind.Semicolon) -> [dynamic]^Node { + range := parser.tok.range + vars : [dynamic]^Node + type : ^Node = nil + are_constants := false + uninitialized := false + for parser.tok.kind != end && parser.tok.kind != .EOF { + names := [dynamic][dynamic]u8{} + for parser.tok.kind == .Identifier { + tok := parser.tok + if !expect(parser, .Identifier) { + break + } + + append(&names, tok.value.([dynamic]u8)) + } + + expect(parser, .Colon) + + if parser.tok.kind != .Colon && parser.tok.kind != .Assign { + type = parser_parse_type(parser) + } + + if accept(parser, .Assign) { + are_constants = false + } else if accept(parser, .Colon) { + are_constants = true + } else { + uninitialized = true + } + + for i in 0.. ^Node { range := parser.tok.range @@ -144,9 +222,9 @@ parser_parse_arrow :: proc(parser: ^Parser) -> ^Node { for accept(parser, .Arrow) { rhs := parser_parse_assignment(parser) if rhs.kind != .FunctionCall && - rhs.kind != .Identifier && - rhs.kind != .FieldAccess && - rhs.kind != .IndexAccess { + rhs.kind != .Identifier && + rhs.kind != .FieldAccess && + rhs.kind != .IndexAccess { append(&g_message_list, message_create( .Error, fmt.aprintf("Expected function call, got {} at {}", rhs.kind, "TODO"), diff --git a/test.cat b/test.cat index 437cb14..e6a0956 100644 --- a/test.cat +++ b/test.cat @@ -4,6 +4,11 @@ use lib "directory/long_library_name" fmt.printf "%d + %d = %d File length: %d" a b a + b (io.file_size "file.txt") fmt.println "Hello world!" +let a := 123 +let uninitialized : u32 +let multiple variables here : u32 = 1 2 3 +let string : str, number : i32 + if a == 1 { lol } elif b == 2 { diff --git a/tokens.odin b/tokens.odin index 02d6c57..75fdaad 100644 --- a/tokens.odin +++ b/tokens.odin @@ -19,7 +19,6 @@ TokenKind :: enum { Type, Use, Pub, - Let, Mut, As, In, @@ -34,6 +33,7 @@ TokenKind :: enum { Ret, Static, Defer, + Let, // Logical Operators Keywords And, @@ -80,6 +80,7 @@ TokenKind :: enum { Colon, Arrow, Dot, + Comma, // Other Semicolon, @@ -96,6 +97,7 @@ TextRange :: struct { } TokenValue :: union { + bool, u64, f64, [dynamic]u8, @@ -140,3 +142,5 @@ token_create_f64 :: proc(kind: TokenKind, value: f64, range: TextRange) -> Token }; } + +