From 72c7be04a6d4ad126b46a977178a0e6e8d69e308 Mon Sep 17 00:00:00 2001 From: Mathias Magnusson Date: Mon, 4 Aug 2025 15:28:38 +0200 Subject: Merge parsing all binary operators into one function --- src/parse.zig | 60 +++++++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 28 deletions(-) (limited to 'src/parse.zig') 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 } }, -- cgit v1.2.3