From f5a72da29db659f818c61265eec1251568f44d80 Mon Sep 17 00:00:00 2001 From: Slendi Date: Thu, 8 Feb 2024 17:09:58 +0200 Subject: [PATCH] Fix parser and implement if-elif-else --- lexer.odin | 8 +++++- parser.odin | 73 +++++++++++++++++++++++++++++++++++++---------------- test.cat | 7 +++++ 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/lexer.odin b/lexer.odin index ff8d1bf..633171d 100644 --- a/lexer.odin +++ b/lexer.odin @@ -131,7 +131,13 @@ lexer_next :: proc(lexer: ^Lexer) -> (ret: Token) { case '/': ret = token_create(.Divide, crange) case '%': ret = token_create(.Modulo, crange) case '`': ret = token_create(.Exponent, crange) - case '=': ret = token_create(.Assign, crange) + case '=': + ret = token_create(.Assign, crange) + if lexer.next == '=' { + lexer_advance(lexer) + crange.end = lexer.position + ret = token_create(.Equals, crange) + } case '!': ret = token_create(.Not, crange) if lexer.next == '=' { diff --git a/parser.odin b/parser.odin index 68a5085..425d366 100644 --- a/parser.odin +++ b/parser.odin @@ -98,26 +98,7 @@ parser_parse_if_statement :: proc(parser: ^Parser) -> ^Node { @(private = "file") parser_parse_expression :: proc(parser: ^Parser) -> ^Node { - return parser_parse_arrow(parser) -} - -@(private = "file") -parser_parse_arrow :: proc(parser: ^Parser) -> ^Node { - // Basically, a -> b is the same as function_call(b, {a}) - lhs := parser_parse_assignment(parser) - for accept(parser, .Arrow) { - rhs := parser_parse_assignment(parser) - if rhs.kind != .FunctionCall && 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"), rhs.range)) - return lhs - } - if rhs.kind != .FunctionCall { - rhs = node_create_function_call(rhs.range, rhs, nil) - } - inject_at(&rhs.children, 1, lhs) - lhs = rhs - } - return lhs + return parser_parse_assignment(parser) } @(private = "file") @@ -135,7 +116,42 @@ parser_parse_binary_expression :: proc(parser: ^Parser, kinds: []TokenKind, next @(private = "file") parser_parse_assignment :: proc(parser: ^Parser) -> ^Node { - return parser_parse_binary_expression(parser, {.Assign}, parser_parse_addition) + return parser_parse_binary_expression(parser, {.Assign}, parser_parse_arrow) +} + +@(private = "file") +parser_parse_arrow :: proc(parser: ^Parser) -> ^Node { + // Basically, a -> b is the same as function_call(b, {a}) + lhs := parser_parse_equality(parser) + for accept(parser, .Arrow) { + rhs := parser_parse_assignment(parser) + if rhs.kind != .FunctionCall && + 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"), + rhs.range)) + return lhs + } + if rhs.kind != .FunctionCall { + rhs = node_create_function_call(rhs.range, rhs, nil) + } + inject_at(&rhs.children, 1, lhs) + lhs = rhs + } + return lhs +} + +@(private = "file") +parser_parse_equality :: proc(parser: ^Parser) -> ^Node { + return parser_parse_binary_expression(parser, {.Equals, .NotEquals}, parser_parse_comparison) +} + +@(private = "file") +parser_parse_comparison :: proc(parser: ^Parser) -> ^Node { + return parser_parse_binary_expression(parser, {.LessThan, .LessThanOrEqual, .GreaterThan, .GreaterThanOrEqual}, parser_parse_addition) } @(private = "file") @@ -215,6 +231,19 @@ parser_parse_prefix :: proc(parser: ^Parser) -> ^Node { return parser_parse_factor(parser) } +@(private = "file") +parser_is_factor_token_or_prefix :: proc(tt: TokenKind) -> bool { + #partial switch tt { + case .Identifier, .Integer, .Float, .String, .Character, .OpenParen: + return true + case .Not, .Subtract, .BitwiseNot, .Increment, .Decrement: + // Assuming these can be used as prefixes in unary operations + return true + case: + return false + } +} + @(private = "file") parser_parse_factor :: proc(parser: ^Parser) -> (ret: ^Node) { ret = nil @@ -243,7 +272,7 @@ parser_parse_factor :: proc(parser: ^Parser) -> (ret: ^Node) { prev := parser.can_be_function parser.can_be_function = false args : [dynamic]^Node - for parser.tok.kind != .CloseParen && parser.tok.kind != .Semicolon && parser.tok.kind != .Arrow && parser.tok.kind != .EOF { + for parser.tok.kind != .CloseParen && parser.tok.kind != .Semicolon && parser.tok.kind != .Arrow && parser.tok.kind != .EOF && parser_is_factor_token_or_prefix(parser.tok.kind) { append(&args, parser_parse_expression(parser)) } ret = node_create_function_call(ret.range, ret, args) diff --git a/test.cat b/test.cat index d1d0809..1980272 100644 --- a/test.cat +++ b/test.cat @@ -1,2 +1,9 @@ fmt.printf "%d + %d = %d File length: %d" a b a + b (io.file_size "file.txt") fmt.println "Hello world!" +if (a == 1) { + lol +} elif (b == 2) { + kek +} else { + aaaaaaa +}