@minelang-ts/parser 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Maysara Elshewehy (https://github.com/maysara-elshewehy)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ <!-- ╔═══════════════════════════ BEG ════════════════════════════╗ -->
2
+
3
+ <br>
4
+ <div align="center">
5
+ <p>
6
+ <img src="./assets/img/logo.png" alt="logo" style="" height="60" />
7
+ </p>
8
+ </div>
9
+
10
+ <div align="center">
11
+ <img data="version" src="https://img.shields.io/badge/v-0.0.1-black"/>
12
+ <a href="https://github.com/minelang-ts"><img src="https://img.shields.io/badge/@-minelang--ts-black"/></a>
13
+ <img src="https://img.shields.io/badge/coverage-99.91%25-brightgreen" alt="Test Coverage" />
14
+ </div>
15
+ <br>
16
+
17
+ <!-- ╚════════════════════════════════════════════════════════════╝ -->
18
+
19
+
20
+
21
+ <!-- ╔═══════════════════════════ DOC ════════════════════════════╗ -->
22
+
23
+ - ## Note 📝
24
+
25
+ > All repositories related to `minelang-ts`, **like this repository**, are temporary repositories created for the purpose of simulating the final form of the Mine language.
26
+ >
27
+ > This means that they will later be ignored or deleted entirely after the real version of Mine is created using Mine itself rather than TypeScript. Until that happens, I will not provide any guarantees for the use of these repositories, since I will not spend much time on them because, as I said, they are temporary.
28
+
29
+ <!-- ╚════════════════════════════════════════════════════════════╝ -->
30
+
31
+
32
+
33
+ <!-- ╔═══════════════════════════ END ════════════════════════════╗ -->
34
+
35
+ <br>
36
+
37
+ <div align="center"><img src="./assets/img/line.png" alt="logo" style="" width="50%" /></div>
38
+
39
+ <br>
40
+
41
+ <div align="center">
42
+ <a href="https://github.com/maysara-elshewehy"><img src="https://img.shields.io/badge/by-Maysara-black"/></a>
43
+ </div>
44
+
45
+ <!-- ╚════════════════════════════════════════════════════════════╝ -->
package/dist/index.cjs ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';var h=class s{constructor(e,t,r,n){this.span={start:-99,end:-99};this.status="unset";this.source=null;this.mode="unset";this.errors=[];this.status=e,this.source=t,this.mode=r,this.span=n;}static create(e,t,r,n){return new s(e,t,r,n)}static createAsToken(e,t,r){return s.create(e,{source_kind:"token-source",type:t?.type??"unset",text:t?.text??void 0,span:r},"token",r)}static createAsOptional(e,t,r){return s.create(e,{source_kind:"optional-source",result:t},"optional",r)}static createAsChoice(e,t,r,n){return s.create(e,{source_kind:"choice-source",atIndex:r,result:t},"choice",n)}static createAsRepeat(e,t,r,n=false){return s.create(e,{source_kind:"repeat-source",endsWithSep:n,result:t??[]},"repeat",r)}static createAsSequence(e,t,r){return s.create(e,{source_kind:"sequence-source",result:t??[]},"seq",r)}static createAsPratt(e,t,r){return s.create(e,{source_kind:"pratt-source",result:t},"pratt",r)}static createAsCustom(e,t,r,n){return s.create(e,{source_kind:"custom-source",name:t,data:r},"custom",n)}isPassed(){return this.status==="passed"}isFailed(){return this.status==="failed"}isUnset(){return this.status==="unset"}isToken(){return this.mode==="token"}isOptional(){return this.mode==="optional"}isChoice(){return this.mode==="choice"}isRepeat(){return this.mode==="repeat"}isSequence(){return this.mode==="seq"}isPratt(){return this.mode==="pratt"}isFullyPassed(){return !(!this.isPassed()||this.isOptional()&&!this.isOptionalPassed())}isOptionalPassed(){return this.isOptional()&&this.source.result!==null}isCustom(e){return this.mode!=="custom"?false:e?this.source.name===e:true}getTokenType(){return this.isToken()?this.source.type:void 0}getTokenSpan(){return this.isToken()?this.source.span:void 0}getOptionalResult(){return this.isOptionalPassed()?this.source.result:void 0}getChoiceIndex(){return this.isChoice()?this.source.atIndex:void 0}getChoiceResult(){return this.isChoice()?this.source.result:void 0}getRepeatCount(){return this.isRepeat()?this.source.result.length:void 0}getRepeatResult(){return this.isRepeat()?this.source.result:void 0}isRepeatEndsWithSep(){return this.isRepeat()?this.source.endsWithSep:void 0}getSequenceCount(){return this.isSequence()?this.source.result.length:void 0}getSequenceResult(){return this.isSequence()?this.source.result:void 0}getPrattResult(){return this.isPratt()?this.source.result:void 0}getCustomData(){return this.isCustom()?this.source.data:void 0}getCustomName(){return this.isCustom()?this.source.name:void 0}getTokenValue(){if(!this.isToken())return;let e=this.source.text;return e===void 0?null:e}getTokenData(){if(!this.isToken())return;let e=this.source;return {type:e.type,text:e.text,span:e.span}}clone(){let e=new s(this.status,this.source,this.mode,this.span);return e.errors=[...this.errors],e}hasErrors(){return this.errors.length>0}withError(e){return this.errors.push(e),this}};var p={LEXICAL_ERROR:"LEXICAL_ERROR",TOKEN_EXPECTED_EOF:"TOKEN_EXPECTED_EOF",TOKEN_MISMATCH:"TOKEN_MISMATCH",RULE_FAILED:"RULE_FAILED",BUILD_FUNCTION_FAILED:"BUILD_FUNCTION_FAILED",REPEAT_MIN_NOT_MET:"REPEAT_MIN_NOT_MET",SEQUENCE_FAILED:"SEQUENCE_FAILED",CUSTOM_ERROR:"CUSTOM_ERROR",CHOICE_ALL_FAILED:"CHOICE_ALL_FAILED",PRATT_NO_PREFIX:"PRATT_NO_PREFIX",FATAL_ERROR:"FATAL_ERROR",UNKNOWN_ERROR:"UNKNOWN_ERROR",RECOVERY_CUSTOM:"RECOVERY_CUSTOM"},E={};var d=h.create("failed",null,"unset",{start:-1,end:-1}),g=class{constructor(e,t){this.tokens=[];this.index=0;this.errors=[];this.ast=[];this.stats={tokensProcessed:0,rulesApplied:0,errorsRecovered:0,parseTimeMs:0};this._compiled=new Map;this._ruleIndex=new Map;this._laTable=new Map;this._memo=new Map;this._depth=0;this._silentDepth=0;this._rootStart=0;this._startTime=0;this._debugLevel="off";this._ignoredSet=new Set;this.lastHandledRule="unknown";this.lastVisitedIndex=0;this.ruleStack=[];this.rules=new Map(e.map(i=>[i.name,i])),this.settings=this._normalizeSettings(t),this._debugLevel=this.settings.debug,this._ignoredSet=new Set(this.settings.ignored);let r=0;for(let i of this.rules.keys())this._ruleIndex.set(i,r++);let n=this._validateGrammar();if(n.length)throw new Error(`Grammar validation failed:
2
+ ${n.join(`
3
+ `)}`);this._buildLookaheadSets();for(let[i,o]of this.rules)this._compiled.set(i,this._compilePattern(o.pattern,o));}parse(e){if(this._reset(e),this._startTime=Date.now(),!e.length)return {ast:[],errors:[]};let t=e.find(a=>a.type==="error");if(t)return {ast:[],errors:[this._mkError(p.LEXICAL_ERROR,`Unexpected token '${t.text}'`,t.span,0,0,"lexer")]};let r=this.rules.get(this.settings.startRule);if(!r)throw new Error(`Start rule '${this.settings.startRule}' not found`);let n=this._compiled.get(this.settings.startRule),i=this.settings.errorRecovery.maxErrors;this.settings.errorRecovery.mode==="resilient";try{for(this._skipIgnored();this.index<this.tokens.length&&!(i>0&&this.errors.length>=i);){let a=this.index;this._rootStart=a;let u=n(!1);if(u.isPassed()){let l=r.options?.build?this._safeBuild(r.options.build,u):u;l&&this.ast.push(l);}if(this.index===a)break;this._skipIgnored();}}catch(a){this._handleFatal(a);}return this.stats.parseTimeMs=Date.now()-this._startTime,{ast:this.ast,errors:this.errors,statistics:this.stats}}dispose(){this._memo.clear(),this._compiled.clear(),this.tokens=[],this.ast=[],this.errors=[];}isNextToken(e,t){let r=new Set([...this._ignoredSet,...t??[]]);for(let n=this.index;n<this.tokens.length;n++){let i=this.tokens[n];if(i.type===e)return true;if(!r.has(i.type))break}return false}isPrevToken(e,t=-1,r){let n=new Set([...this._ignoredSet,...r??[]]),i=t<0?this.index:t;for(let o=i-1;o>=0;o--){let a=this.tokens[o];if(a.type===e)return true;if(!n.has(a.type))break}return false}isPrevRule(e){return this.lastHandledRule===e}_buildLookaheadSets(){for(let t of this.rules.keys())this._laTable.set(t,new Set);let e=true;for(;e;){e=false;for(let[t,r]of this.rules){let n=this._laTable.get(t),i=this._firstOfPattern(r.pattern);for(let o of i)n.has(o)||(n.add(o),e=true);}}}_firstOfPattern(e){let t=new Set;switch(e.type){case "token":t.add(e.name);break;case "rule":{let r=this._laTable.get(e.name);if(r)for(let n of r)t.add(n);break}case "seq":for(let r of e.patterns??[]){for(let n of this._firstOfPattern(r))t.add(n);if(r.type!=="optional")break}break;case "choice":for(let r of e.patterns??[])for(let n of this._firstOfPattern(r))t.add(n);break;case "optional":case "repeat":case "conditional":case "not":case "lookahead":if(e.pattern)for(let r of this._firstOfPattern(e.pattern))t.add(r);break;case "action":break;case "pratt":if(e.table)for(let r of e.table.prefix.keys())t.add(r);break}return t}_compilePattern(e,t){switch(e.type){case "token":return this._compileToken(e,t);case "rule":return this._compileRule(e,t);case "seq":return this._compileSeq(e,t);case "choice":return this._compileChoice(e,t);case "repeat":return this._compileRepeat(e,t);case "optional":return this._compileOptional(e,t);case "pratt":return this._compilePratt(e,t);case "conditional":return this._compileConditional(e,t);case "action":return this._compileAction(e,t);case "not":return this._compileNot(e,t);case "lookahead":return this._compileLookahead(e,t);default:throw new Error(`Unknown pattern type: ${e.type}`)}}_compileToken(e,t){let r=e.name,n=e.value;return i=>{if(this.lastHandledRule=t?.name??r,this.lastVisitedIndex=this.index,this.index>=this.tokens.length){if(i)return d;throw this._mkError(p.TOKEN_EXPECTED_EOF,`Expected '${r}', got EOF`,this._span(),0,this.index,this.lastHandledRule)}let o=this.tokens[this.index];if(o.type===r){if(n!==void 0&&o.text!==n){if(i)return d;throw this._mkError(p.TOKEN_MISMATCH,`Expected '${r}' with value '${n}', got '${o.text}'`,o.span,0,this.index,this.lastHandledRule)}return this.index++,this.stats.tokensProcessed++,h.createAsToken("passed",o,o.span)}if(i)return d;let a=this._mkError(p.TOKEN_MISMATCH,`Expected '${r}', got '${o.type}'`,o.span,0,this.index,this.lastHandledRule);throw this._customErrorOr(t,a)}}_compileRule(e,t){let r=e.name;return n=>{let i=this.rules.get(r);if(!i)throw new Error(`Rule '${r}' not found`);let o=this._compiled.get(r);if(!o)throw new Error(`Rule '${r}' not compiled`);this.ruleStack.push(r),this.stats.rulesApplied++;let u=(this._ruleIndex.get(r)??0)<<16|this.index,l=this._getMemo(u);if(l)return this.ruleStack.pop(),this.index=l.endIndex,l.result??d;let c=this.index,f=this.errors.length,m=o(n);if(!m.isFullyPassed()){if(this.index=c,this.ruleStack.pop(),n)return d;let _=this._mkError(p.RULE_FAILED,`Rule '${r}' failed`,this._span(),0,this.lastVisitedIndex,r);throw this._customErrorOr(t,_)}let R=m;if(i.options?.build){let _=this._safeBuild(i.options.build,m);_&&(R=_);}return this._setMemo(u,R,this.index,f),this.ruleStack.pop(),R}}_compileSeq(e,t){let r=(e.patterns??[]).map(n=>this._compilePattern(n,t));return n=>{let i=this.index,o=[];for(let a=0;a<r.length;a++){this._skipIgnored(t?.options?.ignored);let u=r[a](n);if(!u.isPassed()){if(this.index=i,n)return d;let l=this._mkError(p.SEQUENCE_FAILED,`Sequence failed at element ${a+1}/${r.length}`,this._span(),a,this.lastVisitedIndex,this.lastHandledRule);throw this._customErrorOr(t,l)}o.push(u);}return h.createAsSequence("passed",o,this._spanOf(o))}}_compileChoice(e,t){let r=e.patterns??[],n=r.map(o=>this._firstOfPattern(o)),i=r.map(o=>this._compilePattern(o,t));return o=>{let a=this.index;if(this._silentDepth++,this.index<this.tokens.length){let c=this.tokens[this.index].type,f=-1,m=false;for(let R=0;R<n.length;R++)if(n[R].has(c)){if(f>=0){m=true;break}f=R;}if(!m&&f>=0){this._silentDepth--;let R=i[f](o);if(R.isFullyPassed())return h.createAsChoice("passed",R,f,R.span);this.index=a,this._silentDepth++;}}let u=null;for(let c=0;c<i.length;c++){this.index=a;let f=i[c](true);if(f.isFullyPassed())return this._silentDepth--,h.createAsChoice("passed",f,c,f.span);let m=this.lastVisitedIndex-a;(!u||m>u.index-a)&&(u={index:this.lastVisitedIndex,err:null,altIdx:c});}if(this._silentDepth--,this.index=a,o)return d;let l=this._mkError(p.CHOICE_ALL_FAILED,`Expected one of: ${r.map(c=>this._patStr(c)).join(" | ")}`,this._span(),u?.altIdx??0,this.lastVisitedIndex,this.lastHandledRule);throw this._customErrorOr(t,l)}}_compileOptional(e,t){let r=this._compilePattern(e.pattern,t);return n=>{let i=this.index;this._silentDepth++;let o=r(true);return this._silentDepth--,o.isFullyPassed()?h.createAsOptional("passed",o,o.span):(this.index=i,h.createAsOptional("passed",null,this._span()))}}_compileRepeat(e,t){let r=e.min??0,n=e.max??1/0,i=this._compilePattern(e.pattern,t),o=e.separator?this._compilePattern(e.separator,t):null;return a=>{let u=[],l=false,c=this.index;for(;u.length<n&&this.index<this.tokens.length;){let f=this.index;this._silentDepth++;let m=i(true);if(this._silentDepth--,!m.isFullyPassed()){this.index=f,l=false;break}if(u.push(m),l=false,this.index===f)break;if(o&&u.length<n&&this.index<this.tokens.length){let R=this.index;this._silentDepth++;let _=o(true);if(this._silentDepth--,!_.isFullyPassed()){this.index=R;break}l=true;}}if(u.length<r){if(this.index=c,a)return d;throw this._mkError(p.REPEAT_MIN_NOT_MET,`Expected at least ${r} occurrences, got ${u.length}`,this._span(),0,this.index,this.lastHandledRule)}return h.createAsRepeat("passed",u,this._spanOf(u),l)}}_compilePratt(e,t){let r=e.table;return n=>{if(this.index>=this.tokens.length){if(n)return d;throw this._mkError(p.PRATT_NO_PREFIX,"Expected an expression",this._span(),0,this.index,"pratt")}let i=this.tokens[this.index],o=r.prefix.get(i.type);if(!o){if(n)return d;throw this._mkError(p.PRATT_NO_PREFIX,`Unexpected token '${i.type}' in expression`,i.span,0,this.index,"pratt")}this.index++;let a=o.parse(this,i);if(!a.isPassed())return n?d:a;for(;this.index<this.tokens.length&&(this._skipIgnored(),!(this.index>=this.tokens.length));){let u=this.tokens[this.index],l=r.infix.get(u.type);if(!l||l.lbp<=0||(this.index++,a=l.parse(this,a,u),!a.isPassed()))break}return a}}_compileConditional(e,t){let r=this._compilePattern(e.pattern,t),n=e.predicate;return i=>{let o=this.index,a;if(i?(this._silentDepth++,a=r(true),this._silentDepth--):a=r(false),!a.isFullyPassed())return this.index=o,i?d:a;try{let u={parser:this,result:a,index:this.index,depth:this._depth,ruleStack:[...this.ruleStack]};if(n(u))return h.createAsCustom("passed","conditional",a,a.span);{if(this.index=o,i)return d;let c=this._mkError(p.RULE_FAILED,"Conditional predicate returned false",this._span(),0,this.lastVisitedIndex,this.lastHandledRule);throw this._customErrorOr(t,c)}}catch(u){if(this.index=o,i)return d;let l=u instanceof Error?u.message:String(u),c=this._mkError(p.RULE_FAILED,`Conditional predicate threw: ${l}`,this._span(),0,this.lastVisitedIndex,this.lastHandledRule);throw this._customErrorOr(t,c)}}}_compileAction(e,t){let r=e.fn;return n=>{try{r(this);}catch(i){let o=i instanceof Error?i.message:String(i);throw this._mkError(p.RULE_FAILED,`Action function threw: ${o}`,this._span(),0,this.index,"action")}return h.createAsCustom("passed","action",null,this._span())}}_compileNot(e,t){let r=this._compilePattern(e.pattern,t);return n=>{let i=this.index;this._silentDepth++;let o=r(true);if(this._silentDepth--,o.isFullyPassed()){if(this.index=i,n)return d;let a=this._mkError(p.RULE_FAILED,"NOT pattern failed - inner pattern matched",this._span(),0,i,this.lastHandledRule);throw this._customErrorOr(t,a)}else return this.index=i,h.createAsCustom("passed","not",null,this._span())}}_compileLookahead(e,t){let r=this._compilePattern(e.pattern,t);return n=>{let i=this.index;this._silentDepth++;let o=r(true);if(this._silentDepth--,this.index=i,o.isFullyPassed())return h.createAsCustom("passed","lookahead",null,this._span());{if(n)return d;let a=this._mkError(p.RULE_FAILED,"Lookahead pattern failed",this._span(),0,i,this.lastHandledRule);throw this._customErrorOr(t,a)}}}_getMemo(e){let t=this._memo.get(e);return t?t.errorCount!==this.errors.length?(this._memo.delete(e),null):t:null}_setMemo(e,t,r,n){this._memo.set(e,{result:t,endIndex:r,errorCount:this.errors.length});}_mkError(e,t,r,n,i,o,a){return {code:e,msg:t,span:r,failedAt:n,tokenIndex:i,startIndex:this._rootStart,prevRule:o,prevInnerRule:a??this.ruleStack.at(-1)??"unknown"}}_customErrorOr(e,t){if(!e?.options?.errors)return t;for(let r of e.options.errors){let n=false;if(typeof r.cond=="number")n=t.failedAt===r.cond;else if(typeof r.cond=="function")try{n=r.cond(this,{failedAt:t.failedAt,tokenIndex:t.tokenIndex});}catch{}if(n)return this._mkError(r.code??p.CUSTOM_ERROR,r.msg,t.span,t.failedAt,t.tokenIndex,t.prevRule,t.prevInnerRule)}return t}_addError(e){if(this._silentDepth>0)return;let t=this.settings.errorRecovery.maxErrors;t>0&&this.errors.length>=t||this.settings.errorRecovery.mode==="strict"&&this.errors.length>0||this.errors.some(r=>r.span?.start===e.span?.start)||this.errors.push(e);}_handleFatal(e){e&&typeof e=="object"&&"msg"in e&&"code"in e?this._addError(e):e instanceof Error&&this._addError(this._mkError(p.FATAL_ERROR,e.message,this._span(),0,this.index,this.lastHandledRule));}_safeBuild(e,t){try{return e(t,this)}catch(r){let n=this._mkError(p.BUILD_FUNCTION_FAILED,r instanceof Error?r.message:String(r),this._span(),0,this.index,this.lastHandledRule);return this._addError(n),t}}_span(){if(!this.tokens.length)return {start:0,end:0};if(this.index>=this.tokens.length){let e=this.tokens[this.tokens.length-1];return {start:e.span.end,end:e.span.end}}return this.tokens[this.index].span}_spanOf(e){return e.length?{start:e[0].span.start,end:e[e.length-1].span.end}:this._span()}_skipIgnored(e){let t=e?new Set([...this._ignoredSet,...e]):this._ignoredSet;for(;this.index<this.tokens.length&&t.has(this.tokens[this.index].type);)this.index++,this.stats.tokensProcessed++;}_patStr(e){switch(e.type){case "token":return e.name;case "rule":return e.name;case "seq":return `(${(e.patterns??[]).map(t=>this._patStr(t)).join(" ")})`;case "choice":return (e.patterns??[]).map(t=>this._patStr(t)).join(" | ");case "optional":return `${this._patStr(e.pattern)}?`;case "repeat":return `${this._patStr(e.pattern)}*`;case "conditional":return `${this._patStr(e.pattern)}.if(...)`;case "action":return "action(...)";case "not":return `!${this._patStr(e.pattern)}`;case "lookahead":return `lookahead(${this._patStr(e.pattern)})`;case "pratt":return "expr";default:return e.type}}_validateGrammar(){let e=[],t=new Set(this.rules.keys()),r=(n,i)=>{n.type==="rule"&&!t.has(n.name)&&e.push(`Rule '${i}' references undefined rule '${n.name}'`);for(let o of [n.pattern,...n.patterns??[]])o&&r(o,i);n.separator&&r(n.separator,i);};for(let[n,i]of this.rules)r(i.pattern,n);return this.rules.has(this.settings.startRule)||e.push(`Start rule '${this.settings.startRule}' is not defined`),e}_normalizeSettings(e){return {startRule:e?.startRule??"root",errorRecovery:{mode:e?.errorRecovery?.mode??"strict",maxErrors:e?.errorRecovery?.maxErrors??1},ignored:e?.ignored??["ws"],debug:e?.debug??"off",maxDepth:e?.maxDepth??1e3}}_reset(e){this.tokens=e,this.index=0,this.errors=[],this.ast=[],this._depth=0,this._silentDepth=0,this._rootStart=0,this.ruleStack=[],this._memo.clear(),this.stats={tokensProcessed:0,rulesApplied:0,errorsRecovered:0,parseTimeMs:0};}};function w(s){Object.assign(E,s);}function F(s,e,t){let r=new g(e,t);try{return r.parse(s)}finally{r.dispose();}}function L(s,e,t={}){return {name:s,pattern:e,options:{name:false,...t}}}function M(s,e){if(!s)throw new Error("token(): name must be a non-empty string");return {type:"token",name:s,value:e,silent:false}}function k(s){return {type:"optional",pattern:s,silent:false}}function D(...s){if(!s.length)throw new Error("choice(): at least one pattern required");return {type:"choice",patterns:s,silent:false}}function T(s,e=0,t=1/0,r){if(e<0)throw new Error("repeat(): min cannot be negative");if(t<e)throw new Error("repeat(): max cannot be less than min");return {type:"repeat",pattern:s,min:e,max:t,separator:r,silent:false}}function H(s,e){return T(s,1,1/0,e)}function x(s,e){return T(s,0,1/0,e)}function N(s,e){return O(T(s,0,1,e))}function y(...s){if(!s.length)throw new Error("seq(): at least one pattern required");return {type:"seq",patterns:s,silent:false}}function U(s,e){if(!s)throw new Error("rule(): name must be a non-empty string");return {type:"rule",name:s,params:e,silent:false}}function O(s){return {...s,silent:true}}function $(s){return {...s,silent:false}}function q(s){return {type:"pratt",table:s,silent:false}}function S(s,e){return {type:"conditional",pattern:s,predicate:e,silent:false}}function V(s,e){return S(s,e)}function B(s,e){return S(s,e)}function K(s){return {type:"action",fn:s,silent:false}}function X(s){return {type:"not",pattern:s,silent:false}}function I(s){return {type:"lookahead",pattern:s,silent:false}}function j(s){return I(s)}function W(s){return {prefix:new Map(Object.entries(s.prefix??{})),infix:new Map(Object.entries(s.infix??{}))}}function z(s,e,t){let{min:r=0,trailingOk:n=false}=t??{},i;return r===0?n?i=k(y(T(s,1,1/0),x(y(e,s)),k(e))):i=k(y(T(s,1,1/0),x(y(e,s)))):r===1?n?i=y(T(s,1,1/0),x(y(e,s)),k(e)):i=y(T(s,1,1/0),x(y(e,s))):n?i=y(T(s,r,1/0),x(y(e,s)),k(e)):i=y(T(s,r,1/0),x(y(e,s))),i}function G(s,e,t){return y(e,s,t)}function Q(s,e,t){return y(s,e,t)}function Y(s,e,t){return {cond:s,msg:e,code:t??p.RECOVERY_CUSTOM}}var J={skipUntil(s){return {type:"skipUntil",tokens:Array.isArray(s)?s:[s]}}};exports.ERRORS=p;exports.Parser=g;exports.Result=h;exports.action=K;exports.between=Q;exports.buildPrattTable=W;exports.choice=D;exports.conditional=S;exports.createRule=L;exports.delimited=z;exports.error=Y;exports.errorRecoveryStrategies=J;exports.globalTokenMap=E;exports.ifCondition=B;exports.lookahead=I;exports.loud=$;exports.not=X;exports.oneOrMore=H;exports.optional=k;exports.parse=F;exports.peek=j;exports.pratt=q;exports.registerTokenMap=w;exports.repeat=T;exports.rule=U;exports.seq=y;exports.silent=O;exports.surrounded=G;exports.token=M;exports.when=V;exports.zeroOrMore=x;exports.zeroOrOne=N;
@@ -0,0 +1,500 @@
1
+ import { Span, Token } from '@minelang-ts/lexer';
2
+ export { Span, Token } from '@minelang-ts/lexer';
3
+
4
+ type ResultStatus = 'unset' | 'failed' | 'passed';
5
+ type ResultMode = 'unset' | 'token' | 'optional' | 'choice' | 'repeat' | 'seq' | 'pratt' | 'custom';
6
+ interface TokenSource {
7
+ source_kind: 'token-source';
8
+ type: string;
9
+ text?: string;
10
+ span?: Span;
11
+ }
12
+ interface OptionalSource {
13
+ source_kind: 'optional-source';
14
+ result: Result | null;
15
+ }
16
+ interface ChoiceSource {
17
+ source_kind: 'choice-source';
18
+ atIndex: number;
19
+ result: Result | null;
20
+ }
21
+ interface RepeatSource {
22
+ source_kind: 'repeat-source';
23
+ endsWithSep: boolean;
24
+ result: Result[];
25
+ }
26
+ interface SequenceSource {
27
+ source_kind: 'sequence-source';
28
+ result: Result[];
29
+ }
30
+ interface PrattSource {
31
+ source_kind: 'pratt-source';
32
+ result: Result[];
33
+ }
34
+ interface CustomSource {
35
+ source_kind: 'custom-source';
36
+ name: string;
37
+ data: unknown;
38
+ }
39
+ type ResultSource = TokenSource | OptionalSource | ChoiceSource | RepeatSource | SequenceSource | PrattSource | CustomSource | null;
40
+ declare class Result {
41
+ span: Span;
42
+ status: ResultStatus;
43
+ source: ResultSource;
44
+ mode: ResultMode;
45
+ errors: ParseError[];
46
+ constructor(status: ResultStatus, source: ResultSource | null, mode: ResultMode, span: Span);
47
+ static create(status: ResultStatus, source: ResultSource | null, mode: ResultMode, span: Span): Result;
48
+ static createAsToken(status: ResultStatus, source: Token | null, span: Span): Result;
49
+ static createAsOptional(status: ResultStatus, source: Result | null, span: Span): Result;
50
+ static createAsChoice(status: ResultStatus, source: Result | null, index: number, span: Span): Result;
51
+ static createAsRepeat(status: ResultStatus, source: Result[] | null, span: Span, endsWithSep?: boolean): Result;
52
+ static createAsSequence(status: ResultStatus, source: Result[] | null, span: Span): Result;
53
+ static createAsPratt(status: ResultStatus, source: Result[], span: Span): Result;
54
+ static createAsCustom(status: ResultStatus, name: string, data: unknown, span: Span): Result;
55
+ isPassed(): boolean;
56
+ isFailed(): boolean;
57
+ isUnset(): boolean;
58
+ isToken(): boolean;
59
+ isOptional(): boolean;
60
+ isChoice(): boolean;
61
+ isRepeat(): boolean;
62
+ isSequence(): boolean;
63
+ isPratt(): boolean;
64
+ isFullyPassed(): boolean;
65
+ isOptionalPassed(): boolean;
66
+ isCustom(tag?: string): boolean;
67
+ getTokenType(): string | undefined;
68
+ getTokenSpan(): Span | undefined;
69
+ getOptionalResult(): Result | null | undefined;
70
+ getChoiceIndex(): number | undefined;
71
+ getChoiceResult(): Result | null | undefined;
72
+ getRepeatCount(): number | undefined;
73
+ getRepeatResult(): Result[] | undefined;
74
+ isRepeatEndsWithSep(): boolean | undefined;
75
+ getSequenceCount(): number | undefined;
76
+ getSequenceResult(): Result[] | undefined;
77
+ getPrattResult(): Result[] | undefined;
78
+ getCustomData(): unknown | undefined;
79
+ getCustomName(): string | undefined;
80
+ getTokenValue(): string | null | undefined;
81
+ getTokenData(): Token | undefined;
82
+ clone(): Result;
83
+ hasErrors(): boolean;
84
+ withError(e: ParseError): Result;
85
+ }
86
+
87
+ declare class Parser {
88
+ rules: Map<string, Rule>;
89
+ settings: ParserSettings;
90
+ tokens: Token[];
91
+ index: number;
92
+ errors: ParseError[];
93
+ ast: Result[];
94
+ stats: ParseStatistics;
95
+ private _compiled;
96
+ private _ruleIndex;
97
+ private _laTable;
98
+ private _memo;
99
+ private _depth;
100
+ private _silentDepth;
101
+ private _rootStart;
102
+ private _startTime;
103
+ private _debugLevel;
104
+ private _ignoredSet;
105
+ lastHandledRule: string;
106
+ lastVisitedIndex: number;
107
+ ruleStack: string[];
108
+ constructor(rules: Rule[], settings?: ParserSettings);
109
+ parse(tokens: Token[]): ParseResult;
110
+ dispose(): void;
111
+ isNextToken(kind: string, extra?: string[]): boolean;
112
+ isPrevToken(kind: string, from?: number, extra?: string[]): boolean;
113
+ isPrevRule(name: string): boolean;
114
+ private _buildLookaheadSets;
115
+ private _firstOfPattern;
116
+ private _compilePattern;
117
+ private _compileToken;
118
+ private _compileRule;
119
+ private _compileSeq;
120
+ private _compileChoice;
121
+ private _compileOptional;
122
+ private _compileRepeat;
123
+ private _compilePratt;
124
+ private _compileConditional;
125
+ private _compileAction;
126
+ private _compileNot;
127
+ private _compileLookahead;
128
+ private _getMemo;
129
+ private _setMemo;
130
+ private _mkError;
131
+ private _customErrorOr;
132
+ private _addError;
133
+ private _handleFatal;
134
+ private _safeBuild;
135
+ private _span;
136
+ private _spanOf;
137
+ private _skipIgnored;
138
+ private _patStr;
139
+ private _validateGrammar;
140
+ private _normalizeSettings;
141
+ private _reset;
142
+ }
143
+
144
+ interface MiniToken {
145
+ kind: string;
146
+ value: string | null;
147
+ }
148
+ /**
149
+ * Conditional context passed to predicate function.
150
+ * Provides access to parser state for conditional decision-making.
151
+ */
152
+ interface ConditionalContext {
153
+ parser: Parser;
154
+ result: Result | null;
155
+ index: number;
156
+ depth: number;
157
+ ruleStack: string[];
158
+ }
159
+ /**
160
+ * Predicate function for conditional pattern execution.
161
+ * Return true to continue with the pattern, false to fail.
162
+ */
163
+ type ConditionalPredicate = (context: ConditionalContext) => boolean;
164
+ /**
165
+ * Action function executed for side effects during parsing.
166
+ * Called during pattern execution, can access and modify parser state.
167
+ */
168
+ type ActionFunction = (parser: Parser) => void;
169
+ interface Pattern {
170
+ type: 'token' | 'rule' | 'repeat' | 'choice' | 'seq' | 'optional' | 'pratt' | 'conditional' | 'action' | 'not' | 'lookahead';
171
+ silent: boolean;
172
+ value?: string;
173
+ name?: string;
174
+ min?: number;
175
+ max?: number;
176
+ patterns?: Pattern[];
177
+ separator?: Pattern;
178
+ pattern?: Pattern;
179
+ table?: PrattTable;
180
+ predicate?: ConditionalPredicate;
181
+ fn?: ActionFunction;
182
+ params?: Record<string, any>;
183
+ }
184
+ interface PrefixHandler {
185
+ /** How tightly this prefix binds its right operand. */
186
+ bp: number;
187
+ parse: (parser: Parser, token: Token) => Result;
188
+ }
189
+ interface InfixHandler {
190
+ /** Precedence level - left binding power. */
191
+ lbp: number;
192
+ /** Right binding power (lbp - 1 for right-associative). Defaults to lbp. */
193
+ rbp?: number;
194
+ parse: (parser: Parser, left: Result, token: Token) => Result;
195
+ }
196
+ interface PrattTable {
197
+ prefix: Map<string, PrefixHandler>;
198
+ infix: Map<string, InfixHandler>;
199
+ }
200
+ interface ErrorHandler {
201
+ cond: number | ((parser: Parser, opt: {
202
+ failedAt: number;
203
+ tokenIndex: number;
204
+ force?: boolean;
205
+ prevRule?: string;
206
+ prevInnerRule?: string;
207
+ }) => boolean);
208
+ msg: string;
209
+ code?: string;
210
+ }
211
+ interface RecoveryStrategy {
212
+ type: 'skipUntil' | 'synchronize';
213
+ tokens?: string[];
214
+ token?: string;
215
+ }
216
+ type BuildFunction = (matches: Result, parser: Parser) => Result;
217
+ interface Rule {
218
+ name: string;
219
+ pattern: Pattern;
220
+ options?: {
221
+ build?: BuildFunction;
222
+ errors?: ErrorHandler[];
223
+ recovery?: RecoveryStrategy;
224
+ ignored?: string[];
225
+ silent?: boolean;
226
+ };
227
+ }
228
+ type Rules = Rule[];
229
+ interface ParseStatistics {
230
+ tokensProcessed: number;
231
+ rulesApplied: number;
232
+ errorsRecovered: number;
233
+ parseTimeMs: number;
234
+ }
235
+ interface ParseError {
236
+ msg: string;
237
+ code: string;
238
+ span: Span;
239
+ failedAt: number;
240
+ tokenIndex: number;
241
+ startIndex: number;
242
+ prevRule: string;
243
+ prevInnerRule?: string;
244
+ }
245
+ interface ParseResult {
246
+ ast: Result[];
247
+ errors: ParseError[];
248
+ statistics?: ParseStatistics;
249
+ }
250
+ type DebugLevel = 'off' | 'errors' | 'rules' | 'patterns' | 'tokens' | 'verbose';
251
+ interface ParserSettings {
252
+ startRule: string;
253
+ errorRecovery?: {
254
+ mode?: 'strict' | 'resilient';
255
+ maxErrors?: number;
256
+ };
257
+ ignored?: string[];
258
+ debug?: DebugLevel;
259
+ maxDepth?: number;
260
+ }
261
+ declare const ERRORS: {
262
+ readonly LEXICAL_ERROR: "LEXICAL_ERROR";
263
+ readonly TOKEN_EXPECTED_EOF: "TOKEN_EXPECTED_EOF";
264
+ readonly TOKEN_MISMATCH: "TOKEN_MISMATCH";
265
+ readonly RULE_FAILED: "RULE_FAILED";
266
+ readonly BUILD_FUNCTION_FAILED: "BUILD_FUNCTION_FAILED";
267
+ readonly REPEAT_MIN_NOT_MET: "REPEAT_MIN_NOT_MET";
268
+ readonly SEQUENCE_FAILED: "SEQUENCE_FAILED";
269
+ readonly CUSTOM_ERROR: "CUSTOM_ERROR";
270
+ readonly CHOICE_ALL_FAILED: "CHOICE_ALL_FAILED";
271
+ readonly PRATT_NO_PREFIX: "PRATT_NO_PREFIX";
272
+ readonly FATAL_ERROR: "FATAL_ERROR";
273
+ readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
274
+ readonly RECOVERY_CUSTOM: "RECOVERY_CUSTOM";
275
+ };
276
+ /**
277
+ * Global registry mapping string literals to token kinds.
278
+ * Example: {'let': 'LET', 'if': 'IF', '{': 'LBRACE'}
279
+ * When registered, string patterns like seq('let', 'IDENT') will work.
280
+ */
281
+ declare const globalTokenMap: Record<string, string>;
282
+
283
+ /**
284
+ * Register a global token map for string shorthand patterns.
285
+ * After registration, you can use 'let', 'if', etc. directly in patterns.
286
+ *
287
+ * @example
288
+ * registerTokenMap({
289
+ * 'let': 'LET',
290
+ * 'if': 'IF',
291
+ * '{': 'LBRACE',
292
+ * '}': 'RBRACE',
293
+ * '=': 'EQ',
294
+ * });
295
+ *
296
+ * // Now you can write:
297
+ * seq('let', 'IDENT', '=', rule('expr'))
298
+ */
299
+ declare function registerTokenMap(map: Record<string, string>): void;
300
+ declare function parse(tokens: Token[], rules: Rules, settings?: ParserSettings): ParseResult;
301
+ declare function createRule(name: string, pattern: Pattern, options?: Rule['options']): Rule;
302
+ declare function token(name: string, value?: string): Pattern;
303
+ declare function optional(pattern: Pattern): Pattern;
304
+ declare function choice(...patterns: Pattern[]): Pattern;
305
+ declare function repeat(pattern: Pattern, min?: number, max?: number, separator?: Pattern): Pattern;
306
+ declare function oneOrMore(pattern: Pattern, separator?: Pattern): Pattern;
307
+ declare function zeroOrMore(pattern: Pattern, separator?: Pattern): Pattern;
308
+ declare function zeroOrOne(pattern: Pattern, separator?: Pattern): Pattern;
309
+ declare function seq(...patterns: Pattern[]): Pattern;
310
+ declare function rule(name: string): Pattern;
311
+ declare function rule(name: string, params: Record<string, unknown>): Pattern;
312
+ declare function silent<T extends Pattern>(pattern: T): T;
313
+ declare function loud<T extends Pattern>(pattern: T): T;
314
+ /**
315
+ * Build a Pratt expression parser inline in a rule.
316
+ *
317
+ * @example
318
+ * const expr = pratt({
319
+ * prefix: new Map([
320
+ * ['NUM', { bp: 0, parse: (_, tok) => Result.createAsToken('passed', tok, tok.span) }],
321
+ * ['MINUS', { bp: 70, parse: (p, tok) => {
322
+ * const right = p.parse(...) // handled via sub-rule
323
+ * return Result.createAsPratt('passed', [right], right.span)
324
+ * }}],
325
+ * ]),
326
+ * infix: new Map([
327
+ * ['PLUS', { lbp: 50, parse: (_, left, tok) => ... }],
328
+ * ['STAR', { lbp: 60, parse: (_, left, tok) => ... }],
329
+ * ['STAR2', { lbp: 70, rbp: 69, parse: ... }], // right-associative
330
+ * ]),
331
+ * });
332
+ */
333
+ declare function pratt(table: PrattTable): Pattern;
334
+ /**
335
+ * Adds conditional execution to a pattern.
336
+ * The predicate receives parser context and decides whether to continue.
337
+ *
338
+ * @param pattern - The pattern to conditionally execute
339
+ * @param predicate - Function that receives parser context and returns true to continue
340
+ * @returns Conditional pattern that evaluates predicate after inner pattern matches
341
+ *
342
+ * @example
343
+ * // Only match if we're not too deep in the parse tree
344
+ * pattern.if(ctx => ctx.depth < 10)
345
+ *
346
+ * // Only match if next token after match is LBRACE
347
+ * token('IF').if(ctx => ctx.parser.isNextToken('LBRACE'))
348
+ *
349
+ * // Inspect full parser state
350
+ * rule('expr').if(ctx => {
351
+ * return ctx.parser.errors.length === 0 && ctx.ruleStack.length < 5
352
+ * })
353
+ */
354
+ declare function conditional(pattern: Pattern, predicate: ConditionalPredicate): Pattern;
355
+ /**
356
+ * Shorthand for conditional() - more natural syntax
357
+ * @see conditional
358
+ */
359
+ declare function when(pattern: Pattern, predicate: ConditionalPredicate): Pattern;
360
+ /**
361
+ * Method-chaining style: pattern.if(predicate)
362
+ * Extends Pattern type with .if() method for fluent API
363
+ *
364
+ * @note This is implemented as a utility function, not directly on Pattern
365
+ * Use: conditional(pattern, predicate) or when(pattern, predicate)
366
+ */
367
+ declare function ifCondition(pattern: Pattern, predicate: ConditionalPredicate): Pattern;
368
+ /**
369
+ * Action pattern - executes a side effect during parsing.
370
+ * Useful for scope management, state tracking, and stateful parsing.
371
+ *
372
+ * @param fn - Function called during execution with access to parser state
373
+ * @returns Action pattern that always succeeds
374
+ *
375
+ * @example
376
+ * // Track parse state
377
+ * seq(
378
+ * token('LBRACE'),
379
+ * action(p => p.symbolTable?.pushScope()),
380
+ * zeroOrMore(rule('stmt')),
381
+ * token('RBRACE'),
382
+ * action(p => p.symbolTable?.popScope())
383
+ * )
384
+ *
385
+ * // Count custom metric
386
+ * action(p => p.stats.customCounter = (p.stats.customCounter ?? 0) + 1)
387
+ */
388
+ declare function action(fn: ActionFunction): Pattern;
389
+ /**
390
+ * NOT pattern - succeeds if the inner pattern FAILS.
391
+ * Useful for negative lookahead and validation checks.
392
+ *
393
+ * @param pattern - The pattern to negate
394
+ * @returns NOT pattern
395
+ *
396
+ * @example
397
+ * // Match any character except EOF
398
+ * not(token('EOF'))
399
+ *
400
+ * // In a choice: match IDENT that is not a keyword
401
+ * choice(
402
+ * not(choice(token('IF'), token('WHILE'), token('FOR'))),
403
+ * token('IDENT')
404
+ * )
405
+ */
406
+ declare function not(pattern: Pattern): Pattern;
407
+ /**
408
+ * Lookahead pattern - checks if inner pattern would match WITHOUT consuming tokens.
409
+ * Common alias: peek()
410
+ *
411
+ * @param pattern - The pattern to lookahead check
412
+ * @returns Lookahead pattern
413
+ *
414
+ * @example
415
+ * // Only match expr if followed by RPAREN
416
+ * seq(
417
+ * lookahead(seq(rule('expr'), token('RPAREN'))),
418
+ * rule('expr')
419
+ * )
420
+ *
421
+ * // Safe token inspection
422
+ * seq(
423
+ * token('IDENT'),
424
+ * when(lookahead(token('LPAREN')), ctx => ctx.parser.isNextToken('LPAREN'))
425
+ * )
426
+ */
427
+ declare function lookahead(pattern: Pattern): Pattern;
428
+ /**
429
+ * Alias for lookahead() - more concise syntax.
430
+ * @see lookahead
431
+ */
432
+ declare function peek(pattern: Pattern): Pattern;
433
+ /** Convenience: build a PrattTable from plain objects. */
434
+ declare function buildPrattTable(spec: {
435
+ prefix?: Record<string, PrefixHandler>;
436
+ infix?: Record<string, InfixHandler>;
437
+ }): PrattTable;
438
+ /**
439
+ * Delimited list pattern - matches items separated by a delimiter.
440
+ * Commonly used for comma-separated values, arguments, etc.
441
+ *
442
+ * @param item - The pattern for each list item
443
+ * @param sep - The separator pattern (usually token(','))
444
+ * @param options - {min?: number, trailingOk?: boolean}
445
+ * @returns Composed pattern for delimited list
446
+ *
447
+ * @example
448
+ * // Comma-separated identifiers (0+)
449
+ * delimited(token('IDENT'), token('COMMA'))
450
+ *
451
+ * // Function arguments (1+ with optional trailing)
452
+ * delimited(rule('expr'), token('COMMA'), {min: 1, trailingOk: true})
453
+ *
454
+ * // Array elements
455
+ * between('[', delimited(rule('expr'), token('COMMA')), ']')
456
+ */
457
+ declare function delimited(item: Pattern, sep: Pattern, options?: {
458
+ min?: number;
459
+ trailingOk?: boolean;
460
+ }): Pattern;
461
+ /**
462
+ * Surrounded pattern - matches content between open and close delimiters.
463
+ * Alias for between(open, content, close).
464
+ *
465
+ * @param content - The pattern for interior content
466
+ * @param open - Opening delimiter
467
+ * @param close - Closing delimiter
468
+ * @returns Composed pattern: open, content, close
469
+ *
470
+ * @example
471
+ * // Parenthesized expression
472
+ * surrounded(rule('expr'), token('LPAREN'), token('RPAREN'))
473
+ *
474
+ * // Generic syntax with string shorthand
475
+ * surrounded(rule('typeList'), '(', ')')
476
+ */
477
+ declare function surrounded(content: Pattern, open: Pattern, close: Pattern): Pattern;
478
+ /**
479
+ * Between pattern - matches content between left and right patterns.
480
+ * Alias for surrounded but with more explicit name.
481
+ *
482
+ * @param left - Left sentinel pattern
483
+ * @param content - Interior content pattern
484
+ * @param right - Right sentinel pattern
485
+ * @returns Composed pattern: left, content, right
486
+ *
487
+ * @example
488
+ * // Array literal
489
+ * between(token('LBRACK'), delimited(rule('expr'), token('COMMA')), token('RBRACK'))
490
+ *
491
+ * // Function call
492
+ * between('(', delimited(rule('param'), ','), ')')
493
+ */
494
+ declare function between(left: Pattern, content: Pattern, right: Pattern): Pattern;
495
+ declare function error(cond: ErrorHandler['cond'], msg: string, code?: string): ErrorHandler;
496
+ declare const errorRecoveryStrategies: {
497
+ skipUntil(tokens: string | string[]): RecoveryStrategy;
498
+ };
499
+
500
+ export { type BuildFunction, type ConditionalContext, type ConditionalPredicate, type DebugLevel, ERRORS, type ErrorHandler, type InfixHandler, type MiniToken, type ParseError, type ParseResult, Parser, type ParserSettings, type Pattern, type PrattTable, type PrefixHandler, type RecoveryStrategy, Result, type Rule, type Rules, action, between, buildPrattTable, choice, conditional, createRule, delimited, error, errorRecoveryStrategies, globalTokenMap, ifCondition, lookahead, loud, not, oneOrMore, optional, parse, peek, pratt, registerTokenMap, repeat, rule, seq, silent, surrounded, token, when, zeroOrMore, zeroOrOne };
@@ -0,0 +1,500 @@
1
+ import { Span, Token } from '@minelang-ts/lexer';
2
+ export { Span, Token } from '@minelang-ts/lexer';
3
+
4
+ type ResultStatus = 'unset' | 'failed' | 'passed';
5
+ type ResultMode = 'unset' | 'token' | 'optional' | 'choice' | 'repeat' | 'seq' | 'pratt' | 'custom';
6
+ interface TokenSource {
7
+ source_kind: 'token-source';
8
+ type: string;
9
+ text?: string;
10
+ span?: Span;
11
+ }
12
+ interface OptionalSource {
13
+ source_kind: 'optional-source';
14
+ result: Result | null;
15
+ }
16
+ interface ChoiceSource {
17
+ source_kind: 'choice-source';
18
+ atIndex: number;
19
+ result: Result | null;
20
+ }
21
+ interface RepeatSource {
22
+ source_kind: 'repeat-source';
23
+ endsWithSep: boolean;
24
+ result: Result[];
25
+ }
26
+ interface SequenceSource {
27
+ source_kind: 'sequence-source';
28
+ result: Result[];
29
+ }
30
+ interface PrattSource {
31
+ source_kind: 'pratt-source';
32
+ result: Result[];
33
+ }
34
+ interface CustomSource {
35
+ source_kind: 'custom-source';
36
+ name: string;
37
+ data: unknown;
38
+ }
39
+ type ResultSource = TokenSource | OptionalSource | ChoiceSource | RepeatSource | SequenceSource | PrattSource | CustomSource | null;
40
+ declare class Result {
41
+ span: Span;
42
+ status: ResultStatus;
43
+ source: ResultSource;
44
+ mode: ResultMode;
45
+ errors: ParseError[];
46
+ constructor(status: ResultStatus, source: ResultSource | null, mode: ResultMode, span: Span);
47
+ static create(status: ResultStatus, source: ResultSource | null, mode: ResultMode, span: Span): Result;
48
+ static createAsToken(status: ResultStatus, source: Token | null, span: Span): Result;
49
+ static createAsOptional(status: ResultStatus, source: Result | null, span: Span): Result;
50
+ static createAsChoice(status: ResultStatus, source: Result | null, index: number, span: Span): Result;
51
+ static createAsRepeat(status: ResultStatus, source: Result[] | null, span: Span, endsWithSep?: boolean): Result;
52
+ static createAsSequence(status: ResultStatus, source: Result[] | null, span: Span): Result;
53
+ static createAsPratt(status: ResultStatus, source: Result[], span: Span): Result;
54
+ static createAsCustom(status: ResultStatus, name: string, data: unknown, span: Span): Result;
55
+ isPassed(): boolean;
56
+ isFailed(): boolean;
57
+ isUnset(): boolean;
58
+ isToken(): boolean;
59
+ isOptional(): boolean;
60
+ isChoice(): boolean;
61
+ isRepeat(): boolean;
62
+ isSequence(): boolean;
63
+ isPratt(): boolean;
64
+ isFullyPassed(): boolean;
65
+ isOptionalPassed(): boolean;
66
+ isCustom(tag?: string): boolean;
67
+ getTokenType(): string | undefined;
68
+ getTokenSpan(): Span | undefined;
69
+ getOptionalResult(): Result | null | undefined;
70
+ getChoiceIndex(): number | undefined;
71
+ getChoiceResult(): Result | null | undefined;
72
+ getRepeatCount(): number | undefined;
73
+ getRepeatResult(): Result[] | undefined;
74
+ isRepeatEndsWithSep(): boolean | undefined;
75
+ getSequenceCount(): number | undefined;
76
+ getSequenceResult(): Result[] | undefined;
77
+ getPrattResult(): Result[] | undefined;
78
+ getCustomData(): unknown | undefined;
79
+ getCustomName(): string | undefined;
80
+ getTokenValue(): string | null | undefined;
81
+ getTokenData(): Token | undefined;
82
+ clone(): Result;
83
+ hasErrors(): boolean;
84
+ withError(e: ParseError): Result;
85
+ }
86
+
87
+ declare class Parser {
88
+ rules: Map<string, Rule>;
89
+ settings: ParserSettings;
90
+ tokens: Token[];
91
+ index: number;
92
+ errors: ParseError[];
93
+ ast: Result[];
94
+ stats: ParseStatistics;
95
+ private _compiled;
96
+ private _ruleIndex;
97
+ private _laTable;
98
+ private _memo;
99
+ private _depth;
100
+ private _silentDepth;
101
+ private _rootStart;
102
+ private _startTime;
103
+ private _debugLevel;
104
+ private _ignoredSet;
105
+ lastHandledRule: string;
106
+ lastVisitedIndex: number;
107
+ ruleStack: string[];
108
+ constructor(rules: Rule[], settings?: ParserSettings);
109
+ parse(tokens: Token[]): ParseResult;
110
+ dispose(): void;
111
+ isNextToken(kind: string, extra?: string[]): boolean;
112
+ isPrevToken(kind: string, from?: number, extra?: string[]): boolean;
113
+ isPrevRule(name: string): boolean;
114
+ private _buildLookaheadSets;
115
+ private _firstOfPattern;
116
+ private _compilePattern;
117
+ private _compileToken;
118
+ private _compileRule;
119
+ private _compileSeq;
120
+ private _compileChoice;
121
+ private _compileOptional;
122
+ private _compileRepeat;
123
+ private _compilePratt;
124
+ private _compileConditional;
125
+ private _compileAction;
126
+ private _compileNot;
127
+ private _compileLookahead;
128
+ private _getMemo;
129
+ private _setMemo;
130
+ private _mkError;
131
+ private _customErrorOr;
132
+ private _addError;
133
+ private _handleFatal;
134
+ private _safeBuild;
135
+ private _span;
136
+ private _spanOf;
137
+ private _skipIgnored;
138
+ private _patStr;
139
+ private _validateGrammar;
140
+ private _normalizeSettings;
141
+ private _reset;
142
+ }
143
+
144
+ interface MiniToken {
145
+ kind: string;
146
+ value: string | null;
147
+ }
148
+ /**
149
+ * Conditional context passed to predicate function.
150
+ * Provides access to parser state for conditional decision-making.
151
+ */
152
+ interface ConditionalContext {
153
+ parser: Parser;
154
+ result: Result | null;
155
+ index: number;
156
+ depth: number;
157
+ ruleStack: string[];
158
+ }
159
+ /**
160
+ * Predicate function for conditional pattern execution.
161
+ * Return true to continue with the pattern, false to fail.
162
+ */
163
+ type ConditionalPredicate = (context: ConditionalContext) => boolean;
164
+ /**
165
+ * Action function executed for side effects during parsing.
166
+ * Called during pattern execution, can access and modify parser state.
167
+ */
168
+ type ActionFunction = (parser: Parser) => void;
169
+ interface Pattern {
170
+ type: 'token' | 'rule' | 'repeat' | 'choice' | 'seq' | 'optional' | 'pratt' | 'conditional' | 'action' | 'not' | 'lookahead';
171
+ silent: boolean;
172
+ value?: string;
173
+ name?: string;
174
+ min?: number;
175
+ max?: number;
176
+ patterns?: Pattern[];
177
+ separator?: Pattern;
178
+ pattern?: Pattern;
179
+ table?: PrattTable;
180
+ predicate?: ConditionalPredicate;
181
+ fn?: ActionFunction;
182
+ params?: Record<string, any>;
183
+ }
184
+ interface PrefixHandler {
185
+ /** How tightly this prefix binds its right operand. */
186
+ bp: number;
187
+ parse: (parser: Parser, token: Token) => Result;
188
+ }
189
+ interface InfixHandler {
190
+ /** Precedence level - left binding power. */
191
+ lbp: number;
192
+ /** Right binding power (lbp - 1 for right-associative). Defaults to lbp. */
193
+ rbp?: number;
194
+ parse: (parser: Parser, left: Result, token: Token) => Result;
195
+ }
196
+ interface PrattTable {
197
+ prefix: Map<string, PrefixHandler>;
198
+ infix: Map<string, InfixHandler>;
199
+ }
200
+ interface ErrorHandler {
201
+ cond: number | ((parser: Parser, opt: {
202
+ failedAt: number;
203
+ tokenIndex: number;
204
+ force?: boolean;
205
+ prevRule?: string;
206
+ prevInnerRule?: string;
207
+ }) => boolean);
208
+ msg: string;
209
+ code?: string;
210
+ }
211
+ interface RecoveryStrategy {
212
+ type: 'skipUntil' | 'synchronize';
213
+ tokens?: string[];
214
+ token?: string;
215
+ }
216
+ type BuildFunction = (matches: Result, parser: Parser) => Result;
217
+ interface Rule {
218
+ name: string;
219
+ pattern: Pattern;
220
+ options?: {
221
+ build?: BuildFunction;
222
+ errors?: ErrorHandler[];
223
+ recovery?: RecoveryStrategy;
224
+ ignored?: string[];
225
+ silent?: boolean;
226
+ };
227
+ }
228
+ type Rules = Rule[];
229
+ interface ParseStatistics {
230
+ tokensProcessed: number;
231
+ rulesApplied: number;
232
+ errorsRecovered: number;
233
+ parseTimeMs: number;
234
+ }
235
+ interface ParseError {
236
+ msg: string;
237
+ code: string;
238
+ span: Span;
239
+ failedAt: number;
240
+ tokenIndex: number;
241
+ startIndex: number;
242
+ prevRule: string;
243
+ prevInnerRule?: string;
244
+ }
245
+ interface ParseResult {
246
+ ast: Result[];
247
+ errors: ParseError[];
248
+ statistics?: ParseStatistics;
249
+ }
250
+ type DebugLevel = 'off' | 'errors' | 'rules' | 'patterns' | 'tokens' | 'verbose';
251
+ interface ParserSettings {
252
+ startRule: string;
253
+ errorRecovery?: {
254
+ mode?: 'strict' | 'resilient';
255
+ maxErrors?: number;
256
+ };
257
+ ignored?: string[];
258
+ debug?: DebugLevel;
259
+ maxDepth?: number;
260
+ }
261
+ declare const ERRORS: {
262
+ readonly LEXICAL_ERROR: "LEXICAL_ERROR";
263
+ readonly TOKEN_EXPECTED_EOF: "TOKEN_EXPECTED_EOF";
264
+ readonly TOKEN_MISMATCH: "TOKEN_MISMATCH";
265
+ readonly RULE_FAILED: "RULE_FAILED";
266
+ readonly BUILD_FUNCTION_FAILED: "BUILD_FUNCTION_FAILED";
267
+ readonly REPEAT_MIN_NOT_MET: "REPEAT_MIN_NOT_MET";
268
+ readonly SEQUENCE_FAILED: "SEQUENCE_FAILED";
269
+ readonly CUSTOM_ERROR: "CUSTOM_ERROR";
270
+ readonly CHOICE_ALL_FAILED: "CHOICE_ALL_FAILED";
271
+ readonly PRATT_NO_PREFIX: "PRATT_NO_PREFIX";
272
+ readonly FATAL_ERROR: "FATAL_ERROR";
273
+ readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
274
+ readonly RECOVERY_CUSTOM: "RECOVERY_CUSTOM";
275
+ };
276
+ /**
277
+ * Global registry mapping string literals to token kinds.
278
+ * Example: {'let': 'LET', 'if': 'IF', '{': 'LBRACE'}
279
+ * When registered, string patterns like seq('let', 'IDENT') will work.
280
+ */
281
+ declare const globalTokenMap: Record<string, string>;
282
+
283
+ /**
284
+ * Register a global token map for string shorthand patterns.
285
+ * After registration, you can use 'let', 'if', etc. directly in patterns.
286
+ *
287
+ * @example
288
+ * registerTokenMap({
289
+ * 'let': 'LET',
290
+ * 'if': 'IF',
291
+ * '{': 'LBRACE',
292
+ * '}': 'RBRACE',
293
+ * '=': 'EQ',
294
+ * });
295
+ *
296
+ * // Now you can write:
297
+ * seq('let', 'IDENT', '=', rule('expr'))
298
+ */
299
+ declare function registerTokenMap(map: Record<string, string>): void;
300
+ declare function parse(tokens: Token[], rules: Rules, settings?: ParserSettings): ParseResult;
301
+ declare function createRule(name: string, pattern: Pattern, options?: Rule['options']): Rule;
302
+ declare function token(name: string, value?: string): Pattern;
303
+ declare function optional(pattern: Pattern): Pattern;
304
+ declare function choice(...patterns: Pattern[]): Pattern;
305
+ declare function repeat(pattern: Pattern, min?: number, max?: number, separator?: Pattern): Pattern;
306
+ declare function oneOrMore(pattern: Pattern, separator?: Pattern): Pattern;
307
+ declare function zeroOrMore(pattern: Pattern, separator?: Pattern): Pattern;
308
+ declare function zeroOrOne(pattern: Pattern, separator?: Pattern): Pattern;
309
+ declare function seq(...patterns: Pattern[]): Pattern;
310
+ declare function rule(name: string): Pattern;
311
+ declare function rule(name: string, params: Record<string, unknown>): Pattern;
312
+ declare function silent<T extends Pattern>(pattern: T): T;
313
+ declare function loud<T extends Pattern>(pattern: T): T;
314
+ /**
315
+ * Build a Pratt expression parser inline in a rule.
316
+ *
317
+ * @example
318
+ * const expr = pratt({
319
+ * prefix: new Map([
320
+ * ['NUM', { bp: 0, parse: (_, tok) => Result.createAsToken('passed', tok, tok.span) }],
321
+ * ['MINUS', { bp: 70, parse: (p, tok) => {
322
+ * const right = p.parse(...) // handled via sub-rule
323
+ * return Result.createAsPratt('passed', [right], right.span)
324
+ * }}],
325
+ * ]),
326
+ * infix: new Map([
327
+ * ['PLUS', { lbp: 50, parse: (_, left, tok) => ... }],
328
+ * ['STAR', { lbp: 60, parse: (_, left, tok) => ... }],
329
+ * ['STAR2', { lbp: 70, rbp: 69, parse: ... }], // right-associative
330
+ * ]),
331
+ * });
332
+ */
333
+ declare function pratt(table: PrattTable): Pattern;
334
+ /**
335
+ * Adds conditional execution to a pattern.
336
+ * The predicate receives parser context and decides whether to continue.
337
+ *
338
+ * @param pattern - The pattern to conditionally execute
339
+ * @param predicate - Function that receives parser context and returns true to continue
340
+ * @returns Conditional pattern that evaluates predicate after inner pattern matches
341
+ *
342
+ * @example
343
+ * // Only match if we're not too deep in the parse tree
344
+ * pattern.if(ctx => ctx.depth < 10)
345
+ *
346
+ * // Only match if next token after match is LBRACE
347
+ * token('IF').if(ctx => ctx.parser.isNextToken('LBRACE'))
348
+ *
349
+ * // Inspect full parser state
350
+ * rule('expr').if(ctx => {
351
+ * return ctx.parser.errors.length === 0 && ctx.ruleStack.length < 5
352
+ * })
353
+ */
354
+ declare function conditional(pattern: Pattern, predicate: ConditionalPredicate): Pattern;
355
+ /**
356
+ * Shorthand for conditional() - more natural syntax
357
+ * @see conditional
358
+ */
359
+ declare function when(pattern: Pattern, predicate: ConditionalPredicate): Pattern;
360
+ /**
361
+ * Method-chaining style: pattern.if(predicate)
362
+ * Extends Pattern type with .if() method for fluent API
363
+ *
364
+ * @note This is implemented as a utility function, not directly on Pattern
365
+ * Use: conditional(pattern, predicate) or when(pattern, predicate)
366
+ */
367
+ declare function ifCondition(pattern: Pattern, predicate: ConditionalPredicate): Pattern;
368
+ /**
369
+ * Action pattern - executes a side effect during parsing.
370
+ * Useful for scope management, state tracking, and stateful parsing.
371
+ *
372
+ * @param fn - Function called during execution with access to parser state
373
+ * @returns Action pattern that always succeeds
374
+ *
375
+ * @example
376
+ * // Track parse state
377
+ * seq(
378
+ * token('LBRACE'),
379
+ * action(p => p.symbolTable?.pushScope()),
380
+ * zeroOrMore(rule('stmt')),
381
+ * token('RBRACE'),
382
+ * action(p => p.symbolTable?.popScope())
383
+ * )
384
+ *
385
+ * // Count custom metric
386
+ * action(p => p.stats.customCounter = (p.stats.customCounter ?? 0) + 1)
387
+ */
388
+ declare function action(fn: ActionFunction): Pattern;
389
+ /**
390
+ * NOT pattern - succeeds if the inner pattern FAILS.
391
+ * Useful for negative lookahead and validation checks.
392
+ *
393
+ * @param pattern - The pattern to negate
394
+ * @returns NOT pattern
395
+ *
396
+ * @example
397
+ * // Match any character except EOF
398
+ * not(token('EOF'))
399
+ *
400
+ * // In a choice: match IDENT that is not a keyword
401
+ * choice(
402
+ * not(choice(token('IF'), token('WHILE'), token('FOR'))),
403
+ * token('IDENT')
404
+ * )
405
+ */
406
+ declare function not(pattern: Pattern): Pattern;
407
+ /**
408
+ * Lookahead pattern - checks if inner pattern would match WITHOUT consuming tokens.
409
+ * Common alias: peek()
410
+ *
411
+ * @param pattern - The pattern to lookahead check
412
+ * @returns Lookahead pattern
413
+ *
414
+ * @example
415
+ * // Only match expr if followed by RPAREN
416
+ * seq(
417
+ * lookahead(seq(rule('expr'), token('RPAREN'))),
418
+ * rule('expr')
419
+ * )
420
+ *
421
+ * // Safe token inspection
422
+ * seq(
423
+ * token('IDENT'),
424
+ * when(lookahead(token('LPAREN')), ctx => ctx.parser.isNextToken('LPAREN'))
425
+ * )
426
+ */
427
+ declare function lookahead(pattern: Pattern): Pattern;
428
+ /**
429
+ * Alias for lookahead() - more concise syntax.
430
+ * @see lookahead
431
+ */
432
+ declare function peek(pattern: Pattern): Pattern;
433
+ /** Convenience: build a PrattTable from plain objects. */
434
+ declare function buildPrattTable(spec: {
435
+ prefix?: Record<string, PrefixHandler>;
436
+ infix?: Record<string, InfixHandler>;
437
+ }): PrattTable;
438
+ /**
439
+ * Delimited list pattern - matches items separated by a delimiter.
440
+ * Commonly used for comma-separated values, arguments, etc.
441
+ *
442
+ * @param item - The pattern for each list item
443
+ * @param sep - The separator pattern (usually token(','))
444
+ * @param options - {min?: number, trailingOk?: boolean}
445
+ * @returns Composed pattern for delimited list
446
+ *
447
+ * @example
448
+ * // Comma-separated identifiers (0+)
449
+ * delimited(token('IDENT'), token('COMMA'))
450
+ *
451
+ * // Function arguments (1+ with optional trailing)
452
+ * delimited(rule('expr'), token('COMMA'), {min: 1, trailingOk: true})
453
+ *
454
+ * // Array elements
455
+ * between('[', delimited(rule('expr'), token('COMMA')), ']')
456
+ */
457
+ declare function delimited(item: Pattern, sep: Pattern, options?: {
458
+ min?: number;
459
+ trailingOk?: boolean;
460
+ }): Pattern;
461
+ /**
462
+ * Surrounded pattern - matches content between open and close delimiters.
463
+ * Alias for between(open, content, close).
464
+ *
465
+ * @param content - The pattern for interior content
466
+ * @param open - Opening delimiter
467
+ * @param close - Closing delimiter
468
+ * @returns Composed pattern: open, content, close
469
+ *
470
+ * @example
471
+ * // Parenthesized expression
472
+ * surrounded(rule('expr'), token('LPAREN'), token('RPAREN'))
473
+ *
474
+ * // Generic syntax with string shorthand
475
+ * surrounded(rule('typeList'), '(', ')')
476
+ */
477
+ declare function surrounded(content: Pattern, open: Pattern, close: Pattern): Pattern;
478
+ /**
479
+ * Between pattern - matches content between left and right patterns.
480
+ * Alias for surrounded but with more explicit name.
481
+ *
482
+ * @param left - Left sentinel pattern
483
+ * @param content - Interior content pattern
484
+ * @param right - Right sentinel pattern
485
+ * @returns Composed pattern: left, content, right
486
+ *
487
+ * @example
488
+ * // Array literal
489
+ * between(token('LBRACK'), delimited(rule('expr'), token('COMMA')), token('RBRACK'))
490
+ *
491
+ * // Function call
492
+ * between('(', delimited(rule('param'), ','), ')')
493
+ */
494
+ declare function between(left: Pattern, content: Pattern, right: Pattern): Pattern;
495
+ declare function error(cond: ErrorHandler['cond'], msg: string, code?: string): ErrorHandler;
496
+ declare const errorRecoveryStrategies: {
497
+ skipUntil(tokens: string | string[]): RecoveryStrategy;
498
+ };
499
+
500
+ export { type BuildFunction, type ConditionalContext, type ConditionalPredicate, type DebugLevel, ERRORS, type ErrorHandler, type InfixHandler, type MiniToken, type ParseError, type ParseResult, Parser, type ParserSettings, type Pattern, type PrattTable, type PrefixHandler, type RecoveryStrategy, Result, type Rule, type Rules, action, between, buildPrattTable, choice, conditional, createRule, delimited, error, errorRecoveryStrategies, globalTokenMap, ifCondition, lookahead, loud, not, oneOrMore, optional, parse, peek, pratt, registerTokenMap, repeat, rule, seq, silent, surrounded, token, when, zeroOrMore, zeroOrOne };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ var h=class s{constructor(e,t,r,n){this.span={start:-99,end:-99};this.status="unset";this.source=null;this.mode="unset";this.errors=[];this.status=e,this.source=t,this.mode=r,this.span=n;}static create(e,t,r,n){return new s(e,t,r,n)}static createAsToken(e,t,r){return s.create(e,{source_kind:"token-source",type:t?.type??"unset",text:t?.text??void 0,span:r},"token",r)}static createAsOptional(e,t,r){return s.create(e,{source_kind:"optional-source",result:t},"optional",r)}static createAsChoice(e,t,r,n){return s.create(e,{source_kind:"choice-source",atIndex:r,result:t},"choice",n)}static createAsRepeat(e,t,r,n=false){return s.create(e,{source_kind:"repeat-source",endsWithSep:n,result:t??[]},"repeat",r)}static createAsSequence(e,t,r){return s.create(e,{source_kind:"sequence-source",result:t??[]},"seq",r)}static createAsPratt(e,t,r){return s.create(e,{source_kind:"pratt-source",result:t},"pratt",r)}static createAsCustom(e,t,r,n){return s.create(e,{source_kind:"custom-source",name:t,data:r},"custom",n)}isPassed(){return this.status==="passed"}isFailed(){return this.status==="failed"}isUnset(){return this.status==="unset"}isToken(){return this.mode==="token"}isOptional(){return this.mode==="optional"}isChoice(){return this.mode==="choice"}isRepeat(){return this.mode==="repeat"}isSequence(){return this.mode==="seq"}isPratt(){return this.mode==="pratt"}isFullyPassed(){return !(!this.isPassed()||this.isOptional()&&!this.isOptionalPassed())}isOptionalPassed(){return this.isOptional()&&this.source.result!==null}isCustom(e){return this.mode!=="custom"?false:e?this.source.name===e:true}getTokenType(){return this.isToken()?this.source.type:void 0}getTokenSpan(){return this.isToken()?this.source.span:void 0}getOptionalResult(){return this.isOptionalPassed()?this.source.result:void 0}getChoiceIndex(){return this.isChoice()?this.source.atIndex:void 0}getChoiceResult(){return this.isChoice()?this.source.result:void 0}getRepeatCount(){return this.isRepeat()?this.source.result.length:void 0}getRepeatResult(){return this.isRepeat()?this.source.result:void 0}isRepeatEndsWithSep(){return this.isRepeat()?this.source.endsWithSep:void 0}getSequenceCount(){return this.isSequence()?this.source.result.length:void 0}getSequenceResult(){return this.isSequence()?this.source.result:void 0}getPrattResult(){return this.isPratt()?this.source.result:void 0}getCustomData(){return this.isCustom()?this.source.data:void 0}getCustomName(){return this.isCustom()?this.source.name:void 0}getTokenValue(){if(!this.isToken())return;let e=this.source.text;return e===void 0?null:e}getTokenData(){if(!this.isToken())return;let e=this.source;return {type:e.type,text:e.text,span:e.span}}clone(){let e=new s(this.status,this.source,this.mode,this.span);return e.errors=[...this.errors],e}hasErrors(){return this.errors.length>0}withError(e){return this.errors.push(e),this}};var p={LEXICAL_ERROR:"LEXICAL_ERROR",TOKEN_EXPECTED_EOF:"TOKEN_EXPECTED_EOF",TOKEN_MISMATCH:"TOKEN_MISMATCH",RULE_FAILED:"RULE_FAILED",BUILD_FUNCTION_FAILED:"BUILD_FUNCTION_FAILED",REPEAT_MIN_NOT_MET:"REPEAT_MIN_NOT_MET",SEQUENCE_FAILED:"SEQUENCE_FAILED",CUSTOM_ERROR:"CUSTOM_ERROR",CHOICE_ALL_FAILED:"CHOICE_ALL_FAILED",PRATT_NO_PREFIX:"PRATT_NO_PREFIX",FATAL_ERROR:"FATAL_ERROR",UNKNOWN_ERROR:"UNKNOWN_ERROR",RECOVERY_CUSTOM:"RECOVERY_CUSTOM"},E={};var d=h.create("failed",null,"unset",{start:-1,end:-1}),g=class{constructor(e,t){this.tokens=[];this.index=0;this.errors=[];this.ast=[];this.stats={tokensProcessed:0,rulesApplied:0,errorsRecovered:0,parseTimeMs:0};this._compiled=new Map;this._ruleIndex=new Map;this._laTable=new Map;this._memo=new Map;this._depth=0;this._silentDepth=0;this._rootStart=0;this._startTime=0;this._debugLevel="off";this._ignoredSet=new Set;this.lastHandledRule="unknown";this.lastVisitedIndex=0;this.ruleStack=[];this.rules=new Map(e.map(i=>[i.name,i])),this.settings=this._normalizeSettings(t),this._debugLevel=this.settings.debug,this._ignoredSet=new Set(this.settings.ignored);let r=0;for(let i of this.rules.keys())this._ruleIndex.set(i,r++);let n=this._validateGrammar();if(n.length)throw new Error(`Grammar validation failed:
2
+ ${n.join(`
3
+ `)}`);this._buildLookaheadSets();for(let[i,o]of this.rules)this._compiled.set(i,this._compilePattern(o.pattern,o));}parse(e){if(this._reset(e),this._startTime=Date.now(),!e.length)return {ast:[],errors:[]};let t=e.find(a=>a.type==="error");if(t)return {ast:[],errors:[this._mkError(p.LEXICAL_ERROR,`Unexpected token '${t.text}'`,t.span,0,0,"lexer")]};let r=this.rules.get(this.settings.startRule);if(!r)throw new Error(`Start rule '${this.settings.startRule}' not found`);let n=this._compiled.get(this.settings.startRule),i=this.settings.errorRecovery.maxErrors;this.settings.errorRecovery.mode==="resilient";try{for(this._skipIgnored();this.index<this.tokens.length&&!(i>0&&this.errors.length>=i);){let a=this.index;this._rootStart=a;let u=n(!1);if(u.isPassed()){let l=r.options?.build?this._safeBuild(r.options.build,u):u;l&&this.ast.push(l);}if(this.index===a)break;this._skipIgnored();}}catch(a){this._handleFatal(a);}return this.stats.parseTimeMs=Date.now()-this._startTime,{ast:this.ast,errors:this.errors,statistics:this.stats}}dispose(){this._memo.clear(),this._compiled.clear(),this.tokens=[],this.ast=[],this.errors=[];}isNextToken(e,t){let r=new Set([...this._ignoredSet,...t??[]]);for(let n=this.index;n<this.tokens.length;n++){let i=this.tokens[n];if(i.type===e)return true;if(!r.has(i.type))break}return false}isPrevToken(e,t=-1,r){let n=new Set([...this._ignoredSet,...r??[]]),i=t<0?this.index:t;for(let o=i-1;o>=0;o--){let a=this.tokens[o];if(a.type===e)return true;if(!n.has(a.type))break}return false}isPrevRule(e){return this.lastHandledRule===e}_buildLookaheadSets(){for(let t of this.rules.keys())this._laTable.set(t,new Set);let e=true;for(;e;){e=false;for(let[t,r]of this.rules){let n=this._laTable.get(t),i=this._firstOfPattern(r.pattern);for(let o of i)n.has(o)||(n.add(o),e=true);}}}_firstOfPattern(e){let t=new Set;switch(e.type){case "token":t.add(e.name);break;case "rule":{let r=this._laTable.get(e.name);if(r)for(let n of r)t.add(n);break}case "seq":for(let r of e.patterns??[]){for(let n of this._firstOfPattern(r))t.add(n);if(r.type!=="optional")break}break;case "choice":for(let r of e.patterns??[])for(let n of this._firstOfPattern(r))t.add(n);break;case "optional":case "repeat":case "conditional":case "not":case "lookahead":if(e.pattern)for(let r of this._firstOfPattern(e.pattern))t.add(r);break;case "action":break;case "pratt":if(e.table)for(let r of e.table.prefix.keys())t.add(r);break}return t}_compilePattern(e,t){switch(e.type){case "token":return this._compileToken(e,t);case "rule":return this._compileRule(e,t);case "seq":return this._compileSeq(e,t);case "choice":return this._compileChoice(e,t);case "repeat":return this._compileRepeat(e,t);case "optional":return this._compileOptional(e,t);case "pratt":return this._compilePratt(e,t);case "conditional":return this._compileConditional(e,t);case "action":return this._compileAction(e,t);case "not":return this._compileNot(e,t);case "lookahead":return this._compileLookahead(e,t);default:throw new Error(`Unknown pattern type: ${e.type}`)}}_compileToken(e,t){let r=e.name,n=e.value;return i=>{if(this.lastHandledRule=t?.name??r,this.lastVisitedIndex=this.index,this.index>=this.tokens.length){if(i)return d;throw this._mkError(p.TOKEN_EXPECTED_EOF,`Expected '${r}', got EOF`,this._span(),0,this.index,this.lastHandledRule)}let o=this.tokens[this.index];if(o.type===r){if(n!==void 0&&o.text!==n){if(i)return d;throw this._mkError(p.TOKEN_MISMATCH,`Expected '${r}' with value '${n}', got '${o.text}'`,o.span,0,this.index,this.lastHandledRule)}return this.index++,this.stats.tokensProcessed++,h.createAsToken("passed",o,o.span)}if(i)return d;let a=this._mkError(p.TOKEN_MISMATCH,`Expected '${r}', got '${o.type}'`,o.span,0,this.index,this.lastHandledRule);throw this._customErrorOr(t,a)}}_compileRule(e,t){let r=e.name;return n=>{let i=this.rules.get(r);if(!i)throw new Error(`Rule '${r}' not found`);let o=this._compiled.get(r);if(!o)throw new Error(`Rule '${r}' not compiled`);this.ruleStack.push(r),this.stats.rulesApplied++;let u=(this._ruleIndex.get(r)??0)<<16|this.index,l=this._getMemo(u);if(l)return this.ruleStack.pop(),this.index=l.endIndex,l.result??d;let c=this.index,f=this.errors.length,m=o(n);if(!m.isFullyPassed()){if(this.index=c,this.ruleStack.pop(),n)return d;let _=this._mkError(p.RULE_FAILED,`Rule '${r}' failed`,this._span(),0,this.lastVisitedIndex,r);throw this._customErrorOr(t,_)}let R=m;if(i.options?.build){let _=this._safeBuild(i.options.build,m);_&&(R=_);}return this._setMemo(u,R,this.index,f),this.ruleStack.pop(),R}}_compileSeq(e,t){let r=(e.patterns??[]).map(n=>this._compilePattern(n,t));return n=>{let i=this.index,o=[];for(let a=0;a<r.length;a++){this._skipIgnored(t?.options?.ignored);let u=r[a](n);if(!u.isPassed()){if(this.index=i,n)return d;let l=this._mkError(p.SEQUENCE_FAILED,`Sequence failed at element ${a+1}/${r.length}`,this._span(),a,this.lastVisitedIndex,this.lastHandledRule);throw this._customErrorOr(t,l)}o.push(u);}return h.createAsSequence("passed",o,this._spanOf(o))}}_compileChoice(e,t){let r=e.patterns??[],n=r.map(o=>this._firstOfPattern(o)),i=r.map(o=>this._compilePattern(o,t));return o=>{let a=this.index;if(this._silentDepth++,this.index<this.tokens.length){let c=this.tokens[this.index].type,f=-1,m=false;for(let R=0;R<n.length;R++)if(n[R].has(c)){if(f>=0){m=true;break}f=R;}if(!m&&f>=0){this._silentDepth--;let R=i[f](o);if(R.isFullyPassed())return h.createAsChoice("passed",R,f,R.span);this.index=a,this._silentDepth++;}}let u=null;for(let c=0;c<i.length;c++){this.index=a;let f=i[c](true);if(f.isFullyPassed())return this._silentDepth--,h.createAsChoice("passed",f,c,f.span);let m=this.lastVisitedIndex-a;(!u||m>u.index-a)&&(u={index:this.lastVisitedIndex,err:null,altIdx:c});}if(this._silentDepth--,this.index=a,o)return d;let l=this._mkError(p.CHOICE_ALL_FAILED,`Expected one of: ${r.map(c=>this._patStr(c)).join(" | ")}`,this._span(),u?.altIdx??0,this.lastVisitedIndex,this.lastHandledRule);throw this._customErrorOr(t,l)}}_compileOptional(e,t){let r=this._compilePattern(e.pattern,t);return n=>{let i=this.index;this._silentDepth++;let o=r(true);return this._silentDepth--,o.isFullyPassed()?h.createAsOptional("passed",o,o.span):(this.index=i,h.createAsOptional("passed",null,this._span()))}}_compileRepeat(e,t){let r=e.min??0,n=e.max??1/0,i=this._compilePattern(e.pattern,t),o=e.separator?this._compilePattern(e.separator,t):null;return a=>{let u=[],l=false,c=this.index;for(;u.length<n&&this.index<this.tokens.length;){let f=this.index;this._silentDepth++;let m=i(true);if(this._silentDepth--,!m.isFullyPassed()){this.index=f,l=false;break}if(u.push(m),l=false,this.index===f)break;if(o&&u.length<n&&this.index<this.tokens.length){let R=this.index;this._silentDepth++;let _=o(true);if(this._silentDepth--,!_.isFullyPassed()){this.index=R;break}l=true;}}if(u.length<r){if(this.index=c,a)return d;throw this._mkError(p.REPEAT_MIN_NOT_MET,`Expected at least ${r} occurrences, got ${u.length}`,this._span(),0,this.index,this.lastHandledRule)}return h.createAsRepeat("passed",u,this._spanOf(u),l)}}_compilePratt(e,t){let r=e.table;return n=>{if(this.index>=this.tokens.length){if(n)return d;throw this._mkError(p.PRATT_NO_PREFIX,"Expected an expression",this._span(),0,this.index,"pratt")}let i=this.tokens[this.index],o=r.prefix.get(i.type);if(!o){if(n)return d;throw this._mkError(p.PRATT_NO_PREFIX,`Unexpected token '${i.type}' in expression`,i.span,0,this.index,"pratt")}this.index++;let a=o.parse(this,i);if(!a.isPassed())return n?d:a;for(;this.index<this.tokens.length&&(this._skipIgnored(),!(this.index>=this.tokens.length));){let u=this.tokens[this.index],l=r.infix.get(u.type);if(!l||l.lbp<=0||(this.index++,a=l.parse(this,a,u),!a.isPassed()))break}return a}}_compileConditional(e,t){let r=this._compilePattern(e.pattern,t),n=e.predicate;return i=>{let o=this.index,a;if(i?(this._silentDepth++,a=r(true),this._silentDepth--):a=r(false),!a.isFullyPassed())return this.index=o,i?d:a;try{let u={parser:this,result:a,index:this.index,depth:this._depth,ruleStack:[...this.ruleStack]};if(n(u))return h.createAsCustom("passed","conditional",a,a.span);{if(this.index=o,i)return d;let c=this._mkError(p.RULE_FAILED,"Conditional predicate returned false",this._span(),0,this.lastVisitedIndex,this.lastHandledRule);throw this._customErrorOr(t,c)}}catch(u){if(this.index=o,i)return d;let l=u instanceof Error?u.message:String(u),c=this._mkError(p.RULE_FAILED,`Conditional predicate threw: ${l}`,this._span(),0,this.lastVisitedIndex,this.lastHandledRule);throw this._customErrorOr(t,c)}}}_compileAction(e,t){let r=e.fn;return n=>{try{r(this);}catch(i){let o=i instanceof Error?i.message:String(i);throw this._mkError(p.RULE_FAILED,`Action function threw: ${o}`,this._span(),0,this.index,"action")}return h.createAsCustom("passed","action",null,this._span())}}_compileNot(e,t){let r=this._compilePattern(e.pattern,t);return n=>{let i=this.index;this._silentDepth++;let o=r(true);if(this._silentDepth--,o.isFullyPassed()){if(this.index=i,n)return d;let a=this._mkError(p.RULE_FAILED,"NOT pattern failed - inner pattern matched",this._span(),0,i,this.lastHandledRule);throw this._customErrorOr(t,a)}else return this.index=i,h.createAsCustom("passed","not",null,this._span())}}_compileLookahead(e,t){let r=this._compilePattern(e.pattern,t);return n=>{let i=this.index;this._silentDepth++;let o=r(true);if(this._silentDepth--,this.index=i,o.isFullyPassed())return h.createAsCustom("passed","lookahead",null,this._span());{if(n)return d;let a=this._mkError(p.RULE_FAILED,"Lookahead pattern failed",this._span(),0,i,this.lastHandledRule);throw this._customErrorOr(t,a)}}}_getMemo(e){let t=this._memo.get(e);return t?t.errorCount!==this.errors.length?(this._memo.delete(e),null):t:null}_setMemo(e,t,r,n){this._memo.set(e,{result:t,endIndex:r,errorCount:this.errors.length});}_mkError(e,t,r,n,i,o,a){return {code:e,msg:t,span:r,failedAt:n,tokenIndex:i,startIndex:this._rootStart,prevRule:o,prevInnerRule:a??this.ruleStack.at(-1)??"unknown"}}_customErrorOr(e,t){if(!e?.options?.errors)return t;for(let r of e.options.errors){let n=false;if(typeof r.cond=="number")n=t.failedAt===r.cond;else if(typeof r.cond=="function")try{n=r.cond(this,{failedAt:t.failedAt,tokenIndex:t.tokenIndex});}catch{}if(n)return this._mkError(r.code??p.CUSTOM_ERROR,r.msg,t.span,t.failedAt,t.tokenIndex,t.prevRule,t.prevInnerRule)}return t}_addError(e){if(this._silentDepth>0)return;let t=this.settings.errorRecovery.maxErrors;t>0&&this.errors.length>=t||this.settings.errorRecovery.mode==="strict"&&this.errors.length>0||this.errors.some(r=>r.span?.start===e.span?.start)||this.errors.push(e);}_handleFatal(e){e&&typeof e=="object"&&"msg"in e&&"code"in e?this._addError(e):e instanceof Error&&this._addError(this._mkError(p.FATAL_ERROR,e.message,this._span(),0,this.index,this.lastHandledRule));}_safeBuild(e,t){try{return e(t,this)}catch(r){let n=this._mkError(p.BUILD_FUNCTION_FAILED,r instanceof Error?r.message:String(r),this._span(),0,this.index,this.lastHandledRule);return this._addError(n),t}}_span(){if(!this.tokens.length)return {start:0,end:0};if(this.index>=this.tokens.length){let e=this.tokens[this.tokens.length-1];return {start:e.span.end,end:e.span.end}}return this.tokens[this.index].span}_spanOf(e){return e.length?{start:e[0].span.start,end:e[e.length-1].span.end}:this._span()}_skipIgnored(e){let t=e?new Set([...this._ignoredSet,...e]):this._ignoredSet;for(;this.index<this.tokens.length&&t.has(this.tokens[this.index].type);)this.index++,this.stats.tokensProcessed++;}_patStr(e){switch(e.type){case "token":return e.name;case "rule":return e.name;case "seq":return `(${(e.patterns??[]).map(t=>this._patStr(t)).join(" ")})`;case "choice":return (e.patterns??[]).map(t=>this._patStr(t)).join(" | ");case "optional":return `${this._patStr(e.pattern)}?`;case "repeat":return `${this._patStr(e.pattern)}*`;case "conditional":return `${this._patStr(e.pattern)}.if(...)`;case "action":return "action(...)";case "not":return `!${this._patStr(e.pattern)}`;case "lookahead":return `lookahead(${this._patStr(e.pattern)})`;case "pratt":return "expr";default:return e.type}}_validateGrammar(){let e=[],t=new Set(this.rules.keys()),r=(n,i)=>{n.type==="rule"&&!t.has(n.name)&&e.push(`Rule '${i}' references undefined rule '${n.name}'`);for(let o of [n.pattern,...n.patterns??[]])o&&r(o,i);n.separator&&r(n.separator,i);};for(let[n,i]of this.rules)r(i.pattern,n);return this.rules.has(this.settings.startRule)||e.push(`Start rule '${this.settings.startRule}' is not defined`),e}_normalizeSettings(e){return {startRule:e?.startRule??"root",errorRecovery:{mode:e?.errorRecovery?.mode??"strict",maxErrors:e?.errorRecovery?.maxErrors??1},ignored:e?.ignored??["ws"],debug:e?.debug??"off",maxDepth:e?.maxDepth??1e3}}_reset(e){this.tokens=e,this.index=0,this.errors=[],this.ast=[],this._depth=0,this._silentDepth=0,this._rootStart=0,this.ruleStack=[],this._memo.clear(),this.stats={tokensProcessed:0,rulesApplied:0,errorsRecovered:0,parseTimeMs:0};}};function w(s){Object.assign(E,s);}function F(s,e,t){let r=new g(e,t);try{return r.parse(s)}finally{r.dispose();}}function L(s,e,t={}){return {name:s,pattern:e,options:{name:false,...t}}}function M(s,e){if(!s)throw new Error("token(): name must be a non-empty string");return {type:"token",name:s,value:e,silent:false}}function k(s){return {type:"optional",pattern:s,silent:false}}function D(...s){if(!s.length)throw new Error("choice(): at least one pattern required");return {type:"choice",patterns:s,silent:false}}function T(s,e=0,t=1/0,r){if(e<0)throw new Error("repeat(): min cannot be negative");if(t<e)throw new Error("repeat(): max cannot be less than min");return {type:"repeat",pattern:s,min:e,max:t,separator:r,silent:false}}function H(s,e){return T(s,1,1/0,e)}function x(s,e){return T(s,0,1/0,e)}function N(s,e){return O(T(s,0,1,e))}function y(...s){if(!s.length)throw new Error("seq(): at least one pattern required");return {type:"seq",patterns:s,silent:false}}function U(s,e){if(!s)throw new Error("rule(): name must be a non-empty string");return {type:"rule",name:s,params:e,silent:false}}function O(s){return {...s,silent:true}}function $(s){return {...s,silent:false}}function q(s){return {type:"pratt",table:s,silent:false}}function S(s,e){return {type:"conditional",pattern:s,predicate:e,silent:false}}function V(s,e){return S(s,e)}function B(s,e){return S(s,e)}function K(s){return {type:"action",fn:s,silent:false}}function X(s){return {type:"not",pattern:s,silent:false}}function I(s){return {type:"lookahead",pattern:s,silent:false}}function j(s){return I(s)}function W(s){return {prefix:new Map(Object.entries(s.prefix??{})),infix:new Map(Object.entries(s.infix??{}))}}function z(s,e,t){let{min:r=0,trailingOk:n=false}=t??{},i;return r===0?n?i=k(y(T(s,1,1/0),x(y(e,s)),k(e))):i=k(y(T(s,1,1/0),x(y(e,s)))):r===1?n?i=y(T(s,1,1/0),x(y(e,s)),k(e)):i=y(T(s,1,1/0),x(y(e,s))):n?i=y(T(s,r,1/0),x(y(e,s)),k(e)):i=y(T(s,r,1/0),x(y(e,s))),i}function G(s,e,t){return y(e,s,t)}function Q(s,e,t){return y(s,e,t)}function Y(s,e,t){return {cond:s,msg:e,code:t??p.RECOVERY_CUSTOM}}var J={skipUntil(s){return {type:"skipUntil",tokens:Array.isArray(s)?s:[s]}}};export{p as ERRORS,g as Parser,h as Result,K as action,Q as between,W as buildPrattTable,D as choice,S as conditional,L as createRule,z as delimited,Y as error,J as errorRecoveryStrategies,E as globalTokenMap,B as ifCondition,I as lookahead,$ as loud,X as not,H as oneOrMore,k as optional,F as parse,j as peek,q as pratt,w as registerTokenMap,T as repeat,U as rule,y as seq,O as silent,G as surrounded,M as token,V as when,x as zeroOrMore,N as zeroOrOne};
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@minelang-ts/parser",
3
+ "version": "0.0.1",
4
+ "description": "Mine programming language parser.",
5
+ "keywords": ["mine", "programming", "language", "parser"],
6
+ "license": "MIT",
7
+ "author": {
8
+ "email": "maysara.elshewehy@gmail.com",
9
+ "name": "Maysara Elshewehy",
10
+ "url": "https://github.com/maysara-elshewehy"
11
+ },
12
+ "type": "module",
13
+ "homepage": "https://github.com/minelang-ts/parser#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/minelang-ts/parser/issues"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/minelang-ts/parser.git"
20
+ },
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "files": ["dist"],
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "import": "./dist/index.js",
28
+ "require": "./dist/index.js"
29
+ }
30
+ },
31
+ "engines": {
32
+ "bun": ">=1.3.3"
33
+ },
34
+ "pkg": {
35
+ "type": "pkg"
36
+ },
37
+ "scripts": {},
38
+ "peerDependencies": {
39
+ "bun": "^1.3.14"
40
+ },
41
+ "dependencies": {
42
+ "@minelang-ts/lexer": "^0.0.1"
43
+ },
44
+ "devDependencies": {
45
+ "@eslint/js": "^10.0.1",
46
+ "@stylistic/eslint-plugin": "^5.10.0",
47
+ "@types/bun": "^1.3.14",
48
+ "@types/node": "^26.0.1",
49
+ "bun-plugin-dts": "^0.4.0",
50
+ "bun-types": "^1.3.14",
51
+ "ts-node": "^10.9.2",
52
+ "tsup": "^8.5.1",
53
+ "typescript": "^6.0.3",
54
+ "typescript-eslint": "^8.62.1"
55
+ }
56
+ }