UNPKG

functionalscript

Version:

FunctionalScript is a purely functional subset of JavaScript

278 lines (277 loc) 7.37 kB
import { cp, range, remove, set, str } from "../func/module.f.js"; import { parser, toRuleMap } from "./module.f.js"; import { classic } from "../func/testlib.f.js"; import * as j from "../../json/module.f.js"; import { sort } from "../../types/object/module.f.js"; import { stringToCodePointList } from "../../text/utf16/module.f.js"; import { toArray } from "../../types/list/module.f.js"; const stringify = j.stringify(sort); const classicTest = () => { const map = { json: [ ['element'] ], value: [ ['object'], ['array'], ['string'], ['number'], str('true'), str('false'), str('null'), ], object: [ [cp('{'), 'ws', cp('}')], [cp('{'), 'members', cp('}')], ], members: [ ['member'], ['member', cp(','), 'members'], ], member: [ ['ws', 'string', 'ws', cp(':'), 'element'], ], array: [ [cp('['), 'ws', cp(']')], [cp('['), 'elements', cp(']')], ], elements: [ ['element'], ['element', cp(','), 'elements'], ], element: [ ['ws', 'value', 'ws'], ], string: [ [cp('"'), 'characters', cp('"')], ], characters: [ [], ['character', 'characters'], ], character: [ ...remove([0x20, 0x10FFFF], [cp('"'), cp('\\')]), [cp('\\'), 'escape'], // 92 ], escape: [ str('"'), str('\\'), str('/'), str('b'), str('f'), str('n'), str('r'), str('t'), [cp('u'), 'hex', 'hex', 'hex', 'hex'], ], hex: [ ['digit'], [range('AF')], // A-F [range('af')], // a-f ], number: [ ['integer', 'fraction', 'exponent'], ], integer: [ ['digit'], ['onenine', 'digits'], [cp('-'), 'digit'], [cp('-'), 'onenine', 'digits'], ], digits: [ ['digit'], ['digit', 'digits'], ], digit: [ [cp('0')], ['onenine'], ], onenine: [ [range('19')], ], fraction: [ [], [cp('.'), 'digits'], ], exponent: [ [], [cp('E'), 'sign', 'digits'], [cp('e'), 'sign', 'digits'], ], sign: [ [], [cp('+')], [cp('-')], ], ws: [ [], [cp(' '), 'ws'], [cp('\n'), 'ws'], [cp('\r'), 'ws'], [cp('\t'), 'ws'], ], }; const result = map; return result; }; const repeat0Name = (v) => `${v}Repeat0`; const repeat0Body = (v) => [ [], [v, repeat0Name(v)] ]; const repeat0 = (v) => { const name = repeat0Name(v); const body = repeat0Body(v); return { [name]: body }; }; const deterministic = () => { const map = { json: [ ['wsRepeat0', 'element'] ], value: [ [cp('{'), 'wsRepeat0', 'object', cp('}')], [cp('['), 'wsRepeat0', 'array', cp(']')], ['string'], ['number'], str('true'), str('false'), str('null'), ], object: [ [], ['member', 'memberTailRepeat0'], ], memberTail: [ [cp(','), 'wsRepeat0', 'member'] ], ...repeat0('memberTail'), member: [ ['string', 'wsRepeat0', cp(':'), 'wsRepeat0', 'element'], ], array: [ [], ['element', 'elements'], ], elements: [ [], [cp(','), 'wsRepeat0', 'element', 'elements'], ], element: [ ['value', 'wsRepeat0'], ], string: [ [cp('"'), 'characterRepeat0', cp('"')], ], ...repeat0('character'), character: [ ...remove([0x20, 0x10FFFF], [cp('"'), cp('\\')]), [cp('\\'), 'escape'], // 92 ], escape: [ ...set('"\\/bfnrt'), [cp('u'), 'hex', 'hex', 'hex', 'hex'], ], hex: [ ['digit'], [range('AF')], [range('af')], ], numberSign: [ [], [cp('-')] ], number: [ ['numberSign', 'integer', 'fraction', 'exponent'], ], integer: [ [cp('0')], ['onenine', 'digitRepeat0'], ], ...repeat0('digit'), digit: [ [cp('0')], ['onenine'], ], onenine: [ [range('19')], ], fraction: [ [], [cp('.'), 'digit', 'digitRepeat0'], ], e: set('Ee'), exponent: [ [], ['e', 'sign', 'digit', 'digitRepeat0'], ], sign: [ [], [cp('+')], [cp('-')], ], ws: set(' \n\r\t'), ...repeat0('ws'), }; const _map = map; return _map; }; export default { example: { module: () => { // Define a simple grammar const grammar = () => [ [range('AZ')], // 'A-Z' [range('az'), grammar], // 'a-z' followed by more grammar ]; const ruleMap = toRuleMap(grammar); const parse = parser(ruleMap); // Parse an input const input = toArray(stringToCodePointList('abcdefgA')); const result = parse(grammar.name, input); if (result === null) { throw result; } const [, b] = result; if (b?.length !== 0) { throw b; } }, }, classic: () => { const c = classic(); const json = stringify(toRuleMap(c.json)); const jsonE = stringify(classicTest()); if (json !== jsonE) { //console.error(json) //console.error(jsonE) throw [json, jsonE]; } }, map: () => { const f = parser(deterministic()); // console.error(stringify(x)) // const isSuccess = (s) => s?.length === 0; const expect = (s, success) => { const [a, r] = f('json', toArray(stringToCodePointList(s))); if (isSuccess(r) !== success) { throw r; } }; // expect(' true ', true); expect(' tr2ue ', false); expect(' true" ', false); expect(' "Hello" ', true); expect(' "Hello ', false); expect(' "Hello\\n\\r\\"" ', true); expect(' -56.7e+5 ', true); expect(' h-56.7e+5 ', false); expect(' -56.7e+5 3', false); expect(' [ 12, false, "a"] ', true); expect(' [ 12, false2, "a"] ', false); expect(' { "q": [ 12, false, [{}], "a"] } ', true); expect(' { "q": [ 12, false, [}], "a"] } ', false); } };