Created
March 10, 2021 20:29
-
-
Save slimsag/db2dd2c49aa038e23b654120e70c9b00 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
const Allocator = std.mem.Allocator; | |
pub const Error = error{ | |
EndOfStream, | |
Utf8InvalidStartByte, | |
} || std.fs.File.ReadError || std.fs.File.SeekError || std.mem.Allocator.Error; | |
pub fn Parser(comptime Value: type, comptime Reader: type) type { | |
return struct { | |
const Self = @This(); | |
_parse: fn(self: *Self, allocator: *Allocator, src: *Reader) callconv(.Inline) Error!?Value, | |
pub fn parse(self: *Self, allocator: *Allocator, src: *Reader) callconv(.Inline) Error!?Value { | |
return self._parse(self, allocator, src); | |
} | |
}; | |
} | |
pub fn OneOf(comptime Value: type, comptime Reader: type) type { | |
return struct { | |
parser: Parser(Value, Reader) = .{ | |
._parse = parse, | |
}, | |
parsers: []*Parser(Value, Reader), | |
const Self = @This(); | |
// `parsers` slice must stay alive for as long as the parser will be | |
// used. | |
pub fn init(parsers: []*Parser(Value, Reader)) Self { | |
return Self{ | |
.parsers = parsers, | |
}; | |
} | |
// Caller is responsible for freeing the value, if any. | |
fn parse(parser: *Parser(Value, Reader), allocator: *Allocator, src: *Reader) callconv(.Inline) Error!?Value { | |
const self = @fieldParentPtr(Self, "parser", parser); | |
for (self.parsers) | one_of_parser | { | |
const result = try one_of_parser.parse(allocator, src); | |
if (result != null) { | |
return result; | |
} | |
} | |
return null; | |
} | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
const Allocator = std.mem.Allocator; | |
const Parser = @import("parser.zig").Parser; | |
const OneOf = @import("parser.zig").OneOf; | |
const Error = @import("parser.zig").Error; | |
pub fn Literal(comptime Reader: type) type { | |
return struct { | |
parser: Parser([]u8, Reader) = .{ | |
._parse = parse, | |
}, | |
want: []const u8, | |
const Self = @This(); | |
pub fn init(want: []const u8) Self { | |
return Self{ | |
.want = want | |
}; | |
} | |
fn parse(parser: *Parser([]u8, Reader), allocator: *Allocator, src: *Reader) callconv(.Inline) Error!?[]u8 { | |
const self = @fieldParentPtr(Self, "parser", parser); | |
const buf = try allocator.alloc(u8, self.want.len); | |
const read = try src.reader().readAll(buf); | |
if (read < self.want.len or !std.mem.eql(u8, buf, self.want)) { | |
try src.seekableStream().seekBy(-@intCast(i64, read)); | |
allocator.free(buf); | |
return null; | |
} | |
return buf; | |
} | |
}; | |
} | |
test "literal" { | |
const allocator = std.testing.allocator; | |
var reader = std.io.fixedBufferStream("abcdef"); | |
var want: []const u8 = "abc"; | |
var literal = Literal(@TypeOf(reader)).init(want); | |
const p = &literal.parser; | |
var result = try p.parse(allocator, &reader); | |
std.testing.expectEqualStrings(want, result.?); | |
if (result) |r| { | |
allocator.free(r); | |
} | |
} | |
test "oneof_literal" { | |
const allocator = std.testing.allocator; | |
var reader = std.io.fixedBufferStream("catdogsheep"); | |
// Define our parser. | |
var one_of = OneOf([]u8, @TypeOf(reader)).init(&.{ | |
&Literal(@TypeOf(reader)).init("dog").parser, | |
&Literal(@TypeOf(reader)).init("sheep").parser, | |
&Literal(@TypeOf(reader)).init("cat").parser, | |
}); | |
var p = &one_of.parser; | |
// Parse! | |
var result = try p.parse(allocator, &reader); | |
std.testing.expectEqualStrings("cat", result.?); | |
if (result) |r| { | |
allocator.free(r); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment