diff options
Diffstat (limited to 'src/paca.mjs')
| -rw-r--r-- | src/paca.mjs | 82 |
1 files changed, 76 insertions, 6 deletions
diff --git a/src/paca.mjs b/src/paca.mjs index ccff1ca..0625d5c 100644 --- a/src/paca.mjs +++ b/src/paca.mjs @@ -46,7 +46,9 @@ const escapingStateStep = ({ out, state, context }, char, _index, next) => : { out: out.concat( char, - shouldConcat(null, next) ? [{ operator: "concat" }] : [], + shouldConcat(null, next) + ? [{ operator: "concat" }] + : [], ), state: ConcatStep.ACCEPTING, context, @@ -167,8 +169,9 @@ const classStateStep = ({ out, state, context }, char, _index, _next) => { return { out: out.concat({ - meta: "class", - set: context.set, + meta: "class", + set: context.set, + caret: !!context.caret, }), state: ConcatStep.ACCEPTING, context: null, @@ -495,7 +498,7 @@ const emptyNFA = () => { }; }; -const baseNFA = (edge, id) => { +const literal = (edge, id) => { const startID = id + 0; const endID = id + 1; const nextID = id + 2; @@ -620,6 +623,63 @@ const zeroOrOne = nfa => { }; }; +const characterClass = ({ set, caret }, id) => { + const start = id + 0; + const end = id + 1; + const nextID = id + 2; + const { string, object } = Object.groupBy(set, x => typeof x); + const matches = new Set(string); + const ranges = Object.fromEntries(object.map( + ({ from, to }) => [ from.charCodeAt(0), to.charCodeAt(0) ], + )); + return { + start, + end, + nextID, + nodes: { + [start]: { + direct: [], + transitions: {}, + meta: { + op: caret ? "excludes" : "includes", + to: end, + matches, + ranges, + }, + }, + [end]: { + direct: [], + transitions: {}, + }, + }, + }; +}; + +const wildcard = (_edge, id) => { + const start = id + 0; + const end = id + 1; + const nextID = id + 2; + return { + start, + end, + nextID, + nodes: { + [start]: { + direct: [], + transitions: {}, + meta: { + op: true, + to: end, + }, + }, + [end]: { + direct: [], + transitions: {}, + }, + }, + }; +}; + const OPERATORS_FNS = ({ zeroOrMoreFn = zeroOrMore, oneOrMoreFn = oneOrMore, @@ -639,11 +699,21 @@ const OPERATORS_FNS = ({ last(stack), )), }); - const OPERATORS = OPERATORS_FNS(); +const METACHARACTERS_FNS = { + "class": characterClass, + ".": wildcard, +}; + +const baseNFA = (token, id) => ( + !token.meta + ? literal + : METACHARACTERS_FNS[token.meta] +)(token, id); + const buildNFAStep = (stack, token) => - typeof token === "string" + !token.operator ? stack.concat(baseNFA(token, last(stack)?.nextID || 1)) : OPERATORS[token.operator](stack); |
