summaryrefslogtreecommitdiff
path: root/src/estd/parser/root.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/estd/parser/root.zig')
-rw-r--r--src/estd/parser/root.zig408
1 files changed, 204 insertions, 204 deletions
diff --git a/src/estd/parser/root.zig b/src/estd/parser/root.zig
index b168a88..ffead8f 100644
--- a/src/estd/parser/root.zig
+++ b/src/estd/parser/root.zig
@@ -5,280 +5,280 @@ pub const Context = @import("context.zig").Context;
pub fn ParseFn(comptime I: type, comptime O: type) type {
- return *const fn (ctx: *Context(I)) anyerror!O;
+ return *const fn (ctx: *Context(I)) anyerror!O;
}
pub fn Parser(comptime I: type, comptime O: type, comptime parse_fn: ParseFn(I, O)) type {
- return struct {
- const Self = @This();
+ return struct {
+ const Self = @This();
- pub fn parse(ctx: *Context(I)) !O {
- return try parse_fn(ctx);
- }
+ pub fn parse(ctx: *Context(I)) !O {
+ return try parse_fn(ctx);
+ }
- pub fn or_else(comptime other: ParseFn(I, O)) type {
- return Parser(I, O, struct {
- pub fn parse(ctx: *Context(I)) !O {
- return parse_fn(ctx) catch other(ctx);
- }
- }.parse);
- }
+ pub fn or_else(comptime other: ParseFn(I, O)) type {
+ return Parser(I, O, struct {
+ pub fn parse(ctx: *Context(I)) !O {
+ return parse_fn(ctx) catch other(ctx);
+ }
+ }.parse);
+ }
- pub fn and_skip(comptime skip: anytype) type {
- return Parser(I, O, struct {
- pub fn parse(ctx: *Context(I)) !O {
- const snapshot = ctx.cursor.snapshot();
- errdefer ctx.cursor.rollback(snapshot);
+ pub fn and_skip(comptime skip: anytype) type {
+ return Parser(I, O, struct {
+ pub fn parse(ctx: *Context(I)) !O {
+ const snapshot = ctx.cursor.snapshot();
+ errdefer ctx.cursor.rollback(snapshot);
- _ = try skip(ctx);
- return try parse_fn(ctx);
- }
- }.parse);
- }
+ _ = try skip(ctx);
+ return try parse_fn(ctx);
+ }
+ }.parse);
+ }
- pub fn then_skip(comptime skip: anytype) type {
- return Parser(I, O, struct {
- pub fn parse(ctx: *Context(I)) !O {
- const snapshot = ctx.cursor.snapshot();
- errdefer ctx.cursor.rollback(snapshot);
- const value = try parse_fn(ctx);
- _ = try skip(ctx);
- return value;
- }
- }.parse);
- }
+ pub fn then_skip(comptime skip: anytype) type {
+ return Parser(I, O, struct {
+ pub fn parse(ctx: *Context(I)) !O {
+ const snapshot = ctx.cursor.snapshot();
+ errdefer ctx.cursor.rollback(snapshot);
+ const value = try parse_fn(ctx);
+ _ = try skip(ctx);
+ return value;
+ }
+ }.parse);
+ }
- pub fn then(comptime O2: type, comptime other: ParseFn(I, O2)) type {
- const CombinedOutput = struct { O, O2 };
+ pub fn then(comptime O2: type, comptime other: ParseFn(I, O2)) type {
+ const CombinedOutput = struct { O, O2 };
- return Parser(I, CombinedOutput, struct {
- pub fn parse(ctx: *Context(I)) !CombinedOutput {
- const snapshot = ctx.cursor.snapshot();
- errdefer ctx.cursor.rollback(snapshot);
+ return Parser(I, CombinedOutput, struct {
+ pub fn parse(ctx: *Context(I)) !CombinedOutput {
+ const snapshot = ctx.cursor.snapshot();
+ errdefer ctx.cursor.rollback(snapshot);
- return .{ try parse_fn(ctx), try other(ctx) };
- }
- }.parse);
- }
+ return .{ try parse_fn(ctx), try other(ctx) };
+ }
+ }.parse);
+ }
- pub fn zero_or_more() type {
- return Parser(I, std.ArrayList(O), struct {
- pub fn parse(ctx: *Context(I)) !std.ArrayList(O) {
- var values = std.ArrayList(O).init(ctx.allocator);
- errdefer values.deinit();
+ pub fn zero_or_more() type {
+ return Parser(I, std.ArrayList(O), struct {
+ pub fn parse(ctx: *Context(I)) !std.ArrayList(O) {
+ var values = std.ArrayList(O).init(ctx.allocator);
+ errdefer values.deinit();
- while (parse_fn(ctx)) |value| {
- try values.append(value);
- } else |_| {}
+ while (parse_fn(ctx)) |value| {
+ try values.append(value);
+ } else |_| {}
- return values;
- }
- }.parse);
- }
+ return values;
+ }
+ }.parse);
+ }
- pub fn repeat(n: usize) type {
- return Parser(I, [n]O, struct {
- pub fn parse(ctx: *Context(I)) ![n]O {
- const snapshot = ctx.cursor.snapshot();
- errdefer ctx.cursor.rollback(snapshot);
+ pub fn repeat(n: usize) type {
+ return Parser(I, [n]O, struct {
+ pub fn parse(ctx: *Context(I)) ![n]O {
+ const snapshot = ctx.cursor.snapshot();
+ errdefer ctx.cursor.rollback(snapshot);
- var values: [n]O = undefined;
+ var values: [n]O = undefined;
- for (&values) |*value| {
- value.* = try parse_fn(ctx);
- }
+ for (&values) |*value| {
+ value.* = try parse_fn(ctx);
+ }
- return values;
- }
- }.parse);
- }
+ return values;
+ }
+ }.parse);
+ }
- pub fn map(M: type, map_fn: *const fn (value: O) M) type {
- return Parser(I, M, struct {
- pub fn parse(ctx: *Context(I)) !M {
- return map_fn(try parse_fn(ctx));
- }
- }.parse);
- }
+ pub fn map(M: type, map_fn: *const fn (value: O) M) type {
+ return Parser(I, M, struct {
+ pub fn parse(ctx: *Context(I)) !M {
+ return map_fn(try parse_fn(ctx));
+ }
+ }.parse);
+ }
- pub fn end() type {
- return Parser(I, O, struct {
- pub fn parse(ctx: *Context(I)) !O {
- const value = try parse_fn(ctx);
- _ = ctx.cursor.peek(1) catch return value;
- return error.NotEnd;
- }
- }.parse);
- }
- };
+ pub fn end() type {
+ return Parser(I, O, struct {
+ pub fn parse(ctx: *Context(I)) !O {
+ const value = try parse_fn(ctx);
+ _ = ctx.cursor.peek(1) catch return value;
+ return error.NotEnd;
+ }
+ }.parse);
+ }
+};
}
fn parse_zero(ctx: *Context(u8)) !u8 {
- const snapshot = ctx.cursor.snapshot();
- errdefer ctx.cursor.rollback(snapshot);
+ const snapshot = ctx.cursor.snapshot();
+ errdefer ctx.cursor.rollback(snapshot);
- const value = try ctx.cursor.consume(1);
+ const value = try ctx.cursor.consume(1);
- if (value[0] == '0') {
- return 0;
- }
+ if (value[0] == '0') {
+ return 0;
+ }
- return error.NotZero;
+ return error.NotZero;
}
fn parse_one(ctx: *Context(u8)) !u8 {
- const snapshot = ctx.cursor.snapshot();
- errdefer ctx.cursor.rollback(snapshot);
+ const snapshot = ctx.cursor.snapshot();
+ errdefer ctx.cursor.rollback(snapshot);
- const value = try ctx.cursor.consume(1);
+ const value = try ctx.cursor.consume(1);
- if (value[0] == '1') {
- return 1;
- }
+ if (value[0] == '1') {
+ return 1;
+ }
- return error.NotOne;
+ return error.NotOne;
}
test "direct" {
- const ZeroParser = Parser(u8, u8, parse_zero);
+ const ZeroParser = Parser(u8, u8, parse_zero);
- var ctx = Context(u8) {
- .cursor = Cursor(u8).init("0"),
- .allocator = std.testing.allocator,
- };
- try std.testing.expectEqual(0, try ZeroParser.parse(&ctx));
+ var ctx = Context(u8) {
+ .cursor = Cursor(u8).init("0"),
+ .allocator = std.testing.allocator,
+};
+try std.testing.expectEqual(0, try ZeroParser.parse(&ctx));
- ctx.cursor = Cursor(u8).init("1");
- try std.testing.expectError(error.NotZero, ZeroParser.parse(&ctx));
+ctx.cursor = Cursor(u8).init("1");
+try std.testing.expectError(error.NotZero, ZeroParser.parse(&ctx));
}
test "or_else" {
- const ZeroParser = Parser(u8, u8, parse_zero);
- const ZeroAndOneParser = ZeroParser.or_else(parse_one);
+ const ZeroParser = Parser(u8, u8, parse_zero);
+ const ZeroAndOneParser = ZeroParser.or_else(parse_one);
- var ctx = Context(u8) {
- .cursor = Cursor(u8).init("0"),
- .allocator = std.testing.allocator,
- };
- try std.testing.expectEqual(0, try ZeroAndOneParser.parse(&ctx));
+ var ctx = Context(u8) {
+ .cursor = Cursor(u8).init("0"),
+ .allocator = std.testing.allocator,
+};
+try std.testing.expectEqual(0, try ZeroAndOneParser.parse(&ctx));
- ctx.cursor = Cursor(u8).init("1");
- try std.testing.expectEqual(1, try ZeroAndOneParser.parse(&ctx));
+ctx.cursor = Cursor(u8).init("1");
+try std.testing.expectEqual(1, try ZeroAndOneParser.parse(&ctx));
- ctx.cursor = Cursor(u8).init("2");
- try std.testing.expectError(error.NotZero, ZeroParser.parse(&ctx));
+ctx.cursor = Cursor(u8).init("2");
+try std.testing.expectError(error.NotZero, ZeroParser.parse(&ctx));
}
test "then" {
- const ZeroParser = Parser(u8, u8, parse_zero);
- const ZeroThenOneParser = ZeroParser.then(u8, parse_one);
+ const ZeroParser = Parser(u8, u8, parse_zero);
+ const ZeroThenOneParser = ZeroParser.then(u8, parse_one);
- var ctx = Context(u8) {
- .cursor = Cursor(u8).init("01"),
- .allocator = std.testing.allocator,
- };
- try std.testing.expectEqual(.{ 0, 1 }, try ZeroThenOneParser.parse(&ctx));
+ var ctx = Context(u8) {
+ .cursor = Cursor(u8).init("01"),
+ .allocator = std.testing.allocator,
+};
+try std.testing.expectEqual(.{ 0, 1 }, try ZeroThenOneParser.parse(&ctx));
- ctx.cursor = Cursor(u8).init("11");
- try std.testing.expectError(error.NotZero, ZeroThenOneParser.parse(&ctx));
+ctx.cursor = Cursor(u8).init("11");
+try std.testing.expectError(error.NotZero, ZeroThenOneParser.parse(&ctx));
- ctx.cursor = Cursor(u8).init("00");
- try std.testing.expectError(error.NotOne, ZeroThenOneParser.parse(&ctx));
+ctx.cursor = Cursor(u8).init("00");
+try std.testing.expectError(error.NotOne, ZeroThenOneParser.parse(&ctx));
}
test "zero_or_more" {
- const ZeroParser = Parser(u8, u8, parse_zero);
- const ZeroWildcardParser = ZeroParser.zero_or_more();
- const ZeroOrOneWildcardParser = ZeroParser.or_else(parse_one).zero_or_more();
+ const ZeroParser = Parser(u8, u8, parse_zero);
+ const ZeroWildcardParser = ZeroParser.zero_or_more();
+ const ZeroOrOneWildcardParser = ZeroParser.or_else(parse_one).zero_or_more();
- var ctx = Context(u8) {
- .cursor = Cursor(u8).init("0000"),
- .allocator = std.testing.allocator,
- };
- var result = try ZeroWildcardParser.parse(&ctx);
- try std.testing.expectEqualSlices(u8, &[_]u8{0, 0, 0, 0}, result.items);
- result.deinit();
+ var ctx = Context(u8) {
+ .cursor = Cursor(u8).init("0000"),
+ .allocator = std.testing.allocator,
+};
+var result = try ZeroWildcardParser.parse(&ctx);
+try std.testing.expectEqualSlices(u8, &[_]u8{0, 0, 0, 0}, result.items);
+result.deinit();
- ctx.cursor = Cursor(u8).init("00001");
- result = try ZeroWildcardParser.parse(&ctx);
- try std.testing.expectEqualSlices(u8, &[_]u8{0, 0, 0, 0}, result.items);
- result.deinit();
+ctx.cursor = Cursor(u8).init("00001");
+result = try ZeroWildcardParser.parse(&ctx);
+try std.testing.expectEqualSlices(u8, &[_]u8{0, 0, 0, 0}, result.items);
+result.deinit();
- ctx.cursor = Cursor(u8).init("0101110");
- result = try ZeroOrOneWildcardParser.parse(&ctx);
- try std.testing.expectEqualSlices(u8, &[_]u8{0, 1, 0, 1, 1, 1, 0}, result.items);
- result.deinit();
+ctx.cursor = Cursor(u8).init("0101110");
+result = try ZeroOrOneWildcardParser.parse(&ctx);
+try std.testing.expectEqualSlices(u8, &[_]u8{0, 1, 0, 1, 1, 1, 0}, result.items);
+result.deinit();
- ctx.cursor = Cursor(u8).init("0101110abc");
- result = try ZeroOrOneWildcardParser.parse(&ctx);
- try std.testing.expectEqualSlices(u8, &[_]u8{0, 1, 0, 1, 1, 1, 0}, result.items);
- result.deinit();
+ctx.cursor = Cursor(u8).init("0101110abc");
+result = try ZeroOrOneWildcardParser.parse(&ctx);
+try std.testing.expectEqualSlices(u8, &[_]u8{0, 1, 0, 1, 1, 1, 0}, result.items);
+result.deinit();
}
test "repeat" {
- const ZeroParser = Parser(u8, u8, parse_zero);
- const FourZerosParser = ZeroParser.repeat(4);
+ const ZeroParser = Parser(u8, u8, parse_zero);
+ const FourZerosParser = ZeroParser.repeat(4);
- var ctx = Context(u8) {
- .cursor = Cursor(u8).init("00001"),
- .allocator = std.testing.allocator,
- };
- try std.testing.expectEqualSlices(
- u8,
- &[_]u8{0, 0, 0, 0},
- &(try FourZerosParser.parse(&ctx))
- );
+ var ctx = Context(u8) {
+ .cursor = Cursor(u8).init("00001"),
+ .allocator = std.testing.allocator,
+};
+try std.testing.expectEqualSlices(
+ u8,
+ &[_]u8{0, 0, 0, 0},
+ &(try FourZerosParser.parse(&ctx))
+);
- ctx.cursor = Cursor(u8).init("0001");
- try std.testing.expectError(
- error.NotZero,
- FourZerosParser.parse(&ctx)
- );
-}
+ ctx.cursor = Cursor(u8).init("0001");
+try std.testing.expectError(
+ error.NotZero,
+ FourZerosParser.parse(&ctx)
+);
+ }
test "map" {
- const ZeroOrOneParser = Parser(u8, u8, parse_zero).or_else(parse_one);
- const ZeroOrOneMappedParser = ZeroOrOneParser.map(u8, struct {
- pub fn map(i: u8) u8 {
- return i * 2;
- }
- }.map).zero_or_more();
+ const ZeroOrOneParser = Parser(u8, u8, parse_zero).or_else(parse_one);
+ const ZeroOrOneMappedParser = ZeroOrOneParser.map(u8, struct {
+ pub fn map(i: u8) u8 {
+ return i * 2;
+ }
+ }.map).zero_or_more();
- var ctx = Context(u8) {
- .cursor = Cursor(u8).init("00110101"),
- .allocator = std.testing.allocator,
- };
- const result = try ZeroOrOneMappedParser.parse(&ctx);
- try std.testing.expectEqualSlices(u8, &[_]u8{ 0, 0, 2, 2, 0, 2, 0, 2 }, result.items);
- defer result.deinit();
+ var ctx = Context(u8) {
+ .cursor = Cursor(u8).init("00110101"),
+ .allocator = std.testing.allocator,
+};
+const result = try ZeroOrOneMappedParser.parse(&ctx);
+try std.testing.expectEqualSlices(u8, &[_]u8{ 0, 0, 2, 2, 0, 2, 0, 2 }, result.items);
+defer result.deinit();
}
test "cursor rollback" {
- const DoubleZeroOrOneParser = Parser(u8, u8, parse_zero).repeat(3).or_else(
- Parser(u8, u8, parse_zero).repeat(2).then(u8, parse_one).map([3]u8, struct {
- pub fn map(r: struct { [2]u8, u8 }) [3]u8 {
- const array, const last = r;
- return array ++ .{ last };
- }
- }.map).parse
- );
- var ctx = Context(u8) {
- .cursor = Cursor(u8).init("0001"),
- .allocator = std.testing.allocator,
- };
- try std.testing.expectEqualSlices(u8, &[_]u8{ 0, 0, 0 }, &(try DoubleZeroOrOneParser.parse(&ctx)));
+ const DoubleZeroOrOneParser = Parser(u8, u8, parse_zero).repeat(3).or_else(
+ Parser(u8, u8, parse_zero).repeat(2).then(u8, parse_one).map([3]u8, struct {
+ pub fn map(r: struct { [2]u8, u8 }) [3]u8 {
+ const array, const last = r;
+ return array ++ .{ last };
+ }
+ }.map).parse
+ );
+ var ctx = Context(u8) {
+ .cursor = Cursor(u8).init("0001"),
+ .allocator = std.testing.allocator,
+};
+try std.testing.expectEqualSlices(u8, &[_]u8{ 0, 0, 0 }, &(try DoubleZeroOrOneParser.parse(&ctx)));
- ctx.cursor = Cursor(u8).init("0010");
- try std.testing.expectEqualSlices(u8, &[_]u8{ 0, 0, 1 }, &(try DoubleZeroOrOneParser.parse(&ctx)));
+ctx.cursor = Cursor(u8).init("0010");
+try std.testing.expectEqualSlices(u8, &[_]u8{ 0, 0, 1 }, &(try DoubleZeroOrOneParser.parse(&ctx)));
}
test "cursor error touched slice" {
- const OneThenDoubleZeroParser = Parser(u8, u8, parse_one).then([2]u8, Parser(u8, u8, parse_zero).repeat(2).parse);
- var ctx = Context(u8) {
- .cursor = Cursor(u8).init("10110"),
- .allocator = std.testing.allocator,
- };
- try std.testing.expectError(error.NotZero, OneThenDoubleZeroParser.parse(&ctx));
- try std.testing.expectEqualSlices(u8, "101", ctx.cursor.touched_slice());
+ const OneThenDoubleZeroParser = Parser(u8, u8, parse_one).then([2]u8, Parser(u8, u8, parse_zero).repeat(2).parse);
+ var ctx = Context(u8) {
+ .cursor = Cursor(u8).init("10110"),
+ .allocator = std.testing.allocator,
+};
+try std.testing.expectError(error.NotZero, OneThenDoubleZeroParser.parse(&ctx));
+try std.testing.expectEqualSlices(u8, "101", ctx.cursor.touched_slice());
}