parser-combinators 1.1.3 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  ## Parser Combinators
2
2
 
3
- ![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/michalusio/Parser/CI/master)
3
+ [![CI](https://github.com/michalusio/Parser/actions/workflows/CI.yml/badge.svg)](https://github.com/michalusio/Parser/actions/workflows/CI.yml)
4
4
  [![CodeQL](https://github.com/michalusio/Parser/actions/workflows/codeql-analysis.yml/badge.svg?branch=master)](https://github.com/michalusio/Parser/actions/workflows/codeql-analysis.yml)
5
- ![Codecov](https://img.shields.io/codecov/c/github/michalusio/Parser)
5
+ [![codecov](https://codecov.io/gh/michalusio/Parser/branch/master/graph/badge.svg?token=gtTR0hPodY)](https://codecov.io/gh/michalusio/Parser)
6
6
 
7
7
  ![NPM](https://img.shields.io/npm/l/parser-combinators)
8
8
  [![NPM Version](https://badge.fury.io/js/parser-combinators.svg)](https://badge.fury.io/js/parser-combinators)
@@ -33,12 +33,14 @@ A library of parser combinators, with which you can create your own parsers.
33
33
  - `opt`ional
34
34
  - `regex`
35
35
  - `seq`uence
36
- - `str`ing
36
+ - `str`ing and `stri`ng (case-insensitive)
37
37
  - Utility combinators:
38
38
  - `ref`er
39
39
  - `expect`
40
40
  - `expectErase`
41
41
  - `surely`
42
+ - `token`
43
+ - `lookaround`
42
44
  - Ready-made value combinators:
43
45
  - `spaces`
44
46
  - `spacesPlus`
@@ -46,10 +48,28 @@ A library of parser combinators, with which you can create your own parsers.
46
48
  - `bool` (and `boolP`)
47
49
  - `int` (and `intP`)
48
50
  - `real` (and `realP`)
51
+ - `eof`
52
+ - Recovery combinators:
53
+ - `recoverBySkippingChars`
54
+ - `recoverByAddingChars`
49
55
  - Whole parsers:
50
56
  - Extended Backus-Naur Form (`EBNF`)
51
57
  - JavaScript Object Notation (`JSON`)
52
58
 
59
+ ##### Optimization remarks:
60
+
61
+ Combining many string parsers using an `any` parser uses parser fusion.
62
+ This means that a parser of the form e.g. `any(str(...), ..., str())` is automatically converted into a search trie.
63
+ This drastically decreases the number of callbacks, and improves performance because all search strings are checked "at once" by going over the trie.
64
+
65
+ Nested `any` parsers are also supported, as well as `stri` parsers, so all of these undergo fusion:
66
+
67
+ any(str('QeQMTvqJuS'), str('IoOYSLNPlM'), str('SpFMUWpzHs'))
68
+
69
+ any(str('QeQMTvqJuS'), any(str('IoOYSLNPlM'), str('SpFMUWpzHs')))
70
+
71
+ any(str('QeQMTvqJuS'), stri('QeQMTvqJuS'), str('QeqmtabeacErEmTDUUIFcFpsAJhfwqXN'), str('SpFMUWpzHs'))
72
+
53
73
  ### Example usage:
54
74
 
55
75
  ##### Using standard combinators:
@@ -85,3 +105,24 @@ A library of parser combinators, with which you can create your own parsers.
85
105
  'The number must be over 1.5!'
86
106
  );
87
107
  const result = ParseText(' number: 1.25 ', parser); // Will throw a ParseError('The number must be over 1.5!')
108
+
109
+ ##### Pretty messages available on parsing errors:
110
+
111
+ import { spacesPlus, str } from 'parser-combinators/parsers';
112
+ import { ParseText } from 'parser-combinators';
113
+
114
+ const parser = seq(
115
+ str('Lazy fox jumps'), spacesPlus, str('over'), spacesPlus, str('a lazy dog')
116
+ );
117
+
118
+ try {
119
+ const result = ParseText('Lazy fox jumps under a lazy dog', parser);
120
+ } catch (e) {
121
+ console.error(e.getPrettyErrorMessage());
122
+ }
123
+
124
+ Will write:
125
+
126
+ Parse error, expected over at char 15 (line 1, col 16):
127
+ Lazy fox jumps under a lazy dog
128
+ ---------------^
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from "./types";
2
- export * from "./parsers";
3
- export * from "./parser";
1
+ export * from "./types";
2
+ export * from "./parsers";
3
+ export * from "./parser";
package/dist/index.js CHANGED
@@ -1,19 +1,19 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./types"), exports);
18
- __exportStar(require("./parsers"), exports);
19
- __exportStar(require("./parser"), exports);
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types"), exports);
18
+ __exportStar(require("./parsers"), exports);
19
+ __exportStar(require("./parser"), exports);
@@ -0,0 +1,4 @@
1
+ "use strict";(()=>{var a=(e,n)=>()=>(n||e((n={exports:{}}).exports,n),n.exports);var l=a(p=>{"use strict";Object.defineProperty(p,"__esModule",{value:!0});p.ParseError=void 0;p.isFailure=be;p.success=k;p.failure=ee;p.result=ve;p.fail=Pe;function be(e){return!e.success}function k(e,n){return{success:!0,value:n,ctx:e}}function ee(e,n,t){return{success:!1,expected:n,ctx:e,history:t}}function ve(e){return n=>k(n,e)}function Pe(e){return n=>ee(n,e,[e])}var B=class extends Error{constructor(n,t,r,s){super(n),this.index=r,this.history=s,[this.line,this.column,this.row]=this.getInputData(t,r)}getInputData(n,t){let r=n.split(`
2
+ `),s=0;for(;t>0;){if(r[s].length>t)return[r[s],t+1,s+1];t-=r[s].length+1,s+=1}return[r[s],t+1,s+1]}getPrettyErrorMessage(){return`${this.message} (line ${this.row}, col ${this.column}):
3
+ ${this.line}
4
+ ${(this.column>0?"-".repeat(this.column-1):"")+"^"}`}};p.ParseError=B});var te=a(z=>{"use strict";Object.defineProperty(z,"__esModule",{value:!0});z.anyString=Oe;var re=l();function Oe(e){let n=`'${e[e.length-1][0]}'`,t;return Object.assign(r=>{t??=we(e);let s=Me(t,r.text,r.index);return s?(0,re.success)({...r,index:s.end},e[s.matchIndex][0]):(0,re.failure)(r,n,["any",n])},{parserType:"anyString",matches:e})}function we(e){let n=new Map;return e.forEach((t,r)=>w(n,t,r)),n}function w(e,n,t,r=0){if(r>=n[0].length)e.matchIndex!=null?e.matchIndex=Math.min(e.matchIndex,t):e.matchIndex=t;else{let s=n[0][r],u=s.toLowerCase(),i=s.toUpperCase(),g=new Map;if(n[1]&&u!==i){let q=e.get(u)??g,_=e.get(i)??g;e.set(u,q),e.set(i,_),w(q,n,t,r+1),q!==_&&w(_,n,t,r+1)}else{let q=e.get(s)??g;e.set(s,q);let _=e.get(u);if(_===e.get(i)){let Z=new Map(_.entries());Z.matchIndex=_.matchIndex,e.set(i,Z)}w(q,n,t,r+1)}}}function Me(e,n,t){let r,s,u=e;for(let i=t;i<n.length;i++){let g=n[i];if(u.matchIndex!=null&&(s==null||u.matchIndex<=s)&&(r=i,s=u.matchIndex),u=u.get(g),!u)break}return u&&u.matchIndex!=null&&(s==null||u.matchIndex<=s)&&(r=n.length,s=u.matchIndex),r==null?void 0:{end:r,matchIndex:s}}});var M=a(f=>{"use strict";Object.defineProperty(f,"__esModule",{value:!0});f.toggleFusions=f.shouldPerformFusions=void 0;f.ref=Fe;f.expect=se;f.expectErase=Se;f.surely=$e;f.token=Te;f.lookaround=Ie;var h=l(),je=()=>ne;f.shouldPerformFusions=je;var ne=!0,me=e=>{ne=e};f.toggleFusions=me;function Fe(e,n,t){return r=>{let s=e(r);return!(0,h.isFailure)(s)&&!n(s.value)?(0,h.failure)(s.ctx,t??"check",[`ref: ${t??"check"}`]):s}}function se(e,n){return t=>{let r=e(t);return(0,h.isFailure)(r)?(0,h.failure)(r.ctx,n,[n,...r.history]):r}}function Se(e,n){return t=>{let r=e(t);return(0,h.isFailure)(r)?(0,h.failure)(r.ctx,n,[n]):r}}function $e(e){return se(e,"surely")}function Te(e){return n=>{let t=e(n);return t.success?{...t,value:{value:t.value,start:n.index,end:t.ctx.index}}:t}}function Ie(e){return n=>{let t=e(n);return t.success?(0,h.success)(n,void 0):(0,h.failure)(n,t.expected,["lookaround",...t.history])}}});var ue=a(R=>{"use strict";Object.defineProperty(R,"__esModule",{value:!0});R.any=ze;var D=l(),Ee=te(),Ce=M(),Be=["str","stri","anyString"];function ze(...e){let n={};if((0,Ce.shouldPerformFusions)()&&e.every(t=>"parserType"in t&&typeof t.parserType=="string"&&Be.includes(t.parserType))){let r=e.flatMap(s=>{switch(s.parserType){case"anyString":return s.matches;case"str":return[[s.match,!1]];case"stri":return[[s.match,!0]]}});if(r.length>10)return(0,Ee.anyString)(r);n={parserType:"anyString",matches:r}}return Object.assign(t=>{let r=[];for(let u of e){let i=u(t);if((0,D.isFailure)(i)){if(i.history.includes("surely"))return(0,D.failure)(i.ctx,i.expected,i.history.filter(g=>g!=="surely"));r.push(i)}else return i}let s=r.reduce((u,i)=>u.history.length>i.history.length?u:i);return(0,D.failure)(s.ctx,s.expected,["any",...s.history])},n)}});var v=a(Q=>{"use strict";Object.defineProperty(Q,"__esModule",{value:!0});Q.seq=De;var N=l();function De(...e){return n=>{let t=[];for(let r of e){let s=r(n);if(n=s.ctx,(0,N.isFailure)(s))return(0,N.failure)(s.ctx,s.expected,["seq",...s.history]);t.push(s.value)}return(0,N.success)(n,t)}}});var oe=a(A=>{"use strict";Object.defineProperty(A,"__esModule",{value:!0});A.between=Ne;var ie=l(),Re=v();function Ne(e,n,t){let r=(0,Re.seq)(e,n,t);return s=>{let u=r(s);if((0,ie.isFailure)(u)){let i=[...u.history];return i.splice(0,1),(0,ie.failure)(u.ctx,u.expected,["between",...i])}return{...u,value:u.value[1]}}}});var ce=a(H=>{"use strict";Object.defineProperty(H,"__esModule",{value:!0});H.exhaust=Qe;var P=l();function Qe(e,n=null){return t=>{let r=[];for(;;){let s=e(t);if((0,P.isFailure)(s))return n===null||(0,P.isFailure)(n(t))?(0,P.failure)(s.ctx,s.expected,["exhaust",...s.history]):(0,P.success)(t,r);if(t=s.ctx,r.push(s.value),s.ctx.index===s.ctx.text.length)return(0,P.success)(s.ctx,r)}}}});var m=a(L=>{"use strict";Object.defineProperty(L,"__esModule",{value:!0});L.map=Ae;var j=l();function Ae(e,n){return t=>{let r=e(t);if((0,j.isFailure)(r))return(0,j.failure)(r.ctx,r.expected,["map",...r.history]);try{let s=n(r.value);return(0,j.success)(r.ctx,s)}catch{return(0,j.failure)(r.ctx,"Error while mapping",["map"])}}}});var F=a(U=>{"use strict";Object.defineProperty(U,"__esModule",{value:!0});U.opt=He;var ae=l();function He(e){return n=>{let t=e(n);return(0,ae.isFailure)(t)?(0,ae.success)(n,null):t}}});var fe=a(b=>{"use strict";Object.defineProperty(b,"__esModule",{value:!0});b.many=V;b.zeroOrMany=Ue;b.oneOrMany=le;b.oneOrManyRed=Ve;var S=l(),x=m(),Le=F(),$=v();function V(e){return n=>{let t=[];for(;;){let r=e(n);if((0,S.isFailure)(r))return(0,S.success)(n,t);n=r.ctx,t.push(r.value)}}}function Ue(e,n){return(0,x.map)((0,Le.opt)(le(e,n)),t=>t??[])}function le(e,n=void 0){let t=(0,x.map)((0,$.seq)(e,V(n?(0,x.map)((0,$.seq)(n,e),([,r])=>r):e)),([r,s])=>[r,...s]);return r=>{let s=t(r);if((0,S.isFailure)(s)){let u=[...s.history];return u.splice(0,2),(0,S.failure)(s.ctx,s.expected,["oneOrMany",...u])}return s}}function Ve(e,n,t){return(0,x.map)((0,x.map)((0,$.seq)((0,x.map)(e,r=>[null,r]),V((0,$.seq)(n,e))),([r,s])=>[r,...s]),r=>{let s=r[0][1];for(let u=1;u<r.length;u++)s=t(s,r[u][1],r[u][0]);return s})}});var G=a(W=>{"use strict";Object.defineProperty(W,"__esModule",{value:!0});W.regex=We;var de=l();function We(e,n){let t=new RegExp(e,typeof e=="string"?"y":e.flags+"y");return r=>{t.lastIndex=r.index;let s=t.exec(r.text);return s!==null&&s.index===r.index?(0,de.success)({...r,index:r.index+s[0].length},s[0]):(0,de.failure)(r,n,[n])}}});var J=a(I=>{"use strict";Object.defineProperty(I,"__esModule",{value:!0});I.str=Ge;I.stri=Ke;var T=l();function Ge(e){let n=`'${e}'`;return Object.assign(t=>t.text.startsWith(e,t.index)?(0,T.success)({...t,index:t.index+e.length},e):(0,T.failure)(t,n,[n]),{parserType:"str",match:e})}var Je=new Intl.Collator("en",{sensitivity:"accent"});function Ke(e){let n=e.toLowerCase(),t=`'${n}'`;return Object.assign(r=>{let s=r.text.slice(r.index,r.index+e.length);return Je.compare(e,s)==0?(0,T.success)({...r,index:r.index+e.length},n):(0,T.failure)(r,t,[t])},{parserType:"stri",match:n})}});var ye=a(E=>{"use strict";Object.defineProperty(E,"__esModule",{value:!0});E.recoverBySkippingChars=Xe;E.recoverByAddingChars=Ye;var pe=l();function Xe(e,n){return t=>{let r=null;for(let s=0;s<=n;s++){let u=e({index:t.index+s,path:t.path,text:t.text});if((0,pe.isFailure)(u))r??=u;else return u}return r}}function Ye(e,n){return t=>{let r=null;for(let s=0;s<=n.length;s++){let u=n.slice(0,s),i=e({index:t.index,path:t.path,text:`${t.text.slice(0,t.index)}${u}${t.text.slice(t.index)}`});if((0,pe.isFailure)(i))r??=i;else return i}return r}}});var ge=a(o=>{"use strict";Object.defineProperty(o,"__esModule",{value:!0});o.eof=o.realP=o.real=o.intP=o.int=o.boolP=o.bool=o.wspaces=o.spacesPlus=o.spaces=void 0;var he=l(),C=m(),Ze=F(),O=G(),ke=v(),er=J(),rr=M();o.spaces=(0,O.regex)(/ */,"spaces");o.spacesPlus=(0,O.regex)(/ +/,"spaces");o.wspaces=(0,Ze.opt)((0,O.regex)(/(?:\s|\t|\n|\r)+/,"whitespace characters"));o.bool=(0,O.regex)(/true|false/,"boolean");o.boolP=(0,C.map)(o.bool,e=>e==="true");o.int=(0,O.regex)(/\d+/,"integer");o.intP=(0,C.map)(o.int,e=>parseInt(e,10));o.real=(0,rr.expect)((0,C.map)((0,ke.seq)(o.int,(0,er.str)("."),o.int),([e,,n])=>`${e}.${n}`),"real");o.realP=(0,C.map)(o.real,e=>parseFloat(e));var tr=e=>e.index===e.text.length?(0,he.success)(e,void 0):(0,he.failure)(e,"End Of File",["EOF"]);o.eof=tr});var qe=a(c=>{"use strict";var nr=c&&c.__createBinding||(Object.create?(function(e,n,t,r){r===void 0&&(r=t);var s=Object.getOwnPropertyDescriptor(n,t);(!s||("get"in s?!n.__esModule:s.writable||s.configurable))&&(s={enumerable:!0,get:function(){return n[t]}}),Object.defineProperty(e,r,s)}):(function(e,n,t,r){r===void 0&&(r=t),e[r]=n[t]})),d=c&&c.__exportStar||function(e,n){for(var t in e)t!=="default"&&!Object.prototype.hasOwnProperty.call(n,t)&&nr(n,e,t)};Object.defineProperty(c,"__esModule",{value:!0});c.stri=c.str=void 0;d(ue(),c);d(oe(),c);d(ce(),c);d(fe(),c);d(m(),c);d(F(),c);d(G(),c);d(v(),c);var _e=J();Object.defineProperty(c,"str",{enumerable:!0,get:function(){return _e.str}});Object.defineProperty(c,"stri",{enumerable:!0,get:function(){return _e.stri}});d(ye(),c);d(M(),c);d(ge(),c)});var xe=a(X=>{"use strict";Object.defineProperty(X,"__esModule",{value:!0});X.ParseText=sr;var K=l();function sr(e,n,t=""){let r=n({text:e,path:t,index:0});if((0,K.isFailure)(r))throw new K.ParseError(`Parse error, expected ${[...r.history].pop()} at char ${r.ctx.index}`,e,r.ctx.index,r.history);if(r.ctx.index!==e.length)throw new K.ParseError(`Parse error, expected end of text at char ${r.ctx.index}`,e,r.ctx.index,[]);return r.value}});var ir=a(y=>{var ur=y&&y.__createBinding||(Object.create?(function(e,n,t,r){r===void 0&&(r=t);var s=Object.getOwnPropertyDescriptor(n,t);(!s||("get"in s?!n.__esModule:s.writable||s.configurable))&&(s={enumerable:!0,get:function(){return n[t]}}),Object.defineProperty(e,r,s)}):(function(e,n,t,r){r===void 0&&(r=t),e[r]=n[t]})),Y=y&&y.__exportStar||function(e,n){for(var t in e)t!=="default"&&!Object.prototype.hasOwnProperty.call(n,t)&&ur(n,e,t)};Object.defineProperty(y,"__esModule",{value:!0});Y(l(),y);Y(qe(),y);Y(xe(),y)});ir();})();
package/dist/parser.d.ts CHANGED
@@ -1,16 +1,9 @@
1
- import { Parser } from './types';
2
- /** Parses the utf-8 content of a given file's content.
3
- * @param path The path to the file to parse.
4
- * @param parser The parser to use.
5
- * @returns The result of the parse.
6
- * @throws {ParseError} if the parsing fails or the parser does not consume the full input.
7
- */
8
- export declare function ParseFile<T>(path: string, parser: Parser<T>): T;
9
- /** Parses the given string.
10
- * @param text The string to parse.
11
- * @param parser The parser to use.
12
- * @param path The path of the parsed text. Can be used for error reporting.
13
- * @returns The result of the parse.
14
- * @throws {ParseError} if the parsing fails or the parser does not consume the full input.
15
- */
16
- export declare function ParseText<T>(text: string, parser: Parser<T>, path?: string): T;
1
+ import { Parser } from './types';
2
+ /** Parses the given string.
3
+ * @param text The string to parse.
4
+ * @param parser The parser to use.
5
+ * @param path The path of the parsed text. Can be used for error reporting.
6
+ * @returns The result of the parse.
7
+ * @throws {ParseError} if the parsing fails or the parser does not consume the full input.
8
+ */
9
+ export declare function ParseText<T>(text: string, parser: Parser<T>, path?: string): T;
package/dist/parser.js CHANGED
@@ -1,34 +1,21 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ParseText = exports.ParseFile = void 0;
4
- const fs = require("fs");
5
- const types_1 = require("./types");
6
- /** Parses the utf-8 content of a given file's content.
7
- * @param path The path to the file to parse.
8
- * @param parser The parser to use.
9
- * @returns The result of the parse.
10
- * @throws {ParseError} if the parsing fails or the parser does not consume the full input.
11
- */
12
- function ParseFile(path, parser) {
13
- const text = fs.readFileSync(path, 'utf8');
14
- return ParseText(text, parser, path);
15
- }
16
- exports.ParseFile = ParseFile;
17
- /** Parses the given string.
18
- * @param text The string to parse.
19
- * @param parser The parser to use.
20
- * @param path The path of the parsed text. Can be used for error reporting.
21
- * @returns The result of the parse.
22
- * @throws {ParseError} if the parsing fails or the parser does not consume the full input.
23
- */
24
- function ParseText(text, parser, path = '') {
25
- const res = parser({ text, path, index: 0 });
26
- if ((0, types_1.isFailure)(res)) {
27
- throw new types_1.ParseError(`Parse error, expected ${[...res.history].pop()} at char ${res.ctx.index}`, text, res.ctx.index, res.history);
28
- }
29
- if (res.ctx.index !== text.length) {
30
- throw new types_1.ParseError(`Parse error at index ${res.ctx.index}`, text, res.ctx.index, []);
31
- }
32
- return res.value;
33
- }
34
- exports.ParseText = ParseText;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ParseText = ParseText;
4
+ const types_1 = require("./types");
5
+ /** Parses the given string.
6
+ * @param text The string to parse.
7
+ * @param parser The parser to use.
8
+ * @param path The path of the parsed text. Can be used for error reporting.
9
+ * @returns The result of the parse.
10
+ * @throws {ParseError} if the parsing fails or the parser does not consume the full input.
11
+ */
12
+ function ParseText(text, parser, path = '') {
13
+ const res = parser({ text, path, index: 0 });
14
+ if ((0, types_1.isFailure)(res)) {
15
+ throw new types_1.ParseError(`Parse error, expected ${[...res.history].pop()} at char ${res.ctx.index}`, text, res.ctx.index, res.history);
16
+ }
17
+ if (res.ctx.index !== text.length) {
18
+ throw new types_1.ParseError(`Parse error, expected end of text at char ${res.ctx.index}`, text, res.ctx.index, []);
19
+ }
20
+ return res.value;
21
+ }
@@ -1,17 +1,16 @@
1
- import { Parser } from '../types';
2
- /** Parses the input using any passed parser, trying from left to right.
3
- * @returns A parser returning the result of the first parser that succeeds, or the failure that has come the furthest.
4
- */
5
- export declare function any<T, U, V, W, X, Z, I, J, K, L, M>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>, Parser<L>, Parser<M>]): Parser<T | U | V | W | X | Z | I | J | K | L | M>;
6
- export declare function any<T, U, V, W, X, Z, I, J, K, L>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>, Parser<L>]): Parser<T | U | V | W | X | Z | I | J | K | L>;
7
- export declare function any<T, U, V, W, X, Z, I, J, K>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>]): Parser<T | U | V | W | X | Z | I | J | K>;
8
- export declare function any<T, U, V, W, X, Z, I, J>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>]): Parser<T | U | V | W | X | Z | I | J>;
9
- export declare function any<T, U, V, W, X, Z, I>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>]): Parser<T | U | V | W | X | Z | I>;
10
- export declare function any<T, U, V, W, X, Z>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>]): Parser<T | U | V | W | X | Z>;
11
- export declare function any<T, U, V, W, X>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>]): Parser<T | U | V | W | X>;
12
- export declare function any<T, U, V, W>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>]): Parser<T | U | V | W>;
13
- export declare function any<T, U, V>(...parsers: [Parser<T>, Parser<U>, Parser<V>]): Parser<T | U | V>;
14
- export declare function any<T, U>(...parsers: [Parser<T>, Parser<U>]): Parser<T | U>;
15
- export declare function any<T>(...parsers: [Parser<T>]): Parser<T>;
16
- export declare function any<T>(...parsers: Parser<T>[]): Parser<T>;
17
- export declare function surely<T>(parser: Parser<T>): Parser<T>;
1
+ import { Parser } from '../types';
2
+ /** Parses the input using any passed parser, trying from left to right.
3
+ * @returns A parser returning the result of the first parser that succeeds, or the failure that has come the furthest.
4
+ */
5
+ export declare function any<T, U, V, W, X, Z, I, J, K, L, M>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>, Parser<L>, Parser<M>]): Parser<T | U | V | W | X | Z | I | J | K | L | M>;
6
+ export declare function any<T, U, V, W, X, Z, I, J, K, L>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>, Parser<L>]): Parser<T | U | V | W | X | Z | I | J | K | L>;
7
+ export declare function any<T, U, V, W, X, Z, I, J, K>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>, Parser<K>]): Parser<T | U | V | W | X | Z | I | J | K>;
8
+ export declare function any<T, U, V, W, X, Z, I, J>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>, Parser<J>]): Parser<T | U | V | W | X | Z | I | J>;
9
+ export declare function any<T, U, V, W, X, Z, I>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>, Parser<I>]): Parser<T | U | V | W | X | Z | I>;
10
+ export declare function any<T, U, V, W, X, Z>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>, Parser<Z>]): Parser<T | U | V | W | X | Z>;
11
+ export declare function any<T, U, V, W, X>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>, Parser<X>]): Parser<T | U | V | W | X>;
12
+ export declare function any<T, U, V, W>(...parsers: [Parser<T>, Parser<U>, Parser<V>, Parser<W>]): Parser<T | U | V | W>;
13
+ export declare function any<T, U, V>(...parsers: [Parser<T>, Parser<U>, Parser<V>]): Parser<T | U | V>;
14
+ export declare function any<T, U>(...parsers: [Parser<T>, Parser<U>]): Parser<T | U>;
15
+ export declare function any<T>(...parsers: [Parser<T>]): Parser<T>;
16
+ export declare function any<T>(...parsers: Parser<T>[]): Parser<T>;
@@ -1,29 +1,47 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.surely = exports.any = void 0;
4
- const _1 = require(".");
5
- const types_1 = require("../types");
6
- function any(...parsers) {
7
- return (ctx) => {
8
- const expected = [];
9
- for (const parser of parsers) {
10
- const res = parser(ctx);
11
- if ((0, types_1.isFailure)(res)) {
12
- if (res.history.includes('surely')) {
13
- console.log('shot');
14
- return (0, types_1.failure)(res.ctx, res.expected, res.history.filter(h => h !== 'surely'));
15
- }
16
- expected.push(res);
17
- }
18
- else
19
- return res;
20
- }
21
- const longest = expected.reduce((a, b) => a.history.length > b.history.length ? a : b);
22
- return (0, types_1.failure)(longest.ctx, longest.expected, ['any', ...longest.history]);
23
- };
24
- }
25
- exports.any = any;
26
- function surely(parser) {
27
- return (0, _1.expect)(parser, 'surely');
28
- }
29
- exports.surely = surely;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.any = any;
4
+ const types_1 = require("../types");
5
+ const anyString_1 = require("./anyString");
6
+ const utilities_1 = require("./utilities");
7
+ const optimizableTypes = ['str', 'stri', 'anyString'];
8
+ function any(...parsers) {
9
+ let marker = {};
10
+ if ((0, utilities_1.shouldPerformFusions)() && parsers.every(p => 'parserType' in p && typeof p.parserType === 'string' && optimizableTypes.includes(p.parserType))) {
11
+ const optimizableParsers = parsers;
12
+ const matches = optimizableParsers.flatMap(p => {
13
+ switch (p.parserType) {
14
+ case 'anyString':
15
+ return p.matches;
16
+ case 'str':
17
+ return [[p.match, false]];
18
+ case 'stri':
19
+ return [[p.match, true]];
20
+ }
21
+ });
22
+ // Not fusing if not enough matches
23
+ // We do pass the matches forward though, because a parser above may want to fuse
24
+ if (matches.length > 10) {
25
+ return (0, anyString_1.anyString)(matches);
26
+ }
27
+ else {
28
+ marker = { parserType: 'anyString', matches };
29
+ }
30
+ }
31
+ return Object.assign((ctx) => {
32
+ const expected = [];
33
+ for (const parser of parsers) {
34
+ const res = parser(ctx);
35
+ if ((0, types_1.isFailure)(res)) {
36
+ if (res.history.includes('surely')) {
37
+ return (0, types_1.failure)(res.ctx, res.expected, res.history.filter(h => h !== 'surely'));
38
+ }
39
+ expected.push(res);
40
+ }
41
+ else
42
+ return res;
43
+ }
44
+ const longest = expected.reduce((a, b) => a.history.length > b.history.length ? a : b);
45
+ return (0, types_1.failure)(longest.ctx, longest.expected, ['any', ...longest.history]);
46
+ }, marker);
47
+ }
@@ -0,0 +1,15 @@
1
+ import { Parser } from "../types";
2
+ import { StrIParser, StrParser } from "./str";
3
+ type AnyStringParser<T> = Parser<T> & {
4
+ parserType: 'anyString';
5
+ /**
6
+ * if flag is true, match case-insensitive
7
+ */
8
+ matches: (readonly [string, boolean])[];
9
+ };
10
+ export type OptimizableStrParser<T> = AnyStringParser<T> | StrParser<T> | StrIParser<T>;
11
+ /**
12
+ * Optimization for `any(str(), str(), ...)` which replaces the parser tree with one parser which tries all strings together
13
+ */
14
+ export declare function anyString<T extends string>(matches: (readonly [string, boolean])[]): AnyStringParser<T>;
15
+ export {};
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.anyString = anyString;
4
+ const types_1 = require("../types");
5
+ /**
6
+ * Optimization for `any(str(), str(), ...)` which replaces the parser tree with one parser which tries all strings together
7
+ */
8
+ function anyString(matches) {
9
+ const lastMatchInQuotes = `'${matches[matches.length - 1][0]}'`;
10
+ let tree;
11
+ return Object.assign((ctx) => {
12
+ tree ??= createSearchTree(matches);
13
+ const result = searchThroughTree(tree, ctx.text, ctx.index);
14
+ if (result) {
15
+ return (0, types_1.success)({ ...ctx, index: result.end }, matches[result.matchIndex][0]);
16
+ }
17
+ else {
18
+ return (0, types_1.failure)(ctx, lastMatchInQuotes, ['any', lastMatchInQuotes]);
19
+ }
20
+ }, { parserType: 'anyString', matches });
21
+ }
22
+ function createSearchTree(matches) {
23
+ const tree = new Map();
24
+ matches.forEach((match, index) => addMatchToTree(tree, match, index));
25
+ return tree;
26
+ }
27
+ function addMatchToTree(node, match, idIndex, charIndex = 0) {
28
+ if (charIndex >= match[0].length) {
29
+ if (node.matchIndex != undefined) {
30
+ node.matchIndex = Math.min(node.matchIndex, idIndex);
31
+ }
32
+ else {
33
+ node.matchIndex = idIndex;
34
+ }
35
+ }
36
+ else {
37
+ const char = match[0][charIndex];
38
+ const lowercase = char.toLowerCase();
39
+ const uppercase = char.toUpperCase();
40
+ const newNode = new Map();
41
+ if (match[1] && (lowercase !== uppercase)) {
42
+ const lower = node.get(lowercase) ?? newNode;
43
+ const upper = node.get(uppercase) ?? newNode;
44
+ node.set(lowercase, lower);
45
+ node.set(uppercase, upper);
46
+ addMatchToTree(lower, match, idIndex, charIndex + 1);
47
+ if (lower !== upper) {
48
+ addMatchToTree(upper, match, idIndex, charIndex + 1);
49
+ }
50
+ }
51
+ else {
52
+ const charNode = node.get(char) ?? newNode;
53
+ node.set(char, charNode);
54
+ const lower = node.get(lowercase);
55
+ if (lower === node.get(uppercase)) {
56
+ const copy = new Map(lower.entries());
57
+ copy.matchIndex = lower.matchIndex;
58
+ node.set(uppercase, copy);
59
+ }
60
+ addMatchToTree(charNode, match, idIndex, charIndex + 1);
61
+ }
62
+ }
63
+ }
64
+ function searchThroughTree(node, text, start) {
65
+ let lastSuccessIndex = undefined;
66
+ let lastSuccessMatchIndex = undefined;
67
+ let currentNode = node;
68
+ for (let index = start; index < text.length; index++) {
69
+ const char = text[index];
70
+ if (currentNode.matchIndex != undefined && (lastSuccessMatchIndex == undefined || currentNode.matchIndex <= lastSuccessMatchIndex)) {
71
+ lastSuccessIndex = index;
72
+ lastSuccessMatchIndex = currentNode.matchIndex;
73
+ }
74
+ currentNode = currentNode.get(char);
75
+ if (!currentNode)
76
+ break;
77
+ }
78
+ if (currentNode && currentNode.matchIndex != undefined && (lastSuccessMatchIndex == undefined || currentNode.matchIndex <= lastSuccessMatchIndex)) {
79
+ lastSuccessIndex = text.length;
80
+ lastSuccessMatchIndex = currentNode.matchIndex;
81
+ }
82
+ return lastSuccessIndex == undefined
83
+ ? undefined
84
+ : { end: lastSuccessIndex, matchIndex: lastSuccessMatchIndex };
85
+ }
@@ -1,5 +1,5 @@
1
- import { Parser } from '../types';
2
- /** Parses a sequence of three parsers.
3
- * @returns A parser returning only the middle parser's result.
4
- */
5
- export declare function between<T, U, V>(left: Parser<U>, parser: Parser<T>, right: Parser<V>): Parser<T>;
1
+ import { Parser } from '../types';
2
+ /** Parses a sequence of three parsers.
3
+ * @returns A parser returning only the middle parser's result.
4
+ */
5
+ export declare function between<T, U, V>(left: Parser<U>, parser: Parser<T>, right: Parser<V>): Parser<T>;
@@ -1,21 +1,20 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.between = void 0;
4
- const types_1 = require("../types");
5
- const seq_1 = require("./seq");
6
- /** Parses a sequence of three parsers.
7
- * @returns A parser returning only the middle parser's result.
8
- */
9
- function between(left, parser, right) {
10
- const sequence = (0, seq_1.seq)(left, parser, right);
11
- return (ctx) => {
12
- const res = sequence(ctx);
13
- if ((0, types_1.isFailure)(res)) {
14
- const newHistory = [...res.history];
15
- newHistory.splice(0, 1);
16
- return (0, types_1.failure)(res.ctx, res.expected, ['between', ...newHistory]);
17
- }
18
- return { ...res, value: res.value[1] };
19
- };
20
- }
21
- exports.between = between;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.between = between;
4
+ const types_1 = require("../types");
5
+ const seq_1 = require("./seq");
6
+ /** Parses a sequence of three parsers.
7
+ * @returns A parser returning only the middle parser's result.
8
+ */
9
+ function between(left, parser, right) {
10
+ const sequence = (0, seq_1.seq)(left, parser, right);
11
+ return (ctx) => {
12
+ const res = sequence(ctx);
13
+ if ((0, types_1.isFailure)(res)) {
14
+ const newHistory = [...res.history];
15
+ newHistory.splice(0, 1);
16
+ return (0, types_1.failure)(res.ctx, res.expected, ['between', ...newHistory]);
17
+ }
18
+ return { ...res, value: res.value[1] };
19
+ };
20
+ }
@@ -1,5 +1,5 @@
1
- import { Parser } from '../types';
2
- /** Parses using the passed in parser, until the input is exhausted or until the `until` condition is satisfied.
3
- * @returns A parser returning an array of parsed results.
4
- */
5
- export declare function exhaust<T, V>(parser: Parser<T>, until?: Parser<V> | null): Parser<T[]>;
1
+ import { Parser } from '../types';
2
+ /** Parses using the passed in parser, until the input is exhausted or until the `until` condition is satisfied.
3
+ * @returns A parser returning an array of parsed results.
4
+ */
5
+ export declare function exhaust<T, V>(parser: Parser<T>, until?: Parser<V> | null): Parser<T[]>;
@@ -1,27 +1,25 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.exhaust = void 0;
4
- const types_1 = require("../types");
5
- /** Parses using the passed in parser, until the input is exhausted or until the `until` condition is satisfied.
6
- * @returns A parser returning an array of parsed results.
7
- */
8
- function exhaust(parser, until = null) {
9
- return (ctx) => {
10
- const results = [];
11
- // eslint-disable-next-line no-constant-condition
12
- while (true) {
13
- const res = parser(ctx);
14
- if ((0, types_1.isFailure)(res)) {
15
- if (until === null || (0, types_1.isFailure)(until(ctx))) {
16
- return (0, types_1.failure)(res.ctx, res.expected, ['exhaust', ...res.history]);
17
- }
18
- return (0, types_1.success)(ctx, results);
19
- }
20
- ctx = res.ctx;
21
- results.push(res.value);
22
- if (res.ctx.index === res.ctx.text.length)
23
- return (0, types_1.success)(res.ctx, results);
24
- }
25
- };
26
- }
27
- exports.exhaust = exhaust;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exhaust = exhaust;
4
+ const types_1 = require("../types");
5
+ /** Parses using the passed in parser, until the input is exhausted or until the `until` condition is satisfied.
6
+ * @returns A parser returning an array of parsed results.
7
+ */
8
+ function exhaust(parser, until = null) {
9
+ return (ctx) => {
10
+ const results = [];
11
+ while (true) {
12
+ const res = parser(ctx);
13
+ if ((0, types_1.isFailure)(res)) {
14
+ if (until === null || (0, types_1.isFailure)(until(ctx))) {
15
+ return (0, types_1.failure)(res.ctx, res.expected, ['exhaust', ...res.history]);
16
+ }
17
+ return (0, types_1.success)(ctx, results);
18
+ }
19
+ ctx = res.ctx;
20
+ results.push(res.value);
21
+ if (res.ctx.index === res.ctx.text.length)
22
+ return (0, types_1.success)(res.ctx, results);
23
+ }
24
+ };
25
+ }
@@ -1,11 +1,12 @@
1
- export * from './any';
2
- export * from './between';
3
- export * from './exhaust';
4
- export * from './many';
5
- export * from './map';
6
- export * from './opt';
7
- export * from './regex';
8
- export * from './seq';
9
- export * from './str';
10
- export * from './utilities';
11
- export * from './values';
1
+ export * from './any';
2
+ export * from './between';
3
+ export * from './exhaust';
4
+ export * from './many';
5
+ export * from './map';
6
+ export * from './opt';
7
+ export * from './regex';
8
+ export * from './seq';
9
+ export { str, stri } from './str';
10
+ export * from './recovery';
11
+ export * from './utilities';
12
+ export * from './values';