Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 41 additions & 15 deletions toml/_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,13 @@ export function deepAssignWithTable(target: Record<string, unknown>, table: {
// Parser combinators and generators
// ---------------------------------

function or<T>(parsers: ParserComponent<T>[]): ParserComponent<T> {
return (scanner: Scanner): ParseResult<T> => {
// deno-lint-ignore no-explicit-any
function or<T extends readonly ParserComponent<any>[]>(
parsers: T,
): ParserComponent<
ReturnType<T[number]> extends ParseResult<infer R> ? R : Failure
> {
return (scanner: Scanner) => {
for (const parse of parsers) {
const result = parse(scanner);
if (result.ok) return result;
Expand Down Expand Up @@ -499,22 +504,41 @@ export function multilineLiteralString(
return success(acc.join(""));
}

const symbolPairs: [string, unknown][] = [
["true", true],
["false", false],
const BOOLEAN_REGEXP = /(?:true|false)\b/y;
export function boolean(scanner: Scanner): ParseResult<boolean> {
scanner.skipWhitespaces();
const match = scanner.match(BOOLEAN_REGEXP);
if (!match) return failure();
const string = match[0];
scanner.next(string.length);
const value = string === "true";
return success(value);
}

const INFINITY_MAP = new Map<string, number>([
["inf", Infinity],
["+inf", Infinity],
["-inf", -Infinity],
["nan", NaN],
["+nan", NaN],
["-nan", NaN],
];
export function symbols(scanner: Scanner): ParseResult<unknown> {
]);
const INFINITY_REGEXP = /[+-]?inf\b/y;
export function infinity(scanner: Scanner): ParseResult<number> {
scanner.skipWhitespaces();
const found = symbolPairs.find(([str]) => scanner.startsWith(str));
if (!found) return failure();
const [str, value] = found;
scanner.next(str.length);
const match = scanner.match(INFINITY_REGEXP);
if (!match) return failure();
const string = match[0];
scanner.next(string.length);
const value = INFINITY_MAP.get(string)!;
return success(value);
}

const NAN_REGEXP = /[+-]?nan\b/y;
export function nan(scanner: Scanner): ParseResult<number> {
scanner.skipWhitespaces();
const match = scanner.match(NAN_REGEXP);
if (!match) return failure();
const string = match[0];
scanner.next(string.length);
const value = NaN;
return success(value);
}

Expand Down Expand Up @@ -652,7 +676,9 @@ export const value = or([
multilineLiteralString,
basicString,
literalString,
symbols,
boolean,
infinity,
nan,
dateTime,
localTime,
binary,
Expand Down
38 changes: 32 additions & 6 deletions toml/parse_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,24 @@ import {
bareKey,
basicString,
binary,
boolean,
dateTime,
deepAssignWithTable,
dottedKey,
float,
hex,
infinity,
inlineTable,
integer,
literalString,
localTime,
multilineBasicString,
multilineLiteralString,
nan,
octal,
pair,
parserFactory,
Scanner,
symbols,
table,
value,
} from "./_parser.ts";
Expand Down Expand Up @@ -181,14 +183,38 @@ Violets are\\tblue'''`),
});

Deno.test({
name: "parse() handles symbols",
name: "parse() handles boolean",
fn() {
const parse = parserFactory(symbols);
const parse = parserFactory(boolean);
assertEquals(parse("true"), true);
assertEquals(parse("nan"), NaN);
assertEquals(parse("false"), false);
assertThrows(() => parse("truetrue"));
assertThrows(() => parse("false "));
},
});

Deno.test({
name: "parse() handles infinity",
fn() {
const parse = parserFactory(infinity);
assertEquals(parse("inf"), Infinity);
assertThrows(() => parse(""));
assertThrows(() => parse("_"));
assertEquals(parse("+inf"), Infinity);
assertEquals(parse("-inf"), -Infinity);
assertThrows(() => parse("infinf"));
assertThrows(() => parse("+inf "));
assertThrows(() => parse("-inf_"));
},
});
Deno.test({
name: "parse() handles nan",
fn() {
const parse = parserFactory(nan);
assertEquals(parse("nan"), NaN);
assertEquals(parse("+nan"), NaN);
assertEquals(parse("-nan"), NaN);
assertThrows(() => parse("nannan"));
assertThrows(() => parse("+nan "));
assertThrows(() => parse("-nan_"));
},
});

Expand Down
Loading