parse unary prefix and postfix expressions

This commit is contained in:
2026-08-12 20:50:51 +02:00
parent a384949ddf
commit 8fbf137c6d
5 changed files with 93 additions and 11 deletions
+20
View File
@@ -116,6 +116,8 @@ render_expr proc(renderer @mut Renderer,
try arraylist.append(&renderer.tokens, tok)
yield node.main_token
}
.expr_unary:
try render_expr_unary(renderer, node_id, parse_state, tokens)
.expr_binary:
try render_expr_binary(renderer, node_id, parse_state, tokens)
.literal_int, .literal_float, .literal_string:
@@ -124,6 +126,24 @@ render_expr proc(renderer @mut Renderer,
}
}
@hide:file
render_expr_unary proc(
renderer @mut Renderer,
node_id NodeId,
parse_state @ParseState,
tokens []Token,
) TokenId ! mem.AllocError {
node :: parse_state.nodes.items[usize(node_id)]
operator :: node.main_token
operand :: node.data0.node_id
# render operator operand
try arraylist.append(&renderer.tokens, tokens[usize(operator)])
last_token :: try render_expr(renderer, operand, parse_state, tokens)
return last_token
}
@hide:file
render_expr_binary proc(
renderer @mut Renderer,
-1
View File
@@ -75,7 +75,6 @@ render_token proc(tok Token, program []u8) void {
}
}
@hide
token_id proc(idx uint) TokenId {
debug.assert(u64(idx) < u64(NO_TOKEN))
return TokenId(idx)
+1
View File
@@ -24,6 +24,7 @@ program ::
`z :: "hello"
`
`a := 1 + 2 * 3
`b :: -3 / 2 + 1
main proc() void! {
strpool.STRINGS = strpool.init(mem.c_allocator)
+66 -10
View File
@@ -2,6 +2,7 @@ import "@std"
import "@std/mem"
import "@std/arraylist"
import "@std/enums/enummap"
import "@std/debug"
import "@source/lexer"
import "@source/ast"
@@ -58,6 +59,9 @@ NO_NODE :: alias ast.NO_NODE
@hide:file
NO_EXTRA :: alias ast.NO_EXTRA
@hide:file
token_id :: alias lexer.token_id
BindingPowerScalar :: distinct u32
BindingPower :: struct {
@@ -65,6 +69,13 @@ BindingPower :: struct {
right BindingPowerScalar
}
prefix_binding_power proc(token_kind TokenKind) ?BindingPowerScalar {
return match token_kind {
.minus: BindingPowerScalar(30)
else: null
}
}
infix_binding_power proc(token_kind TokenKind) ?BindingPower {
return match token_kind {
.plus, .minus: BindingPower{ left = BindingPowerScalar(10), right = BindingPowerScalar(11) }
@@ -73,6 +84,13 @@ infix_binding_power proc(token_kind TokenKind) ?BindingPower {
}
}
postfix_binding_power proc(token_kind TokenKind) ?BindingPowerScalar {
return match token_kind {
.open_paren, .open_bracket: BindingPowerScalar(40)
else: null
}
}
State :: struct {
nodes std.ArrayList(Node)
@@ -170,21 +188,59 @@ parse_expr proc(state @mut State) NodeId ! mem.AllocError {
}
parse_expr_bp proc(state @mut State, min_bp BindingPowerScalar) NodeId ! mem.AllocError {
lhs := try parse_primary(state)
# parse left-hand side
kind := state.tokens[state.next_token].kind
while infix_binding_power(state.tokens[state.next_token].kind) |bp| {
if (bp.left < min_bp) break
operator :: TokenId(state.next_token)
lhs := if (prefix_binding_power(kind)) |right_bp| {
operator :: token_id(state.next_token)
state.next_token += 1
rhs :: try parse_expr_bp(state, bp.right)
lhs = try add_node(state, Node{
kind = .expr_binary,
operand :: try parse_expr_bp(state, right_bp)
yield try add_node(state, Node{
kind = .expr_unary,
main_token = operator,
data0 = NodeData{ node_id = lhs },
data1 = NodeData{ node_id = rhs },
data0 = NodeData{ node_id = operand },
})
} else {
yield try parse_primary(state)
}
# parse right-hand side
while true {
kind = state.tokens[state.next_token].kind
# try postfix (higher precedence)
if postfix_binding_power(kind) |left_bp| {
if (left_bp < min_bp) break
lhs = match state.tokens[state.next_token].kind {
.open_paren: debug.unimplemented() # todo: parse call
.open_bracket: debug.unimplemented() # todo: parse index
else: unreachable
}
continue
}
# try infex (lower precedence)
if infix_binding_power(kind) |bp| {
if (bp.left < min_bp) break
operator :: token_id(state.next_token)
state.next_token += 1
rhs :: try parse_expr_bp(state, bp.right)
lhs = try add_node(state, Node{
kind = .expr_binary,
main_token = operator,
data0 = NodeData{ node_id = lhs },
data1 = NodeData{ node_id = rhs },
})
continue
}
break
}
return lhs
+6
View File
@@ -5,6 +5,12 @@ assert proc(ok bool) void {
if (!ok) unreachable
}
unimplemented proc() noreturn {
print("not yet implemented\n", {})
c.abort()
unreachable
}
print proc($format []u8, $Args type, args Args) void {
writer :: io.Writer{
context = null,