package main import "core:fmt" Parser :: struct { lexer: ^Lexer, tok, next: Token, can_be_function: bool, } parser_create :: proc(lexer: ^Lexer) -> (ret: Parser) { ret = { lexer = lexer, can_be_function = true, } parser_next(&ret) parser_next(&ret) return } @(private = "file") parser_next :: proc(parser: ^Parser) { parser.tok = parser.next parser.next = lexer_next(parser.lexer) } @(private = "file") accept :: proc(parser: ^Parser, tok: TokenKind) -> bool { if parser.tok.kind == tok { parser_next(parser) return true } return false } @(private = "file") expect :: proc(parser: ^Parser, tok: TokenKind) -> bool { if !accept(parser, tok) { append(&g_message_list, message_create(.Error, fmt.aprintf("Expected {}, got {} at {}", tok, parser.tok.kind, "TODO"), parser.tok.range)) return false } return true } parser_parse :: proc(parser: ^Parser) -> (ret: ^Node) { ret = parser_parse_block(parser, .EOF) return } @(private = "file") 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 { 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) return node_create_block(range, statements) } @(private = "file") parser_parse_statement :: proc(parser: ^Parser) -> (ret: ^Node) { range_beg := parser.tok.range if accept(parser, .Semicolon) { ret = nil } else if parser.tok.kind == .If { expect(parser, .If) ret = parser_parse_if_statement(parser) ret.range.start = range_beg.start } else if parser.tok.kind == .Use { ret = parser_parse_use_statement(parser) } else { ret = parser_parse_expression(parser) expect(parser, .Semicolon) } 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 expect(parser, .Use) alias : [dynamic]u8 if parser.tok.kind == .Identifier { alias = parser.tok.value.([dynamic]u8) parser_next(parser) } tok := parser.tok if !expect(parser, .String) { return nil } return node_create_use(range, tok.value.([dynamic]u8), alias) } @(private = "file") parser_parse_if_statement :: proc(parser: ^Parser) -> ^Node { range := parser.tok.range condition := parser_parse_expression(parser) expect(parser, .OpenBrace) body := parser_parse_block(parser, .CloseBrace) if accept(parser, .Elif) { falsebody := parser_parse_if_statement(parser) return node_create_if(range, condition, body, falsebody) } if accept(parser, .Else) { expect(parser, .OpenBrace) falsebody := parser_parse_block(parser, .CloseBrace) return node_create_if(range, condition, body, falsebody) } return node_create_if(range, condition, body, nil) } @(private = "file") parser_parse_expression :: proc(parser: ^Parser) -> ^Node { return parser_parse_assignment(parser) } @(private = "file") parser_parse_binary_expression :: proc(parser: ^Parser, kinds: []TokenKind, next: proc(parser: ^Parser) -> ^Node) -> ^Node { lhs := next(parser) for kind in kinds { for accept(parser, kind) { rhs := next(parser) lhs = node_create_binary(kind, lhs.range, lhs, rhs) lhs^.range.end = rhs.range.end } } return lhs } @(private = "file") parser_parse_assignment :: proc(parser: ^Parser) -> ^Node { 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") parser_parse_addition :: proc(parser: ^Parser) -> ^Node { return parser_parse_binary_expression(parser, {.Add, .Subtract}, parser_parse_multiplication) } @(private = "file") parser_parse_multiplication :: proc(parser: ^Parser) -> ^Node { return parser_parse_binary_expression(parser, {.Multiply, .Divide, .Modulo}, parser_parse_exponent) } @(private = "file") parser_parse_exponent :: proc(parser: ^Parser) -> ^Node { return parser_parse_binary_expression(parser, {.Exponent}, parser_parse_prefix_2) } @(private = "file") parser_parse_bitwise :: proc(parser: ^Parser) -> ^Node { return parser_parse_binary_expression(parser, {.BitwiseAnd, .BitwiseOr, .BitwiseXOR, .BitwiseLeftShift, .BitwiseRightShift}, parser_parse_prefix_2) } @(private = "file") parser_parse_prefix_2 :: proc(parser: ^Parser) -> ^Node { range := parser.tok.range if accept(parser, .Not) { rhs := parser_parse_suffix(parser) range.end = rhs.range.end return node_create_unary(.Not, range, rhs) } else if accept(parser, .BitwiseNot) { rhs := parser_parse_suffix(parser) range.end = rhs.range.end return node_create_unary(.BitwiseNot, range, rhs) } else if accept(parser, .Increment) { rhs := parser_parse_suffix(parser) range.end = rhs.range.end return node_create_unary(.Increment, range, rhs) } else if accept(parser, .Decrement) { rhs := parser_parse_suffix(parser) range.end = rhs.range.end return node_create_unary(.Decrement, range, rhs) } else if accept(parser, .BitwiseXOR) { rhs := parser_parse_suffix(parser) range.end = rhs.range.end return node_create_unary(.BitwiseXOR, range, rhs) } return parser_parse_suffix(parser) } @(private = "file") parser_parse_suffix :: proc(parser: ^Parser) -> ^Node { range := parser.tok.range lhs := parser_parse_prefix(parser) range_op := parser.tok.range range.end = range_op.end if accept(parser, .OpenBracket) { rhs := parser_parse_expression(parser) range.end = rhs.range.end expect(parser, .CloseBracket) return node_create_index_access(range, lhs, rhs) } else if accept(parser, .Increment) { return node_create_unary(.Increment, range, lhs) } else if accept(parser, .Decrement) { return node_create_unary(.Decrement, range, lhs) } return lhs } @(private = "file") parser_parse_prefix :: proc(parser: ^Parser) -> ^Node { range := parser.tok.range if accept(parser, .Add) { return node_create_unary(.Add, range, parser_parse_prefix(parser)) } else if accept(parser, .Subtract) { return node_create_unary(.Subtract, range, parser_parse_prefix(parser)) } 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 if parser.tok.kind == .Integer { ret = node_create_value(.Integer, parser.tok.range, parser.tok.value) parser_next(parser) } else if parser.tok.kind == .Float { ret = node_create_value(.Float, parser.tok.range, parser.tok.value) parser_next(parser) } else if parser.tok.kind == .Character { ret = node_create_value(.Character, parser.tok.range, parser.tok.value) parser_next(parser) } else if parser.tok.kind == .String { ret = node_create_value(.String, parser.tok.range, parser.tok.value) parser_next(parser) } else if parser.tok.kind == .Identifier { ret = node_create_value(.Identifier, parser.tok.range, parser.tok.value) parser_next(parser) prev := parser.can_be_function parser.can_be_function = false if accept(parser, .Dot) { ret = node_create_field_access({ ret.range.start, parser.tok.range.start }, ret, parser_parse_factor(parser)) } parser.can_be_function = prev if parser.can_be_function && parser.tok.kind != .CloseParen && parser.tok.kind != .Semicolon && parser.tok.kind != .Arrow && parser.tok.kind != .EOF { 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 && parser_is_factor_token_or_prefix(parser.tok.kind) { append(&args, parser_parse_expression(parser)) } ret = node_create_function_call(ret.range, ret, args) parser.can_be_function = prev } } else if accept(parser, .OpenParen) { prev := parser.can_be_function parser.can_be_function = true ret = parser_parse_expression(parser) parser.can_be_function = prev expect(parser, .CloseParen) } else { append(&g_message_list, message_create(.Error, fmt.aprintf("Unexpected factor token {} at {}", parser.tok.kind, "TODO"), parser.tok.range)) } return }