summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaylan Kammer <taylan.kammer@gmail.com>2025-03-28 18:02:38 +0100
committerTaylan Kammer <taylan.kammer@gmail.com>2025-03-28 18:02:38 +0100
commit6eedf5394997b91467a392732cdb7fbb80a790b8 (patch)
tree69ad43857ec17315c9a9d5547709eb6fd238502d
parent00fd32b6c0d35140bdc160aa759bbac52242d7d0 (diff)
blub
-rw-r--r--_tests/test.zig4
-rw-r--r--spec/parser.ebnf30
-rw-r--r--src/libzisp.zig16
-rw-r--r--src/libzisp/io/parser.zig250
-rw-r--r--src/libzisp/value/rune.zig4
5 files changed, 170 insertions, 134 deletions
diff --git a/_tests/test.zig b/_tests/test.zig
index 5acb628..e746851 100644
--- a/_tests/test.zig
+++ b/_tests/test.zig
@@ -1,11 +1,13 @@
const std = @import("std");
-pub fn main() void {
+pub fn main() u8 {
// const y: [3]u64 = .{ 1, 2, 3 };
// const x: struct { u8, u64, u8 } = y;
// @import("std").debug.print("{}\n", .{x[0] + x[1] + x[2]});
std.debug.print("{}\n", .{@sizeOf(struct { u64, ?u8 })});
+
+ return while (true) if (true) break 1;
}
// const x: ?u8 = 5;
diff --git a/spec/parser.ebnf b/spec/parser.ebnf
index 44b1967..60f7890 100644
--- a/spec/parser.ebnf
+++ b/spec/parser.ebnf
@@ -1,11 +1,14 @@
-unit : blank* ( datum blank? | EOF ) ;
+unit : empty_unit | datum_unit ;
-blank : 9...13 | comment ;
+empty_unit : blank* EOF ;
-datum : one_datum ( join_char? one_datum )* ;
+datum_unit : blank* datum blank? ;
-join_char : '.' | ':' | '|' ;
+
+blank : 9...13 | comment ;
+
+datum : join_data | dot_string ;
comment : ';' ( skip_unit | skip_line ) ;
@@ -15,9 +18,18 @@ skip_unit : '~' unit ;
skip_line : ( ~10 )* 10? ;
-one_datum : ( bare_str | clad_datum ) ;
+join_data : one_datum ( join_char? one_datum )*
+
+join_char : '.' | ':' | '|' ;
+
+dot_string : '.'{2,}
+
-bare_str : bare_str_elt+ ;
+one_datum : ( num_string | bare_string | clad_datum ) ;
+
+num_string : ( '+' | '-' )? digit ( bare_str_elt | '.' )* ;
+
+bare_string : bare_str_elt+ ;
clad_datum : '\' bare_esc_str
| '"' quoted_str '"'
@@ -37,11 +49,13 @@ bare_esc_str : bare_esc bare_str_elt* ;
quoted_str : ( quoted_char | '\' quoted_esc )* ;
hash_expr : rune clad_datum?
- | '%' label ( '%' | '=' unit )
+ | '%' label ( '%' | '=' datum_unit )
| clad_datum
;
-list : unit+ ( '.' blank+ unit )? blank* ;
+list : datum_unit+ list_tail? blank* ;
+
+list_tail : '.' blank+ datum_unit
quote_expr : ( "'" | "`" | "," ) datum ;
diff --git a/src/libzisp.zig b/src/libzisp.zig
index df8422b..ceee3f6 100644
--- a/src/libzisp.zig
+++ b/src/libzisp.zig
@@ -352,11 +352,17 @@ fn parseBench(path: []const u8, iters: usize) !void {
var timer = try std.time.Timer.start();
for (0..iters) |i| {
_ = i;
- var br = std.io.bufferedReader(file.reader());
- const reader = br.reader().any();
+ // var br = std.io.bufferedReader(file.reader());
+ // const reader = br.reader().any();
+ const reader = file.reader().any();
var v: Value = undefined;
while (true) {
- v = io.parser.parse(reader);
+ v = io.parser._parse(reader) catch |e| {
+ std.debug.print("\nfile pos: {}\n", .{
+ try file.getPos(),
+ });
+ return e;
+ };
if (value.eof.check(v)) {
break;
}
@@ -374,7 +380,7 @@ fn parseBench(path: []const u8, iters: usize) !void {
test "parse bench" {
try parseBench("test-data/parser-test-1.scm", 1000);
try parseBench("test-data/parser-test-2.scm", 1000);
- // try parseBench("test-data/parser-torture.scm", 1);
+ try parseBench("test-data/parser-torture.scm", 1);
}
test "unparse" {
@@ -423,7 +429,7 @@ test "unparse5" {
test "unparse6" {
const w = std.io.getStdErr().writer();
- const v = parseString("(foo .bar ... baz. bat.(qux))");
+ const v = parseString("(foo bar ... baz bat.(qux))");
try io.unparser.unparse(w, v);
try w.writeByte('\n');
}
diff --git a/src/libzisp/io/parser.zig b/src/libzisp/io/parser.zig
index 643f7e8..8093ffe 100644
--- a/src/libzisp/io/parser.zig
+++ b/src/libzisp/io/parser.zig
@@ -275,10 +275,10 @@ const GRAVE = value.rune.pack("GRAVE");
const COMMA = value.rune.pack("COMMA");
const SQUARE = value.rune.pack("SQUARE");
const BRACE = value.rune.pack("BRACE");
+const VOID = value.rune.packForced("");
+const LSTAIL = value.rune.packForced(".");
// zig fmt: on
-const S_DOT = value.sstr.pack(".");
-
const Context = struct {
// What to do next.
next: Fn = .parse_unit,
@@ -288,7 +288,7 @@ const Context = struct {
char: u8 = undefined,
};
-const ParseError = error{
+const ParseError = enum {
InvalidCharacter,
UnclosedString,
UnexpectedEof,
@@ -314,7 +314,6 @@ const State = struct {
result: Value = undefined,
unused_char: ?u8 = null,
- err_code: anyerror = undefined,
err_msg: []const u8 = undefined,
fn init(
@@ -337,9 +336,13 @@ const State = struct {
s.chars.deinit(s.chars_alloc);
}
- fn err(s: *State, e: ParseError, msg: []const u8) ParseError {
- s.err_msg = msg;
- return e;
+ fn err(
+ s: *State,
+ comptime e: ParseError,
+ comptime msg: []const u8,
+ ) error{ParseError} {
+ s.err_msg = @tagName(e) ++ " at: " ++ msg;
+ return error.ParseError;
}
fn read(s: *State) !?u8 {
@@ -348,10 +351,7 @@ const State = struct {
}
const c = s.input.readByte() catch |e| switch (e) {
error.EndOfStream => return null,
- else => {
- s.err_code = e;
- return error.ReadError;
- },
+ else => return s.err(.ReadError, "???"),
};
if (detailed_debug) {
std.debug.print("{c}", .{c});
@@ -359,8 +359,8 @@ const State = struct {
return c;
}
- fn readNoEof(s: *State, emsg: []const u8) !u8 {
- return if (try s.read()) |c| c else s.err(error.UnexpectedEof, emsg);
+ fn readNoEof(s: *State, comptime emsg: []const u8) !u8 {
+ return if (try s.read()) |c| c else s.err(.UnexpectedEof, emsg);
}
fn getUnused(s: *State) ?u8 {
@@ -371,10 +371,6 @@ const State = struct {
return null;
}
- fn skipLine(s: *State) !void {
- while (try s.read()) |c| if (c == '\n') break;
- }
-
fn addChar(s: *State, c: u8) !void {
try s.chars.append(s.chars_alloc, c);
}
@@ -423,7 +419,7 @@ const State = struct {
}
fn abort(s: *State, next: Fn, unused_c: u8) void {
- s.result = value.undef;
+ s.result = VOID;
s.unused_char = unused_c;
s.context.next = next;
}
@@ -438,7 +434,7 @@ const State = struct {
}
};
-pub fn parse(input: std.io.AnyReader) Value {
+pub fn _parse(input: std.io.AnyReader) !Value {
var debug_alloc: std.heap.DebugAllocator(.{}) = undefined;
if (!is_test and is_debug) {
debug_alloc = .init;
@@ -465,25 +461,28 @@ pub fn parse(input: std.io.AnyReader) Value {
var s = State.init(input, stack_alloc, chars_alloc) catch @panic("");
defer s.deinit();
- while (s.context.next != .done) callNext(&s) catch {
- if (s.unused_char) |c| {
- std.debug.panic(
- "Parse error: {} at: {s}, char: {c}\n",
- .{ s.err_code, s.err_msg, c },
- );
- } else {
- std.debug.panic(
- "Parse error: {} at: {s}\n",
- .{ s.err_code, s.err_msg },
- );
- }
+ while (s.context.next != .done) callNext(&s) catch |e| {
+ // _ = e;
+ // if (s.unused_char) |c| {
+ // std.debug.panic(
+ // "Parse error: {s}, unused_char: 0x{x}\n",
+ // .{ s.err_msg, c },
+ // );
+ // } else {
+ // std.debug.panic("Parse error: {s}\n", .{s.err_msg});
+ // }
+ return e;
};
if (s.unused_char) |c| {
- std.debug.panic("Invalid character: {c}\n", .{c});
+ std.debug.panic("Invalid trailing character: {c}\n", .{c});
}
return s.result;
}
+pub fn parse(input: std.io.AnyReader) Value {
+ return _parse(input) catch @panic("");
+}
+
const Fn = enum {
parse_unit,
return_context,
@@ -549,43 +548,74 @@ fn callNext(s: *State) !void {
fn parseUnit(s: *State) !void {
var c1 = s.getUnused() orelse try s.read();
while (c1) |c| : (c1 = try s.read()) {
- switch (try checkBlank(s, c)) {
+ switch (try checkBlanks(s, c)) {
.yes => {},
.skip_unit => try s.push(.parse_unit),
- .skip_line => try s.skipLine(),
.no => return parseDatum(s, c),
}
}
return s.retval(value.eof.eof);
}
-fn checkBlank(s: *State, c: u8) !enum { yes, skip_unit, skip_line, no } {
+fn checkBlanks(s: *State, c: u8) !enum { yes, skip_unit, no } {
return switch (c) {
'\t'...'\r', ' ' => .yes,
';' => switch (try s.read() orelse '\n') {
'\n' => .yes,
'~' => .skip_unit,
- else => .skip_line,
+ else => while (try s.read() != '\n') {} else .yes,
},
else => .no,
};
}
fn parseDatum(s: *State, c: u8) !void {
+ if (c == '.') {
+ return parseDotString(s);
+ }
return parseOneDatum(s, c, .end_one_datum);
}
+fn parseDotString(s: *State) !void {
+ try s.addChar('.');
+ while (try s.read()) |c| {
+ switch (try checkBlanks(s, c)) {
+ .yes => return dotString(s, false),
+ .skip_unit => return dotString(s, true),
+ .no => switch (c) {
+ '.' => try s.addChar('.'),
+ ')', ']', '}' => {
+ s.unused_char = c;
+ return dotString(s, false);
+ },
+ else => return s.err(.InvalidCharacter, "dot string"),
+ },
+ }
+ }
+ unreachable;
+}
+
+fn dotString(s: *State, skip_unit: bool) !void {
+ const lstail = s.chars.items.len == 1;
+ const result = if (lstail) LSTAIL else s.getBareString();
+ if (skip_unit) {
+ s.context.val = result;
+ return s.subr(.parse_unit, .return_context);
+ } else {
+ return s.retval(result);
+ }
+}
+
fn endOneDatum(s: *State) !void {
- if (s.result.eq(value.undef)) {
- return s.retval(value.undef);
+ if (s.result.eq(VOID)) {
+ return s.retval(VOID);
}
const d = s.result;
const c1 = s.getUnused() orelse try s.read();
if (c1) |c| {
- switch (try checkBlank(s, c)) {
+ switch (try checkBlanks(s, c)) {
.yes => {},
.skip_unit => return skipUnitAndReturn(s, d),
- .skip_line => try s.skipLine(),
.no => return parseJoin(s, d, c),
}
}
@@ -629,11 +659,11 @@ fn joinData(s: *State) !void {
const head = s.context.val;
const join = s.context.char;
const tail = s.result;
- if (tail.eq(value.undef)) {
+ if (tail.eq(VOID)) {
if (join == 0) {
return s.retval(head);
} else {
- return s.err(error.InvalidCharacter, "join datum");
+ return s.err(.InvalidCharacter, "join datum");
}
}
const rune = switch (join) {
@@ -649,20 +679,17 @@ fn joinData(s: *State) !void {
fn parseOneDatum(s: *State, c: u8, next: Fn) !void {
if (isBareChar(c)) {
- const d, s.unused_char = try parseBareString(s, c);
- return s.jump(next, d);
+ return s.jump(next, try parseBareString(s, c));
}
return parseCladDatum(s, c, next);
}
fn parseCladDatum(s: *State, c: u8, next: Fn) !void {
if (c == '\\') {
- const bs, s.unused_char = try parseBareEscString(s);
- return s.jump(next, bs);
+ return s.jump(next, try parseBareEscString(s));
}
if (c == '"') {
- const qs = try parseQuotedString(s);
- return s.jump(next, qs);
+ return s.jump(next, try parseQuotedString(s));
}
return switch (c) {
'#' => parseHashExpression(s, next),
@@ -675,10 +702,8 @@ fn parseCladDatum(s: *State, c: u8, next: Fn) !void {
fn isBareChar(c: u8) bool {
return switch (c) {
// zig fmt: off
- 'a'...'z' , 'A'...'Z' , '0'...'9',
- '!' , '$' , '%' , '&' , '*' , '+',
- '-' , '/' , '<' , '=' , '>' , '?',
- '@' , '^' , '_' , '~' , '.' => true,
+ 'a'...'z' , 'A'...'Z' , '0'...'9' , '!' , '$' , '%' , '&' , '*' ,
+ '+' , '-' , '/' , '<' , '=' , '>' , '?' , '@' , '^' , '_' , '~' => true,
// zig fmt: on
else => false,
};
@@ -691,27 +716,28 @@ fn isBareEsc(c: u8) bool {
};
}
-fn parseBareString(s: *State, c: u8) !struct { Value, ?u8 } {
+fn parseBareString(s: *State, c: u8) !Value {
try s.addChar(c);
return parseBareStringRest(s);
}
-fn parseBareEscString(s: *State) !struct { Value, ?u8 } {
+fn parseBareEscString(s: *State) !Value {
try s.addChar(try parseBareEsc(s));
return parseBareStringRest(s);
}
-fn parseBareStringRest(s: *State) !struct { Value, ?u8 } {
+fn parseBareStringRest(s: *State) !Value {
while (try s.read()) |c| {
if (isBareChar(c)) {
try s.addChar(c);
} else if (c == '\\') {
try s.addChar(try parseBareEsc(s));
} else {
- return .{ s.getBareString(), c };
+ s.unused_char = c;
+ break;
}
}
- return .{ s.getBareString(), null };
+ return s.getBareString();
}
fn parseBareEsc(s: *State) !u8 {
@@ -719,7 +745,7 @@ fn parseBareEsc(s: *State) !u8 {
if (isBareEsc(c)) {
return c;
} else {
- return s.err(error.InvalidCharacter, "bare escape");
+ return s.err(.InvalidCharacter, "bare escape");
}
}
@@ -754,17 +780,16 @@ fn parseQuotedEsc(s: *State) !void {
'r' => 13,
'e' => 27,
'x' => try parseHexByte(s, "hex escape"),
- else => return s.err(error.InvalidCharacter, "quoted escape"),
+ else => return s.err(.InvalidCharacter, "quoted escape"),
});
}
fn parseUniHexHandleErrors(s: *State) !void {
return parseUniHex(s) catch |err| switch (err) {
- error.Utf8CannotEncodeSurrogateHalf => e: {
- s.err_code = err;
- s.err_msg = "unicode escape";
- break :e error.UnicodeError;
- },
+ error.Utf8CannotEncodeSurrogateHalf => s.err(
+ .UnicodeError,
+ "unicode escape",
+ ),
else => |e| e,
};
}
@@ -773,16 +798,16 @@ fn parseUniHex(s: *State) !void {
const msg = "unicode escape";
if (try s.readNoEof(msg) != '{') {
- return s.err(error.InvalidCharacter, msg);
+ return s.err(.InvalidCharacter, msg);
}
const uc, const unused_c = try parseHex(s, u21, msg);
if (unused_c) |c| {
if (c != '}') {
- return s.err(error.InvalidCharacter, msg);
+ return s.err(.InvalidCharacter, msg);
}
} else {
- return s.err(error.UnexpectedEof, msg);
+ return s.err(.UnexpectedEof, msg);
}
const n = try std.unicode.utf8CodepointSequenceLength(uc);
@@ -792,8 +817,8 @@ fn parseUniHex(s: *State) !void {
fn parseHashExpression(s: *State, next: Fn) !void {
const c = try s.readNoEof("hash expression");
- if (try checkBlank(s, c) != .no) {
- return s.err(error.InvalidCharacter, "hash expression");
+ if (try checkBlanks(s, c) != .no) {
+ return s.err(.InvalidCharacter, "hash expression");
}
if (std.ascii.isAlphabetic(c)) {
const r, const unused_c = try parseRune(s, c);
@@ -805,16 +830,14 @@ fn parseHashExpression(s: *State, next: Fn) !void {
}
if (isBareChar(c)) {
// Reserved for future extensions to syntax sugar.
- return s.err(error.InvalidCharacter, "hash expression");
+ return s.err(.InvalidCharacter, "hash expression");
}
// fast-path to avoid subr
if (c == '\\') {
- const bs, s.unused_char = try parseBareEscString(s);
- return s.jump(next, cons(HASH, bs));
+ return s.jump(next, cons(HASH, try parseBareEscString(s)));
}
if (c == '"') {
- const qs = try parseQuotedString(s);
- return s.jump(next, cons(HASH, qs));
+ return s.jump(next, cons(HASH, try parseQuotedString(s)));
}
s.unused_char = c;
return s.subr(.parse_hash_datum, next);
@@ -825,8 +848,8 @@ fn parseHashDatum(s: *State) !void {
}
fn endHashDatum(s: *State) !void {
- if (s.result.eq(value.undef)) {
- return s.err(error.InvalidCharacter, "hash datum");
+ if (s.result.eq(VOID)) {
+ return s.err(.InvalidCharacter, "hash datum");
}
return s.retval(cons(HASH, s.result));
}
@@ -846,12 +869,10 @@ fn parseRune(s: *State, c1: u8) !struct { Value, ?u8 } {
fn parseRuneEnd(s: *State, r: Value, c1: ?u8, next: Fn) !void {
const c = c1 orelse return s.jump(next, r);
if (c == '\\') {
- const bs, s.unused_char = try parseBareString(s, c);
- return s.jump(next, cons(r, bs));
+ return s.jump(next, cons(r, try parseBareString(s, c)));
}
if (c == '"') {
- const qs = try parseQuotedString(s);
- return s.jump(next, cons(r, qs));
+ return s.jump(next, cons(r, try parseQuotedString(s)));
}
s.unused_char = c;
switch (c) {
@@ -869,12 +890,10 @@ fn parseRuneDatum(s: *State) !void {
}
fn endRuneDatum(s: *State) !void {
- const r = s.context.val;
- const d = s.result;
- if (d.eq(value.undef)) {
- s.retval(r);
+ if (s.result.eq(VOID)) {
+ s.retval(s.context.val);
}
- return s.retval(cons(r, d));
+ return s.retval(cons(s.context.val, s.result));
}
fn parseLabel(s: *State) !struct { Value, ?u8 } {
@@ -883,7 +902,7 @@ fn parseLabel(s: *State) !struct { Value, ?u8 } {
}
fn parseLabelEnd(s: *State, l: Value, c1: ?u8, next: Fn) !void {
- const c = c1 orelse return s.err(error.UnexpectedEof, "datum label");
+ const c = c1 orelse return s.err(.UnexpectedEof, "datum label");
if (c == '%') {
return s.jump(next, cons(LABEL, l));
}
@@ -892,16 +911,14 @@ fn parseLabelEnd(s: *State, l: Value, c1: ?u8, next: Fn) !void {
s.context.val = l;
return s.subr(.parse_unit, .end_label_datum);
}
- return s.err(error.InvalidCharacter, "datum label");
+ return s.err(.InvalidCharacter, "datum label");
}
fn endLabelDatum(s: *State) !void {
- const l = s.context.val;
- const d = s.result;
- if (d.eq(value.undef)) {
- return s.err(error.InvalidCharacter, "label datum");
+ if (s.result.eq(VOID)) {
+ return s.err(.InvalidCharacter, "label datum");
}
- return s.retval(cons(LABEL, cons(l, d)));
+ return s.retval(cons(LABEL, cons(s.context.val, s.result)));
}
fn parseList(s: *State, open: u8, next: Fn) !void {
@@ -921,14 +938,13 @@ fn parseList(s: *State, open: u8, next: Fn) !void {
if (c == close) {
return s.jump(next, head);
}
- switch (try checkBlank(s, c)) {
+ switch (try checkBlanks(s, c)) {
.yes => {},
.skip_unit => {
try listParserSetup(s, head, close, next);
// Parse twice in a row, ignoring the first result.
return s.subr(.parse_unit, .parse_unit);
},
- .skip_line => try s.skipLine(),
.no => {
try listParserSetup(s, head, close, next);
s.unused_char = c;
@@ -936,7 +952,7 @@ fn parseList(s: *State, open: u8, next: Fn) !void {
},
}
}
- return s.err(error.UnexpectedEof, "list");
+ return s.err(.UnexpectedEof, "list");
}
fn listParserSetup(s: *State, head: Value, close: u8, next: Fn) !void {
@@ -953,15 +969,15 @@ fn parseListElement(s: *State) !void {
fn continueList(s: *State) !void {
const close = s.context.char;
- if (s.result.eq(value.undef)) {
+ if (s.result.eq(VOID)) {
const c = s.getUnused().?;
if (c == close) {
return endList(s);
}
- return s.err(error.InvalidCharacter, "list");
+ return s.err(.InvalidCharacter, "list");
}
- if (s.result.eq(S_DOT)) {
+ if (s.result.eq(LSTAIL)) {
return s.subr(.parse_unit, .end_improper_list);
}
@@ -972,20 +988,19 @@ fn continueList(s: *State) !void {
if (c == close) {
return endList(s);
}
- switch (try checkBlank(s, c)) {
+ switch (try checkBlanks(s, c)) {
.yes => {},
.skip_unit => {
try s.pushContext(.continue_list);
return s.subr(.parse_unit, .parse_unit);
},
- .skip_line => try s.skipLine(),
.no => {
s.unused_char = c;
return s.subr(.parse_list_element, .continue_list);
},
}
}
- return s.err(error.UnexpectedEof, "list");
+ return s.err(.UnexpectedEof, "list");
}
fn endList(s: *State) !void {
@@ -993,11 +1008,10 @@ fn endList(s: *State) !void {
}
fn endImproperList(s: *State) !void {
- const tail = s.result;
- if (tail.eq(value.undef)) {
- return s.err(error.InvalidCharacter, "list tail");
+ if (s.result.eq(VOID)) {
+ return s.err(.InvalidCharacter, "list tail");
}
- s.context.val = lib.list.reverseWithTail(s.context.val, tail);
+ s.context.val = lib.list.reverseWithTail(s.context.val, s.result);
return closeImproperList(s);
}
@@ -1009,11 +1023,10 @@ fn closeImproperList(s: *State) !void {
if (c == close) {
return s.retval(result);
}
- switch (try checkBlank(s, c)) {
+ switch (try checkBlanks(s, c)) {
.yes => {},
.skip_unit => return s.subr(.parse_unit, .close_improper_list),
- .skip_line => try s.skipLine(),
- .no => return s.err(error.InvalidCharacter, "after list tail"),
+ .no => return s.err(.InvalidCharacter, "after list tail"),
}
}
unreachable;
@@ -1030,8 +1043,7 @@ fn parseQuoteExpr(s: *State, c1: u8, next: Fn) !void {
// fast-path to avoid subr
const c = try s.readNoEof("quote expression");
if (isBareChar(c) or c == '\\') {
- const bs, s.unused_char = try parseBareString(s, c);
- return s.jump(next, cons(q, bs));
+ return s.jump(next, cons(q, try parseBareString(s, c)));
}
s.context.val = q;
@@ -1040,12 +1052,10 @@ fn parseQuoteExpr(s: *State, c1: u8, next: Fn) !void {
}
fn endQuoteExpr(s: *State) !void {
- if (s.result.eq(value.undef)) {
- return s.err(error.InvalidCharacter, "quote expression datum");
+ if (s.result.eq(VOID)) {
+ return s.err(.InvalidCharacter, "quote expression datum");
}
- const q = s.context.val;
- const d = s.result;
- return s.retval(cons(q, d));
+ return s.retval(cons(s.context.val, s.result));
}
// Helpers
@@ -1053,7 +1063,7 @@ fn endQuoteExpr(s: *State) !void {
fn parseHex(
s: *State,
u_type: type,
- emsg: []const u8,
+ comptime emsg: []const u8,
) !struct { u_type, ?u8 } {
var uc: u_type = undefined;
@@ -1065,13 +1075,13 @@ fn parseHex(
return .{ uc, c };
}
const shl = std.math.shlExact;
- uc = shl(u_type, uc, 4) catch return s.err(error.OutOfRange, emsg);
+ uc = shl(u_type, uc, 4) catch return s.err(.OutOfRange, emsg);
uc |= try parseHexDigit(s, c, emsg);
}
return .{ uc, null };
}
-fn parseHexByte(s: *State, emsg: []const u8) !u8 {
+fn parseHexByte(s: *State, comptime emsg: []const u8) !u8 {
const h1 = try s.readNoEof(emsg);
const h2 = try s.readNoEof(emsg);
const hi = try parseHexDigit(s, h1, emsg);
@@ -1079,11 +1089,11 @@ fn parseHexByte(s: *State, emsg: []const u8) !u8 {
return hi << 4 | lo;
}
-fn parseHexDigit(s: *State, c: u8, emsg: []const u8) !u8 {
+fn parseHexDigit(s: *State, c: u8, comptime emsg: []const u8) !u8 {
return switch (c) {
'0'...'9' => c - '0',
'A'...'F' => c - 'A' + 10,
'a'...'f' => c - 'a' + 10,
- else => s.err(error.InvalidCharacter, emsg),
+ else => s.err(.InvalidCharacter, emsg),
};
}
diff --git a/src/libzisp/value/rune.zig b/src/libzisp/value/rune.zig
index 154ec13..195210e 100644
--- a/src/libzisp/value/rune.zig
+++ b/src/libzisp/value/rune.zig
@@ -44,6 +44,10 @@ fn assertValidRune(s: []const u8) void {
pub fn pack(s: []const u8) Value {
assertValidRune(s);
+ return packForced(s);
+}
+
+pub fn packForced(s: []const u8) Value {
var v = Value{ .rune = .{ .name = 0 } };
const dest: [*]u8 = @ptrCast(&v.rune.name);
@memcpy(dest, s);