diff options
Diffstat (limited to 'src/estd/parser/root.zig')
| -rw-r--r-- | src/estd/parser/root.zig | 408 |
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()); } |