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