UNPKG

crazy-parser

Version:

A light-weight parser combinator

30 lines (29 loc) 2.12 kB
/* A naïve implementation of JSON parser in pure JavaScript. It's about a thousand times slower than the native one, so don't use it. This is to prove the correctness of this library. */ import { asum, char, cr, digit, eof, hex, lazy, lf, Nothing, one, sequence, space, tab } from "./index"; import { many, some } from "./prefix"; import * as V from "./void"; const pWhitespace = many(asum(space, lf, cr, tab)); const pBoolean = V.str("true").cmap(true).or(V.str("false").cmap(false)); const pNull = V.str("null").cmap(null); const pNumber = sequence(char("-").orPure(""), some(digit).where(digits => digits[0] != "0" || (digits[0] == "0" && digits.length == 1)), V.char(".").right(some(digit)).optional(), sequence(char("e").or(char("E")), char("+").or(char("-")).orPure(""), some(digit)).optional()).map(args => { const [a0, a1_, a2_, a3_] = args; const a1 = a1_.join(""); const a2 = a2_ == Nothing ? "" : `.${a2_.join("")}`; if (a3_ == Nothing) return parseFloat(`${a0}${a1}${a2}`); const [a30, a31, a32] = a3_; return parseFloat(`${a0}${a1}${a2}${a30}${a31}${a32}`); }); const pString = V.char("\"").$_(many(V.char("\\").right(asum(V.char("\"").cmap("\""), V.char("\\").cmap("\\"), V.char("/").cmap("/"), V.char("b").cmap("\b"), V.char("f").cmap("\f"), V.char("n").cmap("\n"), V.char("r").cmap("\r"), V.char("t").cmap("\t"), V.char("u").right(hex.x(4)).map(ds => String.fromCodePoint(Number(`0x${ds.join("")}`))))).or(one.where(c => c != "\""))))._$(V.char("\"")).map(cs => cs.join("")); const pValue = pWhitespace.$_(asum(pString, pNumber, pBoolean, pNull, lazy(() => pObject), lazy(() => pArray)))._$(pWhitespace); const pArray = V.char("[").$_(pValue.and(many(V.char(",").$_(pValue))).map(a => [a[0], ...a[1]]) .orPure([]) // Note: The whitespace should've been consumed )._$(V.char("]")); const pObjectEntry = pWhitespace.$_(pString.and(pWhitespace.$_(V.char(":")).$_(pValue))); const pObject = V.char("{").$_(pObjectEntry.and(many(V.char(",").$_(pObjectEntry))).map(a => Object.fromEntries([a[0], ...a[1]])) .orPure({}))._$(V.char("}")); export const json = pValue._$(eof);