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)
|
try arraylist.append(&renderer.tokens, tok)
|
||||||
yield node.main_token
|
yield node.main_token
|
||||||
}
|
}
|
||||||
|
.expr_unary:
|
||||||
|
try render_expr_unary(renderer, node_id, parse_state, tokens)
|
||||||
.expr_binary:
|
.expr_binary:
|
||||||
try render_expr_binary(renderer, node_id, parse_state, tokens)
|
try render_expr_binary(renderer, node_id, parse_state, tokens)
|
||||||
.literal_int, .literal_float, .literal_string:
|
.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
|
@hide:file
|
||||||
render_expr_binary proc(
|
render_expr_binary proc(
|
||||||
renderer @mut Renderer,
|
renderer @mut Renderer,
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ render_token proc(tok Token, program []u8) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@hide
|
|
||||||
token_id proc(idx uint) TokenId {
|
token_id proc(idx uint) TokenId {
|
||||||
debug.assert(u64(idx) < u64(NO_TOKEN))
|
debug.assert(u64(idx) < u64(NO_TOKEN))
|
||||||
return TokenId(idx)
|
return TokenId(idx)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ program ::
|
|||||||
`z :: "hello"
|
`z :: "hello"
|
||||||
`
|
`
|
||||||
`a := 1 + 2 * 3
|
`a := 1 + 2 * 3
|
||||||
|
`b :: -3 / 2 + 1
|
||||||
|
|
||||||
main proc() void! {
|
main proc() void! {
|
||||||
strpool.STRINGS = strpool.init(mem.c_allocator)
|
strpool.STRINGS = strpool.init(mem.c_allocator)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import "@std"
|
|||||||
import "@std/mem"
|
import "@std/mem"
|
||||||
import "@std/arraylist"
|
import "@std/arraylist"
|
||||||
import "@std/enums/enummap"
|
import "@std/enums/enummap"
|
||||||
|
import "@std/debug"
|
||||||
|
|
||||||
import "@source/lexer"
|
import "@source/lexer"
|
||||||
import "@source/ast"
|
import "@source/ast"
|
||||||
@@ -58,6 +59,9 @@ NO_NODE :: alias ast.NO_NODE
|
|||||||
@hide:file
|
@hide:file
|
||||||
NO_EXTRA :: alias ast.NO_EXTRA
|
NO_EXTRA :: alias ast.NO_EXTRA
|
||||||
|
|
||||||
|
@hide:file
|
||||||
|
token_id :: alias lexer.token_id
|
||||||
|
|
||||||
BindingPowerScalar :: distinct u32
|
BindingPowerScalar :: distinct u32
|
||||||
|
|
||||||
BindingPower :: struct {
|
BindingPower :: struct {
|
||||||
@@ -65,6 +69,13 @@ BindingPower :: struct {
|
|||||||
right BindingPowerScalar
|
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 {
|
infix_binding_power proc(token_kind TokenKind) ?BindingPower {
|
||||||
return match token_kind {
|
return match token_kind {
|
||||||
.plus, .minus: BindingPower{ left = BindingPowerScalar(10), right = BindingPowerScalar(11) }
|
.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 {
|
State :: struct {
|
||||||
nodes std.ArrayList(Node)
|
nodes std.ArrayList(Node)
|
||||||
|
|
||||||
@@ -170,12 +188,45 @@ parse_expr proc(state @mut State) NodeId ! mem.AllocError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parse_expr_bp proc(state @mut State, min_bp BindingPowerScalar) 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| {
|
lhs := if (prefix_binding_power(kind)) |right_bp| {
|
||||||
|
operator :: token_id(state.next_token)
|
||||||
|
state.next_token += 1
|
||||||
|
|
||||||
|
operand :: try parse_expr_bp(state, right_bp)
|
||||||
|
|
||||||
|
yield try add_node(state, Node{
|
||||||
|
kind = .expr_unary,
|
||||||
|
main_token = operator,
|
||||||
|
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
|
if (bp.left < min_bp) break
|
||||||
|
|
||||||
operator :: TokenId(state.next_token)
|
operator :: token_id(state.next_token)
|
||||||
state.next_token += 1
|
state.next_token += 1
|
||||||
|
|
||||||
rhs :: try parse_expr_bp(state, bp.right)
|
rhs :: try parse_expr_bp(state, bp.right)
|
||||||
@@ -185,6 +236,11 @@ parse_expr_bp proc(state @mut State, min_bp BindingPowerScalar) NodeId ! mem.All
|
|||||||
data0 = NodeData{ node_id = lhs },
|
data0 = NodeData{ node_id = lhs },
|
||||||
data1 = NodeData{ node_id = rhs },
|
data1 = NodeData{ node_id = rhs },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return lhs
|
return lhs
|
||||||
|
|||||||
@@ -5,6 +5,12 @@ assert proc(ok bool) void {
|
|||||||
if (!ok) unreachable
|
if (!ok) unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unimplemented proc() noreturn {
|
||||||
|
print("not yet implemented\n", {})
|
||||||
|
c.abort()
|
||||||
|
unreachable
|
||||||
|
}
|
||||||
|
|
||||||
print proc($format []u8, $Args type, args Args) void {
|
print proc($format []u8, $Args type, args Args) void {
|
||||||
writer :: io.Writer{
|
writer :: io.Writer{
|
||||||
context = null,
|
context = null,
|
||||||
|
|||||||
Reference in New Issue
Block a user