aboutsummaryrefslogtreecommitdiff
path: root/src/z/parser/js/grammar/literal.zig
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2026-08-05 09:08:24 +0200
committerNathan Reiner <nathan@nathanreiner.xyz>2026-08-05 09:08:24 +0200
commit0eaa2a420cb699cdb23ce9b1573560a5d9e59a31 (patch)
tree7c33f4be58e47aa6c1641b66442216352fa3f36b /src/z/parser/js/grammar/literal.zig
parent356c2bc0ccb1794b5ec219079d8c5b85ddcc4c87 (diff)
add regex literals
Diffstat (limited to 'src/z/parser/js/grammar/literal.zig')
-rw-r--r--src/z/parser/js/grammar/literal.zig37
1 files changed, 33 insertions, 4 deletions
diff --git a/src/z/parser/js/grammar/literal.zig b/src/z/parser/js/grammar/literal.zig
index 039ebf4..71b990d 100644
--- a/src/z/parser/js/grammar/literal.zig
+++ b/src/z/parser/js/grammar/literal.zig
@@ -24,6 +24,9 @@ pub const Literal = union(enum) {
var token = lexer.start(.{ .literal = undefined });
+ const regex_possible = lexer.context.regex_possible;
+ lexer.context.regex_possible = false;
+
switch (try lexer.consume()) {
'0'...'9', '.' => |c| {
const base = if (c != '0') 10 else switch (lexer.peekChar() orelse 0) {
@@ -69,7 +72,7 @@ pub const Literal = union(enum) {
while (true) {
switch (try lexer.consume()) {
quote => break,
- '\\' => try lexer.consume(),
+ '\\' => try lexer.skip(),
else => {},
}
}
@@ -83,11 +86,12 @@ pub const Literal = union(enum) {
token.kind.literal.template = .whole;
break;
},
- '\\' => try lexer.consume(),
+ '\\' => try lexer.skip(),
'$' => if (lexer.peekChar() == '{') {
lexer.skip() catch unreachable;
lexer.context.template_nesting += 1;
token.kind.literal.template = .start;
+ lexer.context.regex_possible = true;
break;
},
else => {},
@@ -104,17 +108,28 @@ pub const Literal = union(enum) {
token.kind.literal.template = .end;
break;
},
- '\\' => try lexer.consume(),
+ '\\' => try lexer.skip(),
'$' => if (lexer.peekChar() == '{') {
lexer.skip() catch unreachable;
lexer.context.template_nesting += 1;
token.kind.literal.template = .middle;
+ lexer.context.regex_possible = true;
break;
},
else => {},
}
}
- },
+ } else return Lexer.Error.UnexpectedToken,
+ '/' => if (regex_possible) {
+ while (true) {
+ switch (try lexer.consume()) {
+ '/' => break,
+ '\\' => try lexer.skip(),
+ '\n' => return Lexer.Error.UnexpectedToken,
+ else => {},
+ }
+ }
+ } else return Lexer.Error.UnexpectedToken,
else => return Lexer.Error.UnexpectedToken,
}
@@ -159,3 +174,17 @@ test "string" {
Simple.run("'hello", 0),
);
}
+
+test "regex" {
+ const Simple = struct {
+ pub fn run(comptime buffer: []const u8, n: usize) !void {
+ comptime var lexer: Lexer = .init(buffer);
+ try Literal.tokenize(&lexer);
+ try std.testing.expectEqual(1, lexer.tokens.len);
+ try std.testing.expectEqual(n, lexer.tokens[0].slice.len);
+ }
+ };
+
+ try Simple.run("/hello/", 7);
+ try Simple.run("/some string\\/ here/", 20);
+}