554 lines
15 KiB
Odin
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
|
|
}
|