speedcat/parser.odin
2024-02-09 14:36:03 +02:00

554 lines
15 KiB
Odin

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 {
if stmt != nil {
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)
} else if parser.tok.kind == .Use {
ret = parser_parse_use_statement(parser)
expect(parser, .Semicolon)
} else if parser.tok.kind == .OpenBrace {
ret = parser_parse_block(parser, .CloseBrace)
} else if parser.tok.kind == .For {
ret = parser_parse_for_statement(parser)
} else if parser.tok.kind == .Function {
ret = parser_parse_function_definition(parser)
} else if parser.tok.kind == .Struct {
ret = parser_parse_struct_definition(parser)
} else if parser.tok.kind == .Enum {
ret = parser_parse_enum_definition(parser)
} else if parser.tok.kind == .Union {
ret = parser_parse_union_definition(parser)
} else {
ret = parser_parse_expression(parser)
expect(parser, .Semicolon)
}
if ret != nil {
ret.range.start = range_beg.start
}
return
}
@(private = "file")
parser_parse_struct_definition :: proc(parser: ^Parser) -> ^Node {
range := parser.tok.range
expect(parser, .Struct)
name: [dynamic]u8
if parser.tok.kind == .Identifier {
name = parser.tok.value.([dynamic]u8)
parser_next(parser)
} else {
expect(parser, .Identifier)
}
expect(parser, .OpenBrace)
fields := parser_parse_definitions(parser, .CloseBrace)
expect(parser, .CloseBrace)
return node_create_struct_enum_or_union(range, .Struct, name, fields)
}
@(private = "file")
parser_parse_enum_definition :: proc(parser: ^Parser) -> ^Node {
range := parser.tok.range
expect(parser, .Enum)
panic("TODO, enum not implemented yet")
}
@(private = "file")
parser_parse_union_definition :: proc(parser: ^Parser) -> ^Node {
range := parser.tok.range
expect(parser, .Union)
name: [dynamic]u8
if parser.tok.kind == .Identifier {
name = parser.tok.value.([dynamic]u8)
parser_next(parser)
} else {
expect(parser, .Identifier)
}
expect(parser, .OpenBrace)
fields := parser_parse_definitions(parser, .CloseBrace)
expect(parser, .CloseBrace)
return node_create_struct_enum_or_union(range, .Union, name, fields)
}
@(private = "file")
parser_parse_function_definition :: proc(parser: ^Parser) -> ^Node {
expect(parser, .Function)
name: [dynamic]u8
if parser.tok.kind == .Identifier {
name = parser.tok.value.([dynamic]u8)
parser_next(parser)
} else {
expect(parser, .Identifier)
}
params: [dynamic]^Node
if accept(parser, .OpenParen) {
params = parser_parse_definitions(parser, .CloseParen)
expect(parser, .CloseParen)
} else {
params = {}
}
type: ^Node = nil
if parser.tok.kind != .OpenBrace {
type = parser_parse_type(parser)
}
expect(parser, .OpenBrace)
body := parser_parse_block(parser, .CloseBrace)
return node_create_function(parser.tok.range, name, type, body, params)
}
@(private = "file")
parser_parse_for_statement :: proc(parser: ^Parser) -> ^Node {
range := parser.tok.range
expect(parser, .For)
if accept(parser, .OpenBrace) {
body := parser_parse_block(parser, .CloseBrace)
return node_create_for(range, nil, nil, nil, body)
}
if parser.tok.kind == .Let {
panic("TODO, let in for not implemented yet")
}
init := parser_parse_expression(parser)
if accept(parser, .OpenBrace) {
body := parser_parse_block(parser, .CloseBrace)
return node_create_for(range, nil, init, nil, body)
}
expect(parser, .Semicolon)
condition: ^Node = nil
if parser.tok.kind != .Semicolon {
condition = parser_parse_expression(parser)
}
expect(parser, .Semicolon)
if accept(parser, .OpenBrace) {
body := parser_parse_block(parser, .CloseBrace)
return node_create_for(range, init, condition, nil, body)
}
after := parser_parse_expression(parser)
expect(parser, .OpenBrace)
body := parser_parse_block(parser, .CloseBrace)
return node_create_for(range, init, condition, after, body)
}
@(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 ..< len(names) {
value: ^Node = nil
if uninitialized == false {
value = parser_parse_expression(parser)
}
name_node := node_create_value(.Identifier, range, names[i])
append(&vars, node_create_variable(range, name_node, type, value, are_constants))
}
if !accept(parser, .Comma) {
break
}
type = nil
are_constants = false
uninitialized = false
}
return vars
}
@(private = "file")
parser_parse_use_statement :: proc(parser: ^Parser) -> ^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
}