Files
honey/source/parser/parser.hon
T
2026-08-02 22:52:55 +02:00

214 lines
5.2 KiB
Plaintext

import "@std"
import "@std/mem"
import "@std/arraylist"
import "@std/debug"
import "@std/enums/enummap"
import "@source/lexer"
NodeId :: distinct u32
ExtraId :: distinct u32
NO_ID_NODE :: maxval!(NodeId)
NO_ID_EXTRA :: maxval!(ExtraId)
# todo: move error stuff into a separate file
Diagnostic :: struct {
code ErrorCode
node NodeId
}
ParseError :: alias ErrorCode | mem.AllocError
ErrorCode :: enum {
unexpected_token,
}
ErrorDetails :: struct {
name []u8
message []u8
}
error_msg_map std.EnumMap(ErrorCode, ErrorDetails) :: enummap.init({
unexpected_token = ErrorDetails {
name = "P0",
message = "unexpected token",
},
})
hide Token :: alias lexer.Token
hide TokenId :: alias lexer.TokenId
hide TokenKind :: alias lexer.TokenKind
NodeData :: union {
token_id TokenId
node_id NodeId
extra_id ExtraId
}
Node :: struct {
kind NodeKind
main_token TokenId
data0 NodeData = NodeData{ node_id = NO_ID_NODE }
data1 NodeData = NodeData{ node_id = NO_ID_NODE }
}
NodeKind :: enum {
# LITERALS:
# * main_token: token literal
literal_int
literal_float
literal_string
# IDENTIFIER EXPR:
# * main_token: token literal
expr_identifier
expr_unary
expr_binary
# DECL:
# * main_token: symbol name (identifier)
# * data0: ExtraId
# + extra[data0]: NodeId - type identifier node
# + extra[data0 + 1]: NodeId - initializer expression
# * data1: TokenId of either `::` or `=` indicating mutability
stmt_decl
invalid
}
State :: struct {
nodes std.ArrayList(Node)
#! array of raw u32's indexing nodes, tokens, etc.
extra std.ArrayList(u32)
tokens []Token = &[]
next_token TokenId = TokenId(0)
}
init proc(allocator mem.Allocator) State {
return State{
nodes = arraylist.init(allocator),
extra = arraylist.init(allocator),
}
}
deinit proc(state @mut State) void {
arraylist.deinit(&state.nodes)
arraylist.deinit(&state.extra)
}
parse proc(state @mut State, tokens []Token) void ! ParseError {
state.tokens = tokens
_ = try parse_decl(state)
}
parse_decl proc(state @mut State) NodeId ! ParseError {
# expect identifier
try expect(state, .ident)
ident_token :: state.next_token
state.next_token += 1
# check for type
# todo: make a parse_type proc for this
type_id :: if (state.tokens[state.next_token].kind == .ident)
try parse_primary(state)
else
NO_ID_NODE
# expect `::` (immutable assignment)
mutability_tok_id :: try consume(state, .double_colon)
# expect expression
expr_id :: try parse_primary(state)
# expect statement terminator (newline)
_ = try consume_either(state, &[.newline, .eof])
extra_start :: try add_extra(&state.extra, u32(type_id))
_ = try add_extra(&state.extra, u32(expr_id))
decl :: try add_node(&state.nodes, Node{
kind = .stmt_decl,
main_token = ident_token,
data0 = NodeData{ extra_id = extra_start },
data1 = NodeData{ token_id = mutability_tok_id },
})
return decl
}
parse_primary proc(state @mut State) NodeId ! mem.AllocError {
start_token :: state.next_token
state.next_token += 1
return match state.tokens[start_token].kind {
.int: try add_node(&state.nodes, Node{
kind = .literal_int,
main_token = start_token,
})
.float: try add_node(&state.nodes, Node{
kind = .literal_float,
main_token = start_token,
})
.string: try add_node(&state.nodes, Node{
kind = .literal_string,
main_token = start_token,
})
.ident: try add_node(&state.nodes, Node{
kind = .expr_identifier,
main_token = start_token,
})
else: try add_node(&state.nodes, Node{
kind = .invalid,
main_token = start_token,
})
}
}
hide expect proc(state @mut State, token_kind TokenKind) void ! ErrorCode {
if (state.tokens[state.next_token].kind != token_kind) return .unexpected_token
}
hide expect_either proc(state @mut State, token_kinds []TokenKind) void ! ErrorCode {
for (token_kinds) |kind| if (state.tokens[state.next_token].kind == kind) return
return .unexpected_token
}
hide consume proc(state @mut State, token_kind TokenKind) TokenId ! ErrorCode {
try expect(state, token_kind)
state.next_token += 1
return state.next_token - 1
}
hide consume_either proc(state @mut State, token_kinds []TokenKind) TokenId ! ErrorCode {
try expect_either(state, token_kinds)
state.next_token += 1
return state.next_token - 1
}
hide add_node proc(nodes @mut std.ArrayList(Node), node Node) NodeId ! mem.AllocError {
id :: node_id(nodes.items.len)
try arraylist.append(nodes, node)
return id
}
hide node_id proc(idx uint) NodeId {
debug.assert(u64(idx) < u64(NO_ID_NODE))
return NodeId(idx)
}
hide add_extra proc(extra @mut std.ArrayList(u32), idx u32) ExtraId ! mem.AllocError {
id :: extra_id(extra.items.len)
try arraylist.append(extra, idx)
return id
}
hide extra_id proc(idx uint) ExtraId {
debug.assert(u64(idx) < u64(NO_ID_EXTRA))
return ExtraId(idx)
}