aboutsummaryrefslogtreecommitdiff
path: root/src/z/js/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/z/js/parser')
-rw-r--r--src/z/js/parser/builtin.zig17
-rw-r--r--src/z/js/parser/lexical_grammar.zig3
-rw-r--r--src/z/js/parser/parser.zig117
-rw-r--r--src/z/js/parser/result.zig4
-rw-r--r--src/z/js/parser/root.zig11
5 files changed, 152 insertions, 0 deletions
diff --git a/src/z/js/parser/builtin.zig b/src/z/js/parser/builtin.zig
new file mode 100644
index 0000000..fc96fc3
--- /dev/null
+++ b/src/z/js/parser/builtin.zig
@@ -0,0 +1,17 @@
+const std = @import("std");
+
+const parser = @import("root.zig");
+const Parser = parser.Parser;
+const Result = parser.Result;
+
+pub fn literal(lit: []const u8) Parser(void) {
+ return .fromType(struct {
+ pub fn parse(buffer: []const u8) !Result(void) {
+ if (std.mem.startsWith(u8, buffer, lit)) {
+ return .{ void{}, buffer[lit.len..] };
+ }
+
+ return error.Literal;
+ }
+ });
+}
diff --git a/src/z/js/parser/lexical_grammar.zig b/src/z/js/parser/lexical_grammar.zig
new file mode 100644
index 0000000..7060766
--- /dev/null
+++ b/src/z/js/parser/lexical_grammar.zig
@@ -0,0 +1,3 @@
+const parser = @import("root.zig");
+const Result = parser.Result;
+
diff --git a/src/z/js/parser/parser.zig b/src/z/js/parser/parser.zig
new file mode 100644
index 0000000..b73d895
--- /dev/null
+++ b/src/z/js/parser/parser.zig
@@ -0,0 +1,117 @@
+const std = @import("std");
+
+const mod = @import("root.zig");
+const Result = mod.Result;
+
+pub fn Parser(T: type) type {
+ const R = Result(T);
+
+ return struct {
+ parse: *const fn ([]const u8) anyerror!R,
+
+ pub fn parseAll(self: *const @This(), buffer: []const u8) !T {
+ const value, const next = try self.parse(buffer);
+
+ if (next.len > 0) {
+ return error.NotExhaustive;
+ }
+
+ return value;
+ }
+
+ pub fn fromType(P: type) @This() {
+ return .{ .parse = P.parse };
+ }
+
+ pub fn variants(V: type) @This() {
+ if (@typeInfo(T) != .@"union") {
+ @compileError("variants is only allowed with an union as result type");
+ }
+
+ return .{
+ .parse = struct {
+ fn parse(buffer: []const u8) !R {
+ inline for (std.meta.fields(T)) |field| {
+ if (@field(V, field.name).parse(buffer)) |result| {
+ const value, const next = result;
+ return .{
+ @unionInit(T, field.name, value),
+ next,
+ };
+ } else |_| { }
+ }
+
+ return error.Variants;
+ }
+ }.parse,
+ };
+ }
+
+ pub fn any(P: type, comptime parsers: []const struct { Parser(P), T }) @This() {
+ return .{
+ .parse = struct {
+ fn parse(buffer: []const u8) !R {
+ inline for (parsers) |pair| {
+ const parser, const value = pair;
+
+ if (parser.parse(buffer)) |result| {
+ _, const next = result;
+ return .{ value, next };
+ } else |_| { }
+ }
+ return error.Any;
+ }
+ }.parse,
+ };
+ }
+ };
+}
+
+test "variants" {
+ const Char = union(enum) {
+ upper: u8,
+ lower: u8,
+ space: void,
+ };
+
+ const parser: Parser(Char) = .variants(struct {
+ const upper: Parser(u8) = .any(void, &.{
+ .{ mod.builtin.literal("A"), 'A' },
+ .{ mod.builtin.literal("B"), 'B' },
+ });
+
+ const lower: Parser(u8) = .any(void, &.{
+ .{ mod.builtin.literal("a"), 'a' },
+ .{ mod.builtin.literal("b"), 'b' },
+ });
+
+ const space: Parser(void) = mod.builtin.literal(" ");
+ });
+
+ {
+ const result = try parser.parseAll("a");
+ try std.testing.expect(result.lower == 'a');
+ }
+
+ {
+ const result = try parser.parseAll("b");
+ try std.testing.expect(result.lower == 'b');
+ }
+
+ {
+ const result = try parser.parseAll("A");
+ try std.testing.expect(result.upper == 'A');
+ }
+
+ {
+ const result = try parser.parseAll("B");
+ try std.testing.expect(result.upper == 'B');
+ }
+
+ {
+ const result = try parser.parseAll(" ");
+ try std.testing.expect(result == .space);
+ }
+
+ try std.testing.expect(parser.parseAll("c") == error.Variants);
+}
diff --git a/src/z/js/parser/result.zig b/src/z/js/parser/result.zig
new file mode 100644
index 0000000..5cc5878
--- /dev/null
+++ b/src/z/js/parser/result.zig
@@ -0,0 +1,4 @@
+
+pub fn Result(T: type) type {
+ return struct { T, []const u8 };
+}
diff --git a/src/z/js/parser/root.zig b/src/z/js/parser/root.zig
new file mode 100644
index 0000000..a6be9ca
--- /dev/null
+++ b/src/z/js/parser/root.zig
@@ -0,0 +1,11 @@
+const std = @import("std");
+
+pub const lexical_grammar = @import("lexical_grammar.zig");
+
+pub const Result = @import("result.zig").Result;
+pub const Parser = @import("parser.zig").Parser;
+pub const builtin = @import("builtin.zig");
+
+test {
+ _ = std.testing.refAllDecls(@This());
+}