diff options
author | Mathias Magnusson <mathias@magnusson.space> | 2025-08-04 15:28:38 +0200 |
---|---|---|
committer | Mathias Magnusson <mathias@magnusson.space> | 2025-08-04 15:28:38 +0200 |
commit | 72c7be04a6d4ad126b46a977178a0e6e8d69e308 (patch) | |
tree | 381bce03db9d1cd62cad78c5cb6f5aca958db23e /src/parse.zig | |
parent | 2687a6e8b4f527f6641add097faef004f4e9a58f (diff) | |
download | huginn-72c7be04a6d4ad126b46a977178a0e6e8d69e308.tar.gz |
Merge parsing all binary operators into one function
Diffstat (limited to 'src/parse.zig')
-rw-r--r-- | src/parse.zig | 60 |
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 } }, |