Skip to content

Commit a156bfb

Browse files
authored
refactor(toml): split symbol parser (#6563)
1 parent 69fe7dc commit a156bfb

File tree

2 files changed

+73
-21
lines changed

2 files changed

+73
-21
lines changed

toml/_parser.ts

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,13 @@ export function deepAssignWithTable(target: Record<string, unknown>, table: {
197197
// Parser combinators and generators
198198
// ---------------------------------
199199

200-
function or<T>(parsers: ParserComponent<T>[]): ParserComponent<T> {
201-
return (scanner: Scanner): ParseResult<T> => {
200+
// deno-lint-ignore no-explicit-any
201+
function or<T extends readonly ParserComponent<any>[]>(
202+
parsers: T,
203+
): ParserComponent<
204+
ReturnType<T[number]> extends ParseResult<infer R> ? R : Failure
205+
> {
206+
return (scanner: Scanner) => {
202207
for (const parse of parsers) {
203208
const result = parse(scanner);
204209
if (result.ok) return result;
@@ -533,22 +538,41 @@ export function multilineLiteralString(
533538
return success(acc.join(""));
534539
}
535540

536-
const symbolPairs: [string, unknown][] = [
537-
["true", true],
538-
["false", false],
541+
const BOOLEAN_REGEXP = /(?:true|false)\b/y;
542+
export function boolean(scanner: Scanner): ParseResult<boolean> {
543+
scanner.skipWhitespaces();
544+
const match = scanner.match(BOOLEAN_REGEXP);
545+
if (!match) return failure();
546+
const string = match[0];
547+
scanner.next(string.length);
548+
const value = string === "true";
549+
return success(value);
550+
}
551+
552+
const INFINITY_MAP = new Map<string, number>([
539553
["inf", Infinity],
540554
["+inf", Infinity],
541555
["-inf", -Infinity],
542-
["nan", NaN],
543-
["+nan", NaN],
544-
["-nan", NaN],
545-
];
546-
export function symbols(scanner: Scanner): ParseResult<unknown> {
556+
]);
557+
const INFINITY_REGEXP = /[+-]?inf\b/y;
558+
export function infinity(scanner: Scanner): ParseResult<number> {
547559
scanner.skipWhitespaces();
548-
const found = symbolPairs.find(([str]) => scanner.startsWith(str));
549-
if (!found) return failure();
550-
const [str, value] = found;
551-
scanner.next(str.length);
560+
const match = scanner.match(INFINITY_REGEXP);
561+
if (!match) return failure();
562+
const string = match[0];
563+
scanner.next(string.length);
564+
const value = INFINITY_MAP.get(string)!;
565+
return success(value);
566+
}
567+
568+
const NAN_REGEXP = /[+-]?nan\b/y;
569+
export function nan(scanner: Scanner): ParseResult<number> {
570+
scanner.skipWhitespaces();
571+
const match = scanner.match(NAN_REGEXP);
572+
if (!match) return failure();
573+
const string = match[0];
574+
scanner.next(string.length);
575+
const value = NaN;
552576
return success(value);
553577
}
554578

@@ -683,7 +707,9 @@ export const value = or([
683707
multilineLiteralString,
684708
basicString,
685709
literalString,
686-
symbols,
710+
boolean,
711+
infinity,
712+
nan,
687713
dateTime,
688714
localTime,
689715
binary,

toml/parse_test.ts

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,24 @@ import {
55
bareKey,
66
basicString,
77
binary,
8+
boolean,
89
dateTime,
910
deepAssignWithTable,
1011
dottedKey,
1112
float,
1213
hex,
14+
infinity,
1315
inlineTable,
1416
integer,
1517
literalString,
1618
localTime,
1719
multilineBasicString,
1820
multilineLiteralString,
21+
nan,
1922
octal,
2023
pair,
2124
parserFactory,
2225
Scanner,
23-
symbols,
2426
table,
2527
value,
2628
} from "./_parser.ts";
@@ -181,14 +183,38 @@ Violets are\\tblue'''`),
181183
});
182184

183185
Deno.test({
184-
name: "parse() handles symbols",
186+
name: "parse() handles boolean",
185187
fn() {
186-
const parse = parserFactory(symbols);
188+
const parse = parserFactory(boolean);
187189
assertEquals(parse("true"), true);
188-
assertEquals(parse("nan"), NaN);
190+
assertEquals(parse("false"), false);
191+
assertThrows(() => parse("truetrue"));
192+
assertThrows(() => parse("false "));
193+
},
194+
});
195+
196+
Deno.test({
197+
name: "parse() handles infinity",
198+
fn() {
199+
const parse = parserFactory(infinity);
189200
assertEquals(parse("inf"), Infinity);
190-
assertThrows(() => parse(""));
191-
assertThrows(() => parse("_"));
201+
assertEquals(parse("+inf"), Infinity);
202+
assertEquals(parse("-inf"), -Infinity);
203+
assertThrows(() => parse("infinf"));
204+
assertThrows(() => parse("+inf "));
205+
assertThrows(() => parse("-inf_"));
206+
},
207+
});
208+
Deno.test({
209+
name: "parse() handles nan",
210+
fn() {
211+
const parse = parserFactory(nan);
212+
assertEquals(parse("nan"), NaN);
213+
assertEquals(parse("+nan"), NaN);
214+
assertEquals(parse("-nan"), NaN);
215+
assertThrows(() => parse("nannan"));
216+
assertThrows(() => parse("+nan "));
217+
assertThrows(() => parse("-nan_"));
192218
},
193219
});
194220

0 commit comments

Comments
 (0)