-
-
Notifications
You must be signed in to change notification settings - Fork 29
Expand file tree
/
Copy pathexpression.zig
More file actions
107 lines (82 loc) · 2.84 KB
/
Copy pathexpression.zig
File metadata and controls
107 lines (82 loc) · 2.84 KB
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
const mecha = @import("mecha");
const std = @import("std");
const testing = std.testing;
const expression = mecha.expression;
fn parserResult(comptime P: type) type {
return switch (@typeInfo(P)) {
.pointer => |p| p.child.T,
else => P.T,
};
}
const Ops = struct {
fn add(a: i32, b: i32) i32 {
return a + b;
}
fn sub(a: i32, b: i32) i32 {
return a - b;
}
fn mul(a: i32, b: i32) i32 {
return a * b;
}
fn div(a: i32, b: i32) i32 {
return @divTrunc(a, b);
}
fn pow(a: i32, b: i32) i32 {
return std.math.powi(i32, a, @intCast(b)) catch unreachable;
}
fn neg(v: i32) i32 {
return -v;
}
fn inc(v: i32) i32 {
return v + 1;
}
};
const ws = mecha.ascii.char(' ').discard().many(.{ .collect = false }).discard();
fn token(comptime p: anytype) mecha.Parser(parserResult(@TypeOf(p))) {
return mecha.combine(.{ ws, p, ws });
}
const num = token(mecha.int(i32, .{}));
const atom = num;
const prefix_ops = .{
expression.BinaryOp(i32).withPrefix(token(mecha.ascii.char('-')).mapConst(&Ops.neg)),
};
const postfix_ops = .{
expression.BinaryOp(i32).withPostfix(token(mecha.ascii.char('!')).mapConst(&Ops.inc)),
};
const power_ops = .{
expression.addBinaryOp(token(mecha.ascii.char('^')).mapConst(&Ops.pow), .right),
};
const mul_div_ops = .{
expression.addBinaryOp(token(mecha.ascii.char('*')).mapConst(&Ops.mul), .left),
expression.addBinaryOp(token(mecha.ascii.char('/')).mapConst(&Ops.div), .left),
};
const add_sub_ops = .{
expression.addBinaryOp(token(mecha.ascii.char('+')).mapConst(&Ops.add), .left),
expression.addBinaryOp(token(mecha.ascii.char('-')).mapConst(&Ops.sub), .left),
};
const parser = expression.binaryOp(
.{ prefix_ops, postfix_ops, power_ops, mul_div_ops, add_sub_ops },
atom,
);
fn parseExpression(allocator: std.mem.Allocator, input: []const u8) !i32 {
const result = try parser.parse(allocator, input);
return switch (result.value) {
.ok => |value| if (result.index == input.len) value else error.PartialParse,
.err => error.ParseError,
};
}
test "binaryOp basic" {
const allocator = testing.allocator;
try testing.expectEqual(@as(i32, 42), try parseExpression(allocator, "42"));
try testing.expectEqual(@as(i32, 7), try parseExpression(allocator, "1 + 2 * 3"));
try testing.expectEqual(@as(i32, 9), try parseExpression(allocator, "1 + 2 * 4"));
}
test "binaryOp prefix postfix" {
const allocator = testing.allocator;
try testing.expectEqual(@as(i32, -2), try parseExpression(allocator, "-3!"));
try testing.expectEqual(@as(i32, 9), try parseExpression(allocator, "2! * 3"));
}
test "binaryOp right associative" {
const allocator = testing.allocator;
try testing.expectEqual(@as(i32, 512), try parseExpression(allocator, "2 ^ 3 ^ 2"));
}