speedcat/parser.odin

311 lines
9.2 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 {
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_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
}