From da19db1b236d6a81728d145f11f2461d05641a45 Mon Sep 17 00:00:00 2001 From: Slendi Date: Wed, 28 Feb 2024 15:07:06 +0200 Subject: [PATCH] Add type checker Signed-off-by: Slendi --- ast.odin | 36 +++++++++++++++++++++++++++++++++ lexer.odin | 57 +++++++++++++++++++++++++++++++++++++++++++++++++---- main.odin | 2 ++ parser.odin | 10 ++++++++++ tokens.odin | 1 + util.odin | 8 ++++++++ 6 files changed, 110 insertions(+), 4 deletions(-) diff --git a/ast.odin b/ast.odin index e9a4492..79d7fcd 100644 --- a/ast.odin +++ b/ast.odin @@ -18,6 +18,8 @@ NodeKind :: enum { IndexAccess, FunctionCall, VariableDeclaration, + Cast, + BitwiseCast, // Function, @@ -37,6 +39,7 @@ Node :: struct { children: [dynamic]^Node, value: TokenValue, value_token_kind: TokenKind, + return_type: ^Type, } node_create_value :: proc(kind: NodeKind, range: TextRange, value: TokenValue) -> (ret: ^Node) { @@ -171,6 +174,9 @@ node_print :: proc(node: ^Node, indent := 0) { if node.value_token_kind != .Invalid { fmt.printf("{} ", node.value_token_kind) } + if node.return_type != nil { + fmt.printf("-> {} ", node.return_type) + } fmt.println("") for child in node.children { @@ -265,6 +271,36 @@ node_create_variable :: proc( return } +node_create_cast :: proc( + range: TextRange, + value, type_: ^Node, +) -> ( + ret: ^Node, +) { + ret = new(Node) + ret^ = { + kind = .Cast, + range = range, + children = {value, type_}, + } + return +} + +node_create_bitwise_cast :: proc( + range: TextRange, + value, type_: ^Node, +) -> ( + ret: ^Node, +) { + ret = new(Node) + ret^ = { + kind = .BitwiseCast, + range = range, + children = {value, type_}, + } + return +} + node_create_struct_enum_or_union :: proc( range: TextRange, kind: NodeKind, diff --git a/lexer.odin b/lexer.odin index 0ee06ec..fdd0f62 100644 --- a/lexer.odin +++ b/lexer.odin @@ -306,10 +306,59 @@ lexer_read_identifier :: proc(lexer: ^Lexer) -> Token { lexer_advance(lexer) } - if compare_dyn_arr_string( - &str, - "fn", - ) {return token_create(.Function, crange)} else if compare_dyn_arr_string(&str, "struct") {return token_create(.Struct, crange)} else if compare_dyn_arr_string(&str, "enum") {return token_create(.Enum, crange)} else if compare_dyn_arr_string(&str, "union") {return token_create(.Union, crange)} else if compare_dyn_arr_string(&str, "type") {return token_create(.Type, crange)} else if compare_dyn_arr_string(&str, "use") {return token_create(.Use, crange)} else if compare_dyn_arr_string(&str, "pub") {return token_create(.Pub, crange)} else if compare_dyn_arr_string(&str, "let") {return token_create(.Let, crange)} else if compare_dyn_arr_string(&str, "mut") {return token_create(.Mut, crange)} else if compare_dyn_arr_string(&str, "as") {return token_create(.As, crange)} else if compare_dyn_arr_string(&str, "in") {return token_create(.In, crange)} else if compare_dyn_arr_string(&str, "if") {return token_create(.If, crange)} else if compare_dyn_arr_string(&str, "else") {return token_create(.Else, crange)} else if compare_dyn_arr_string(&str, "elif") {return token_create(.Elif, crange)} else if compare_dyn_arr_string(&str, "for") {return token_create(.For, crange)} else if compare_dyn_arr_string(&str, "break") {return token_create(.Break, crange)} else if compare_dyn_arr_string(&str, "continue") {return token_create(.Continue, crange)} else if compare_dyn_arr_string(&str, "switch") {return token_create(.Switch, crange)} else if compare_dyn_arr_string(&str, "case") {return token_create(.Case, crange)} 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)} + if compare_dyn_arr_string(&str, "fn") { + return token_create(.Function, crange) + } else if compare_dyn_arr_string(&str, "struct") { + return token_create(.Struct, crange) + } else if compare_dyn_arr_string(&str, "enum") { + return token_create(.Enum, crange) + } else if compare_dyn_arr_string(&str, "union") { + return token_create(.Union, crange) + } else if compare_dyn_arr_string(&str, "type") { + return token_create(.Type, crange) + } else if compare_dyn_arr_string(&str, "use") { + return token_create(.Use, crange) + } else if compare_dyn_arr_string(&str, "pub") { + return token_create(.Pub, crange) + } else if compare_dyn_arr_string(&str, "let") { + return token_create(.Let, crange) + } else if compare_dyn_arr_string(&str, "mut") { + return token_create(.Mut, crange) + } else if compare_dyn_arr_string(&str, "as") { + return token_create(.As, crange) + } else if compare_dyn_arr_string(&str, "bitwise_as") { + return token_create(.BitwiseAs, crange) + } else if compare_dyn_arr_string(&str, "in") { + return token_create(.In, crange) + } else if compare_dyn_arr_string(&str, "if") { + return token_create(.If, crange) + } else if compare_dyn_arr_string(&str, "else") { + return token_create(.Else, crange) + } else if compare_dyn_arr_string(&str, "elif") { + return token_create(.Elif, crange) + } else if compare_dyn_arr_string(&str, "for") { + return token_create(.For, crange) + } else if compare_dyn_arr_string(&str, "break") { + return token_create(.Break, crange) + } else if compare_dyn_arr_string(&str, "continue") { + return token_create(.Continue, crange) + } else if compare_dyn_arr_string(&str, "switch") { + return token_create(.Switch, crange) + } else if compare_dyn_arr_string(&str, "case") { + return token_create(.Case, crange) + } 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) + } return token_create_u8(.Identifier, str, crange) } diff --git a/main.odin b/main.odin index b26e2a5..fdf3156 100644 --- a/main.odin +++ b/main.odin @@ -32,12 +32,14 @@ main :: proc() { parser := parser_create(lexer) ast := parser_parse(&parser) + type_check(ast, nil) if len(g_message_list) > 0 { for msg in g_message_list { fmt.printf("%s\n", msg) } return } + node_print(ast) } diff --git a/parser.odin b/parser.odin index f6ee768..355428e 100644 --- a/parser.odin +++ b/parser.odin @@ -459,6 +459,14 @@ parser_parse_suffix :: proc(parser: ^Parser) -> ^Node { return node_create_unary(.Increment, range, lhs) } else if accept(parser, .Decrement) { return node_create_unary(.Decrement, range, lhs) + } else if accept(parser, .As) { + type := parser_parse_type(parser) + range.end = type.range.end + return node_create_cast(range, lhs, type) + } else if accept(parser, .BitwiseAs) { + type := parser_parse_type(parser) + range.end = type.range.end + return node_create_bitwise_cast(range, lhs, type) } return lhs } @@ -519,6 +527,7 @@ parser_parse_factor :: proc(parser: ^Parser) -> (ret: ^Node) { parser.tok.kind != .CloseParen && parser.tok.kind != .Semicolon && parser.tok.kind != .Arrow && + parser.tok.kind != .Assign && parser.tok.kind != .EOF { prev := parser.can_be_function parser.can_be_function = false @@ -527,6 +536,7 @@ parser_parse_factor :: proc(parser: ^Parser) -> (ret: ^Node) { parser.tok.kind != .Semicolon && parser.tok.kind != .Arrow && parser.tok.kind != .EOF && + parser.tok.kind != .Assign && parser_is_factor_token_or_prefix(parser.tok.kind) { append(&args, parser_parse_expression(parser)) } diff --git a/tokens.odin b/tokens.odin index 75fdaad..6cdcee3 100644 --- a/tokens.odin +++ b/tokens.odin @@ -21,6 +21,7 @@ TokenKind :: enum { Pub, Mut, As, + BitwiseAs, In, If, Else, diff --git a/util.odin b/util.odin index 4783858..48319ed 100644 --- a/util.odin +++ b/util.odin @@ -11,3 +11,11 @@ compare_dyn_arr_string :: proc(a: ^[dynamic]u8, b: string) -> bool { } return true } + +get_character_sum_of_dyn_arr :: proc(a: ^[dynamic]u8) -> int { + sum := 0 + for c in a { + sum += int(c) + } + return sum +}