parse unary prefix and postfix expressions
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user