aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Magnusson <mathias@magnusson.space>2025-08-04 15:28:38 +0200
committerMathias Magnusson <mathias@magnusson.space>2025-08-04 15:28:38 +0200
commit72c7be04a6d4ad126b46a977178a0e6e8d69e308 (patch)
tree381bce03db9d1cd62cad78c5cb6f5aca958db23e
parent2687a6e8b4f527f6641add097faef004f4e9a58f (diff)
downloadhuginn-72c7be04a6d4ad126b46a977178a0e6e8d69e308.tar.gz
Merge parsing all binary operators into one function
-rw-r--r--src/main.zig7
-rw-r--r--src/parse.zig60
2 files changed, 32 insertions, 35 deletions
diff --git a/src/main.zig b/src/main.zig
index 78cc18c..2e89029 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -39,13 +39,6 @@ pub fn main() !u8 {
defer allocator.free(source);
var lexer: Lexer = .{ .source = source };
- std.debug.print(blue ++ "tokens:" ++ normal ++ "\n", .{});
- while (true) {
- const token = lexer.next();
- std.debug.print(" {}\n", .{token});
- if (token.type == .eof) break;
- }
- lexer = .{ .source = source };
const ast = parse.file(allocator, &lexer) catch |err| {
std.debug.print(red ++ "parsing error: {}\n" ++ normal, .{err});
return 1;
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 } },