1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
const std = @import("std");
const Allocator = std.mem.Allocator;
const root = @import("root");
const Lexer = root.Lexer;
const Token = root.Lexer.Token;
const Peekable = root.Peekable;
const peekable = root.peekable;
pub const Expr = struct {
loc: Lexer.Location,
type: Type,
pub const Type = union(enum) {
integer_literal,
bin_op: BinOp,
invalid: Token,
pub const BinOp = struct {
lhs: *const Expr,
rhs: *const Expr,
op: Op,
const Op = enum {
plus,
minus,
};
};
};
};
pub fn expression(allocator: Allocator, lexer: *Peekable(Lexer)) error{OutOfMemory}!*Expr {
return addExpr(allocator, lexer);
}
pub fn addExpr(allocator: Allocator, lexer: *Peekable(Lexer)) !*Expr {
var lhs = try primaryExpr(allocator, lexer);
while (true) {
const token: Lexer.Token = if (lexer.peek()) |t| t else break;
const op: Expr.Type.BinOp.Op = switch (token.type) {
.plus => .plus,
.minus => .minus,
else => break,
};
_ = lexer.next();
const rhs = try primaryExpr(allocator, lexer);
lhs = try allocate(allocator, .{
.loc = lhs.loc.combine(rhs.loc),
.type = .{ .bin_op = .{ .lhs = lhs, .op = op, .rhs = rhs } },
});
}
return lhs;
}
pub fn primaryExpr(allocator: Allocator, lexer: *Peekable(Lexer)) !*Expr {
const token = lexer.next().?;
// std.debug.print("term {}\n", .{token});
return allocate(allocator, switch (token.type) {
.left_paren => {
const res = expression(allocator, lexer);
const right_paren = lexer.next().?;
if (right_paren.type != .right_paren)
return allocate(allocator, .{
.loc = right_paren.loc,
.type = .{ .invalid = right_paren },
});
return res;
},
.integer_literal => .{ .loc = token.loc, .type = .integer_literal },
else => .{ .loc = token.loc, .type = .{ .invalid = token } },
});
}
fn allocate(allocator: Allocator, expr: Expr) !*Expr {
const res = try allocator.create(Expr);
res.* = expr;
return res;
}
|