functionalscript
Version:
FunctionalScript is a purely functional subset of JavaScript
500 lines (499 loc) • 21.1 kB
JavaScript
import { stringify } from "../../json/module.f.js";
import { stringToCodePointList } from "../../text/utf16/module.f.js";
import { identity } from "../../types/function/module.f.js";
import { toArray } from "../../types/list/module.f.js";
import { sort } from "../../types/object/module.f.js";
import { join0Plus, max, option, range, remove, repeat, repeat0Plus, set } from "../module.f.js";
import { classic, deterministic } from "../testlib.f.js";
import { dispatchMap, parser, parserRuleSet, toData, createEmptyTagMap } from "./module.f.js";
export default {
toData: [
() => {
const c = toData(classic());
const d = toData(deterministic());
},
() => {
const stringRule = 'true';
const result = stringify(sort)(toData(stringRule));
if (result !== '[{"":["0","1","2","3"],"0":1946157172,"1":1912602738,"2":1962934389,"3":1694498917},""]') {
throw result;
}
},
() => {
const terminalRangeRule = range('AF');
const result = stringify(sort)(toData(terminalRangeRule));
if (result !== '[{"":1090519110},""]') {
throw result;
} //1090519110 = 65 * 2^24 + 70
},
() => {
const sequenceRangeRule = [range('AF'), range('af')];
const result = stringify(sort)(toData(sequenceRangeRule));
if (result !== '[{"":["0","1"],"0":1090519110,"1":1627390054},""]') {
throw result;
}
},
() => {
const lazyRule = () => 'true';
const result = stringify(sort)(toData(lazyRule));
if (result !== '[{"":1946157172,"0":1912602738,"1":1962934389,"2":1694498917,"lazyRule":["","0","1","2"]},"lazyRule"]') {
throw result;
}
},
() => {
const varintRule = { true: 'true', false: 'false' };
const result = stringify(sort)(toData(varintRule));
const expected = '[{"":{"false":"5","true":"0"},"0":["1","2","3","4"],"1":1946157172,"2":1912602738,"3":1962934389,"4":1694498917,"5":["6","7","8","9","4"],"6":1711276134,"7":1627390049,"8":1811939436,"9":1929379955},""]';
if (result !== expected) {
throw [result, expected];
}
},
() => {
const lazyRule = () => 'true';
const lazyRule0 = () => 'false';
const result = stringify(sort)(toData([lazyRule, lazyRule0]));
const expected = '[{"":["lazyRule","lazyRule0"],"0":1946157172,"1":1912602738,"2":1962934389,"3":1694498917,"4":1711276134,"5":1627390049,"6":1811939436,"7":1929379955,"lazyRule":["0","1","2","3"],"lazyRule0":["4","5","6","7","3"]},""]';
if (result !== expected) {
throw [result, expected];
}
},
() => {
const emptyRule = '';
const result = stringify(sort)(toData(emptyRule));
const expected = '[{"":[]},""]';
if (result !== expected) {
throw [result, expected];
}
},
() => {
const optionRule = option('a');
const result = stringify(identity)(toData(optionRule));
if (result !== '[{"0":["1"],"1":1627390049,"2":[],"":{"some":"0","none":"2"}},""]') {
throw result;
}
},
() => {
const repeatRule = repeat0Plus(option('a'));
const result = stringify(identity)(toData(repeatRule));
if (result !== '[{"0":{"some":"1","none":"3"},"1":["2"],"2":1627390049,"3":[],"":["0","r"],"r":{"some":"","none":"3"}},"r"]') {
throw result;
}
},
() => {
const repeatRule = repeat0Plus(set(' \n\r\t'));
const result = stringify(identity)(toData(repeatRule));
if (result !== '[{"0":{" ":"1","\\n":"2","\\r":"3","\\t":"4"},"1":536870944,"2":167772170,"3":218103821,"4":150994953,"5":[],"":["0","r"],"r":{"some":"","none":"5"}},"r"]') {
throw result;
}
}
],
emptyTags: [
() => {
const stringRule = 'true';
const data = toData(stringRule);
const emptyTags = createEmptyTagMap(data);
const result = JSON.stringify(emptyTags);
if (result !== '{"0":false,"1":false,"2":false,"3":false,"":false}') {
throw result;
}
},
() => {
const terminalRangeRule = range('AF');
const data = toData(terminalRangeRule);
const emptyTags = createEmptyTagMap(data);
const result = JSON.stringify(emptyTags);
if (result !== '{"":false}') {
throw result;
}
},
() => {
const varintRule = { true: 'true', false: 'false' };
const data = toData(varintRule);
const emptyTags = createEmptyTagMap(data);
const result = JSON.stringify(emptyTags);
if (result !== '{"0":false,"1":false,"2":false,"3":false,"4":false,"5":false,"6":false,"7":false,"8":false,"9":false,"":false}') {
throw result;
}
},
() => {
const emptyRule = '';
const data = toData(emptyRule);
const emptyTags = createEmptyTagMap(data);
const result = JSON.stringify(emptyTags);
if (result !== '{"":true}') {
throw result;
}
},
() => {
const emptyRule = '';
const varintRule = { true: 'true', e: emptyRule };
const data = toData(varintRule);
const emptyTags = createEmptyTagMap(data);
const result = JSON.stringify(emptyTags);
if (result !== '{"0":false,"1":false,"2":false,"3":false,"4":false,"5":true,"":"e"}') {
throw result;
}
},
() => {
const repeatRule = repeat0Plus(option('a'));
const data = toData(repeatRule);
const emptyTags = createEmptyTagMap(data);
const result = JSON.stringify(emptyTags);
if (result !== '{"0":"none","1":false,"2":false,"3":true,"r":"none","":true}') {
throw result;
}
},
() => {
const repeatRule = repeat0Plus(set(' \n\r\t'));
const data = toData(repeatRule);
const emptyTags = createEmptyTagMap(data);
const result = JSON.stringify(emptyTags);
if (result !== '{"0":false,"1":false,"2":false,"3":false,"4":false,"5":true,"r":"none","":true}') {
throw result;
}
}
],
variantTest: () => {
const varintRule = { a: 'a', b: 'b' };
const result = stringify(sort)(toData(varintRule));
if (result !== '[{"":{"a":"0","b":"2"},"0":["1"],"1":1627390049,"2":["3"],"3":1644167266},""]') {
throw result;
}
},
dispatch: [
() => {
const terminalRangeRule = range('AF');
const data = toData(terminalRangeRule);
const dm = dispatchMap(data[0]);
const result = JSON.stringify(dm);
if (result !== '{"":{"rangeMap":[[null,64],[{"rules":[]},70]]}}') {
throw result;
}
},
() => {
const stringRule = 'AB';
const data = toData(stringRule);
const dm = dispatchMap(data[0]);
const result = JSON.stringify(dm);
if (result !== '{"0":{"rangeMap":[[null,64],[{"rules":[]},65]]},"1":{"rangeMap":[[null,65],[{"rules":[]},66]]},"":{"rangeMap":[[null,64],[{"rules":["1"]},65]]}}') {
throw result;
}
},
() => {
const a = range('AA');
const b = range('BB');
const ab = [a, b];
const data = toData(ab);
const dm = dispatchMap(data[0]);
const result = JSON.stringify(dm);
if (result !== '{"0":{"rangeMap":[[null,64],[{"rules":[]},65]]},"1":{"rangeMap":[[null,65],[{"rules":[]},66]]},"":{"rangeMap":[[null,64],[{"rules":["1"]},65]]}}') {
throw result;
}
},
() => {
const emptyRule = '';
const data = toData(emptyRule);
const dm = dispatchMap(data[0]);
const result = JSON.stringify(dm);
if (result !== '{"":{"emptyTag":true,"rangeMap":[]}}') {
throw result;
}
},
() => {
const variantRule = { 'a': range('AA'), 'b': range('BB') };
const data = toData(variantRule);
const dm = dispatchMap(data[0]);
const result = JSON.stringify(dm);
if (result !== '{"0":{"rangeMap":[[null,64],[{"rules":[]},65]]},"1":{"rangeMap":[[null,65],[{"rules":[]},66]]},"":{"rangeMap":[[null,64],[{"tag":"a","rules":[]},65],[{"tag":"b","rules":[]},66]]}}') {
throw result;
}
},
() => {
const emptyRule = '';
const variantRule = { 'e': emptyRule, 'a': range('AA') };
const data = toData(variantRule);
const dm = dispatchMap(data[0]);
const result = JSON.stringify(dm);
if (result !== '{"0":{"emptyTag":true,"rangeMap":[]},"1":{"rangeMap":[[null,64],[{"rules":[]},65]]},"":{"emptyTag":"e","rangeMap":[[null,64],[{"tag":"a","rules":[]},65]]}}') {
throw result;
}
},
() => {
const emptyRule = '';
const minursRule = range('--');
const optionalMinusRule = { 'none': emptyRule, 'minus': minursRule };
const digitRule = range('09');
const numberRule = [optionalMinusRule, digitRule];
const data = toData(numberRule);
const dm = dispatchMap(data[0]);
const result = JSON.stringify(dm);
if (result !== '{"0":{"emptyTag":"none","rangeMap":[[null,44],[{"tag":"minus","rules":[]},45]]},"1":{"emptyTag":true,"rangeMap":[]},"2":{"rangeMap":[[null,44],[{"rules":[]},45]]},"3":{"rangeMap":[[null,47],[{"rules":[]},57]]},"":{"rangeMap":[[null,44],[{"tag":"minus","rules":["3"]},45],[null,47],[{"rules":[]},57]]}}') {
throw result;
}
},
() => {
const emptyRule = '';
const spaceRule = range(' ');
const optionalSpaceRule = { 'none': emptyRule, 'space': spaceRule };
const minusRule = range('--');
const optionalMinusRule = { 'none': emptyRule, 'minus': minusRule };
const digitRule = range('09');
const numberRule = [optionalSpaceRule, optionalMinusRule, digitRule];
const data = toData(numberRule);
const dm = dispatchMap(data[0]);
const result = JSON.stringify(dm);
if (result !== '{"0":{"emptyTag":"none","rangeMap":[[null,31],[{"tag":"space","rules":[]},32]]},"1":{"emptyTag":true,"rangeMap":[]},"2":{"rangeMap":[[null,31],[{"rules":[]},32]]},"3":{"emptyTag":"none","rangeMap":[[null,44],[{"tag":"minus","rules":[]},45]]},"4":{"rangeMap":[[null,44],[{"rules":[]},45]]},"5":{"rangeMap":[[null,47],[{"rules":[]},57]]},"":{"rangeMap":[[null,31],[{"tag":"space","rules":["3","5"]},32],[null,44],[{"tag":"minus","rules":["5"]},45],[null,47],[{"rules":[]},57]]}}') {
throw result;
}
}
],
parser: [
() => {
const emptyRule = '';
const m = parser(emptyRule);
const mr = m("", []);
const result = JSON.stringify(mr);
if (result !== '[{"tag":true,"sequence":[]},true,[]]') {
throw result;
}
},
() => {
const emptyRule = '';
const m = parser(emptyRule);
const mr = m("", [65, 70]);
const result = JSON.stringify(mr);
if (result !== '[{"tag":true,"sequence":[]},true,[65,70]]') {
throw result;
}
},
() => {
const terminalRangeRule = range('AF');
const m = parser(terminalRangeRule);
const mr = m("", [65]);
const result = JSON.stringify(mr);
if (result !== '[{"sequence":[65]},true,[]]') {
throw result;
}
},
() => {
const terminalRangeRule = range('AF');
const m = parser(terminalRangeRule);
const mr = m("", [64]);
const result = JSON.stringify(mr);
if (result !== '[{"sequence":[]},false,[64]]') {
throw result;
}
},
() => {
const variantRule = { 'a': range('AA'), 'b': range('BB') };
const m = parser(variantRule);
const mr = m("", [65]);
const result = JSON.stringify(mr);
if (result !== '[{"tag":"a","sequence":[65]},true,[]]') {
throw result;
}
},
() => {
const variantRule = { 'a': range('AA'), 'b': range('BB') };
const m = parser(variantRule);
const mr = m("", [64]);
const result = JSON.stringify(mr);
if (result !== '[{"sequence":[]},false,[64]]') {
throw result;
}
},
() => {
const emptyRule = '';
const variantRule = { 'e': emptyRule, 'a': range('AA') };
const m = parser(variantRule);
const mr = m("", []);
const result = JSON.stringify(mr);
if (result !== '[{"tag":"e","sequence":[]},true,[]]') {
throw result;
}
},
() => {
const emptyRule = '';
const variantRule = { 'e': emptyRule, 'a': range('AA') };
const m = parser(variantRule);
const mr = m("", [64]);
const result = JSON.stringify(mr);
if (result !== '[{"tag":"e","sequence":[]},true,[64]]') {
throw result;
}
},
() => {
const stringRule = 'AB';
const m = parser(stringRule);
const mr = m("", [65, 66]);
const result = JSON.stringify(mr);
if (result !== '[{"sequence":[65,{"sequence":[66]}]},true,[]]') {
throw result;
}
},
() => {
const stringRule = 'AB';
const m = parser(stringRule);
const mr = m("", [65, 67]);
const result = JSON.stringify(mr);
if (result !== '[{"sequence":[]},false,[67]]') {
throw result;
}
},
() => {
const emptyRule = '';
const minursRule = range('--');
const optionalMinusRule = { 'none': emptyRule, 'minus': minursRule };
const digitRule = range('09');
const numberRule = [optionalMinusRule, digitRule];
const m = parser(numberRule);
const mr = m("", [50]);
const result = JSON.stringify(mr);
if (result !== '[{"sequence":[50]},true,[]]') {
throw result;
}
},
() => {
const emptyRule = '';
const minusRule = range('--');
const optionalMinusRule = { 'none': emptyRule, 'minus': minusRule };
const digitRule = range('09');
const numberRule = [optionalMinusRule, digitRule];
const m = parser(numberRule);
const mr = m("", [45, 50]);
const result = JSON.stringify(mr);
if (result !== '[{"tag":"minus","sequence":[45,{"sequence":[50]}]},true,[]]') {
throw result;
}
},
() => {
const m = parser(option('a'));
const isSuccess = (mr) => mr[1] && mr[2]?.length === 0;
const expect = (s, success) => {
const mr = m('', toArray(stringToCodePointList(s)));
if (isSuccess(mr) !== success) {
throw mr;
}
};
expect('a', true);
expect('', true);
expect('aa', false);
expect('b', false);
},
() => {
const ws = repeat0Plus(set(' \n\r\t'));
const commaJoin0Plus = ([open, close], a) => [
open,
ws,
join0Plus([a, ws], [',', ws]),
close,
];
const value = () => ({
object: commaJoin0Plus('{}', 'a'),
array: commaJoin0Plus('[]', 'a')
});
value.name; //bun will fail if no usage of name found
const m = parser(value);
const isSuccess = (mr) => mr[1] && mr[2]?.length === 0;
const expect = (s, success) => {
const mr = m('value', toArray(stringToCodePointList(s)));
if (isSuccess(mr) !== success) {
throw mr;
}
};
expect('[]', true);
expect('[a]', true);
expect('[a, a]', true);
expect('{a}', true);
},
() => {
const m = parser(deterministic());
const isSuccess = (mr) => mr[1] && mr[2]?.length === 0;
const expect = (s, success) => {
const mr = m('', toArray(stringToCodePointList(s)));
if (isSuccess(mr) !== success) {
throw mr;
}
};
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(' [] ', true);
expect(' {} ', true);
expect(' [[[]]] ', true);
expect(' [1] ', true);
expect(' [ 12, false, "a"] ', true);
expect(' [ 12, false2, "a"] ', false);
expect(' { "q": [ 12, false, [{"b" : "c"}], "a"] } ', true);
expect(' { "q": [ 12, false, [{}], "a"] } ', true);
expect(' { "q": [ 12, false, [}], "a"] } ', false);
expect(' [{ "q": [ 12, false, [{}], "a"] }] ', true);
expect(' [{ "q": [ 12, false, [}], "a"] }] ', false);
}
],
repeat: [
() => {
const repeatData = [{ "": ["ws", "repa"], "ws": [], "repa": ["a", ""], "a": 1090519105 }, ""];
const dm = dispatchMap(repeatData[0]);
const result = JSON.stringify(dm);
if (result !== '{"ws":{"emptyTag":true,"rangeMap":[]},"a":{"rangeMap":[[null,64],[{"rules":[]},65]]},"repa":{"rangeMap":[[null,64],[{"rules":[""]},65]]},"":{"rangeMap":[[null,64],[{"rules":[""]},65]]}}') {
throw result;
}
}
],
repeatParser: [
() => {
const repeatData = [{ "": ["ws", "repa"], "ws": [], "repa": ["a", ""], "a": 1090519105 }, ""];
const m = parserRuleSet(repeatData[0]);
const mr = m("", []);
const result = JSON.stringify(mr);
if (result !== '[{"sequence":[]},true,null]') {
throw result;
}
},
() => {
const repeatData = [{ "": ["ws", "repa"], "ws": [], "repa": ["a", ""], "a": 1090519105 }, ""];
const m = parserRuleSet(repeatData[0]);
const mr = m("", [65]);
const result = JSON.stringify(mr);
if (result !== '[{"sequence":[65,{"sequence":[]}]},true,null]') {
throw result;
}
},
() => {
const repeatData = [{ "": ["ws", "repa"], "ws": [], "repa": ["a", ""], "a": 1090519105 }, ""];
const m = parserRuleSet(repeatData[0]);
const mr = m("", [65, 65, 65]);
const result = JSON.stringify(mr);
if (result !== '[{"sequence":[65,{"sequence":[65,{"sequence":[65,{"sequence":[]}]}]}]},true,null]') {
throw result;
}
},
() => {
const repeatData = [{ "": ["ws", "repa"], "ws": [], "repa": ["a", ""], "a": 1090519105 }, ""];
const m = parserRuleSet(repeatData[0]);
const mr = m("", [66]);
const result = JSON.stringify(mr);
if (result !== '[{"sequence":[]},false,[66]]') {
throw result;
}
}
],
example: () => {
const grammar = {
space: 0x000020_000020,
digit: 0x000030_000039,
sequence: ['space', 'digit'],
spaceOrDigit: {
'whiteSpace': 'space',
'digit': 'digit',
}
};
}
};