aboutsummaryrefslogtreecommitdiff
path: root/src/parse.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse.zig')
-rw-r--r--src/parse.zig60
1 files changed, 32 insertions, 28 deletions
diff --git a/src/parse.zig b/src/parse.zig
index f6fc0bc..95a9bc9 100644
--- a/src/parse.zig
+++ b/src/parse.zig
@@ -136,6 +136,26 @@ pub const Expr = struct {
.equal_equal => "==",
});
}
+
+ fn precedence(op: Op) usize {
+ return switch (op) {
+ .plus => 2,
+ .minus => 2,
+ .left_angle => 1,
+ .right_angle => 1,
+ .left_angle_equal => 1,
+ .right_angle_equal => 1,
+ .equal_equal => 1,
+ };
+ }
+
+ fn associativity(prec: usize) enum { left, right, no_chain } {
+ return switch (prec) {
+ 2 => .left,
+ 1 => .no_chain,
+ else => @panic("Non-existing precedence"),
+ };
+ }
};
};
@@ -288,7 +308,7 @@ fn parseReturn(allocator: Allocator, lexer: *Lexer) ParseError!*Expr {
}
fn parseProc(allocator: Allocator, lexer: *Lexer) ParseError!*Expr {
- if (lexer.peek().type != .proc) return parseComparisons(allocator, lexer);
+ if (lexer.peek().type != .proc) return parseBinOps(allocator, lexer, 0);
const proc = try mustEat(lexer, .proc);
_ = try mustEat(lexer, .left_paren);
const param_tok = lexer.next();
@@ -306,37 +326,21 @@ fn parseProc(allocator: Allocator, lexer: *Lexer) ParseError!*Expr {
});
}
-fn parseComparisons(allocator: Allocator, lexer: *Lexer) ParseError!*Expr {
- const lhs = try parseTerms(allocator, lexer);
-
- const op: Expr.Type.BinOp.Op = switch (lexer.peek().type) {
- .left_angle => .left_angle,
- .right_angle => .right_angle,
- .left_angle_equal => .left_angle_equal,
- .right_angle_equal => .right_angle_equal,
- .equal_equal => .equal_equal,
- else => return lhs,
- };
- _ = lexer.next();
-
- const rhs = try parseTerms(allocator, lexer);
- return try allocate(Expr, allocator, .{
- .loc = lhs.loc.combine(rhs.loc),
- .type = .{ .bin_op = .{ .lhs = lhs, .op = op, .rhs = rhs } },
- });
-}
-
-fn parseTerms(allocator: Allocator, lexer: *Lexer) !*Expr {
+fn parseBinOps(allocator: Allocator, lexer: *Lexer, precedence: usize) ParseError!*Expr {
var lhs = try parseIf(allocator, lexer);
while (true) {
- const op: Expr.Type.BinOp.Op = switch (lexer.peek().type) {
- .plus => .plus,
- .minus => .minus,
- else => break,
+ const op = std.meta.stringToEnum(Expr.Type.BinOp.Op, @tagName(lexer.peek().type)) orelse return lhs;
+ if (op.precedence() < precedence) break;
+ if (op.precedence() == precedence) switch (@TypeOf(op).associativity(precedence)) {
+ .left => break,
+ .right => continue,
+ .no_chain => {
+ std.debug.print("Operator {s} may not be chained here\n", .{@tagName(op)});
+ return error.UnexpectedToken;
+ },
};
_ = lexer.next();
-
- const rhs = try parseIf(allocator, lexer);
+ const rhs = try parseBinOps(allocator, lexer, op.precedence());
lhs = try allocate(Expr, allocator, .{
.loc = lhs.loc.combine(rhs.loc),
.type = .{ .bin_op = .{ .lhs = lhs, .op = op, .rhs = rhs } },