UNPKG

functionalscript

Version:

FunctionalScript is a purely functional subset of JavaScript

171 lines (168 loc) 5.08 kB
import { todo } from "../../dev/module.f.js"; import { stringToCodePointList } from "../../text/utf16/module.f.js"; import { strictEqual } from "../../types/function/operator/module.f.js"; import { map, toArray } from "../../types/list/module.f.js"; import { rangeMap } from "../../types/range_map/module.f.js"; import { oneEncode, rangeDecode, } from "../module.f.js"; const { entries } = Object; const find = (map) => (fr) => { for (const [k, v] of entries(map)) { if (v === fr) { return k; } } return undefined; }; const newName = (map, name) => { let i = 0; let result = name; while (result in map) { result = name + i; ++i; } return result; }; const sequence = (list) => map => { let result = []; let set = {}; for (const fr of list) { const [map1, set1, id] = toDataAdd(map)(fr); map = map1; set = { ...set, ...set1 }; result = [...result, id]; } return [map, set, result]; }; const variant = (fr) => map => { let set = {}; let rule = {}; for (const [k, v] of entries(fr)) { const [m1, s, id] = toDataAdd(map)(v); map = m1; set = { ...set, ...s }; rule = { ...rule, [k]: id }; } return [map, set, rule]; }; const mapOneEncode = map(oneEncode); const data = (dr) => { switch (typeof dr) { case 'string': { return sequence(toArray(mapOneEncode(stringToCodePointList(dr)))); } case 'number': return m => [m, {}, dr]; default: if (dr instanceof Array) { return sequence(dr); } return variant(dr); } }; const toDataAdd = (map) => (fr) => { { const id = find(map)(fr); if (id !== undefined) { return [map, {}, id]; } } const [dr, tmpId] = typeof fr === 'function' ? [fr(), fr.name] : [fr, '']; const newRule = data(dr); const id = newName(map, tmpId); const map1 = { ...map, [id]: fr }; const [map2, set, rule] = newRule(map1); return [map2, { ...set, [id]: rule }, id]; }; export const toData = (fr) => { const [, ruleSet, id] = toDataAdd({})(fr); return [ruleSet, id]; }; const dispatchOp = rangeMap({ union: a => b => { if (a === null) { return b; } if (b === null) { return a; } throw ['can not merge [', a, '][', b, ']']; }, equal: strictEqual, def: null, }); export const dispatchMap = (ruleSet) => { const addRuleToDispatch = (dr, rule) => { if (dr === null) return null; return { tag: dr.tag, rules: [...dr.rules, rule] }; }; const addTagToDispatch = (dr, tag) => { if (dr === null) return null; return { tag, rules: dr.rules }; }; const dispatchRule = (dm, name) => { if (name in dm) { return dm; } const rule = ruleSet[name]; if (typeof rule === 'number') { const range = rangeDecode(rule); const dispatch = dispatchOp.fromRange(range)({ tag: undefined, rules: [] }); const dr = { emptyTag: undefined, rangeMap: dispatch }; return { ...dm, [name]: dr }; } else if (rule instanceof Array) { let emptyTag = true; let result = []; for (const item of rule) { dm = dispatchRule(dm, item); const dr = dm[item]; if (emptyTag === true) { result = toArray(dispatchOp.merge(result)(dr.rangeMap)); emptyTag = dr.emptyTag !== undefined ? true : undefined; } else { result = result.map(x => [addRuleToDispatch(x[0], dr), x[1]]); } } const dr = { emptyTag, rangeMap: result }; return { ...dm, [name]: dr }; } else { const entries = Object.entries(rule); let result = []; let emptyTag = undefined; for (const [tag, item] of entries) { dm = dispatchRule(dm, item); const dr = dm[item]; if (dr.emptyTag !== undefined) { emptyTag = tag; } else { const d = dr.rangeMap.map(x => [addTagToDispatch(x[0], tag), x[1]]); result = toArray(dispatchOp.merge(result)(d)); } } const dr = { emptyTag, rangeMap: result }; return { ...dm, [name]: dr }; } }; let result = {}; for (const k in ruleSet) { result = dispatchRule(result, k); } return result; }; export const parser = (fr) => { const data = toData(fr); return todo(); }; /** * Either `{ variantItem: id }` or `id`. */ /* type DispatchRule = SingleProperty<> | string type Dispatch = RangeMapArray<DispatchRule> type DispatchMap = { readonly[id in string]: Dispatch } */