summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-01-24 18:59:13 -0700
committerElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-01-24 18:59:13 -0700
commit203925d9a48d34537bdf6cd25502134df5e91ae7 (patch)
treeafe8a12679568ba00bfa019b0a5b6f13a3778c00
downloadtabloid-compiler-203925d9a48d34537bdf6cd25502134df5e91ae7.tar.gz
tabloid-compiler-203925d9a48d34537bdf6cd25502134df5e91ae7.zip
initial commitHEADmain
-rw-r--r--.gitignore175
-rw-r--r--.prettierrc17
-rw-r--r--.tool-versions1
-rwxr-xr-xbun.lockbbin0 -> 21962 bytes
-rw-r--r--package.json18
-rw-r--r--src/args.ts9
-rw-r--r--src/index.ts34
-rw-r--r--src/parser/generate.ts8
-rw-r--r--src/parser/grammar.peg67
-rw-r--r--src/parser/grammar.peg.new67
-rw-r--r--src/parser/index.ts2
-rw-r--r--src/parser/parser.ts2082
-rw-r--r--src/utils/index.ts1
-rw-r--r--src/utils/logger.ts35
-rw-r--r--test/parser.spec.ts12
-rw-r--r--test/programs/fib.ts1
-rw-r--r--test/programs/index.ts5
-rw-r--r--test/programs/module.ts37
-rw-r--r--test/programs/router.ts75
-rw-r--r--tsconfig.json27
20 files changed, 2673 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..468f82a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,175 @@
+# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
+
+# Logs
+
+logs
+_.log
+npm-debug.log_
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Caches
+
+.cache
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+
+report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
+
+# Runtime data
+
+pids
+_.pid
+_.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+
+lib-cov
+
+# Coverage directory used by tools like istanbul
+
+coverage
+*.lcov
+
+# nyc test coverage
+
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+
+bower_components
+
+# node-waf configuration
+
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+
+build/Release
+
+# Dependency directories
+
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+
+web_modules/
+
+# TypeScript cache
+
+*.tsbuildinfo
+
+# Optional npm cache directory
+
+.npm
+
+# Optional eslint cache
+
+.eslintcache
+
+# Optional stylelint cache
+
+.stylelintcache
+
+# Microbundle cache
+
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+
+.node_repl_history
+
+# Output of 'npm pack'
+
+*.tgz
+
+# Yarn Integrity file
+
+.yarn-integrity
+
+# dotenv environment variable files
+
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache (https://parceljs.org/)
+
+.parcel-cache
+
+# Next.js build output
+
+.next
+out
+
+# Nuxt.js build / generate output
+
+.nuxt
+dist
+
+# Gatsby files
+
+# Comment in the public line in if your project uses Gatsby and not Next.js
+
+# https://nextjs.org/blog/next-9-1#public-directory-support
+
+# public
+
+# vuepress build output
+
+.vuepress/dist
+
+# vuepress v2.x temp and cache directory
+
+.temp
+
+# Docusaurus cache and generated files
+
+.docusaurus
+
+# Serverless directories
+
+.serverless/
+
+# FuseBox cache
+
+.fusebox/
+
+# DynamoDB Local files
+
+.dynamodb/
+
+# TernJS port file
+
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+
+.vscode-test
+
+# yarn v2
+
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+# IntelliJ based IDEs
+.idea
+
+# Finder (MacOS) folder config
+.DS_Store
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..38213eb
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,17 @@
+{
+ "arrowParens": "avoid",
+ "bracketSpacing": true,
+ "htmlWhitespaceSensitivity": "css",
+ "insertPragma": false,
+ "jsxBracketSameLine": false,
+ "jsxSingleQuote": true,
+ "printWidth": 80,
+ "proseWrap": "always",
+ "quoteProps": "as-needed",
+ "requirePragma": false,
+ "semi": true,
+ "singleQuote": true,
+ "tabWidth": 2,
+ "trailingComma": "all",
+ "useTabs": false
+}
diff --git a/.tool-versions b/.tool-versions
new file mode 100644
index 0000000..5769236
--- /dev/null
+++ b/.tool-versions
@@ -0,0 +1 @@
+bun 1.0.25
diff --git a/bun.lockb b/bun.lockb
new file mode 100755
index 0000000..c47b87a
--- /dev/null
+++ b/bun.lockb
Binary files differ
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..d511a33
--- /dev/null
+++ b/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "tabloid-compiler",
+ "type": "module",
+ "devDependencies": {
+ "@types/bun": "latest"
+ },
+ "module": "src/index.ts",
+ "peerDependencies": {
+ "typescript": "^5.0.0"
+ },
+ "dependencies": {
+ "@types/minimist": "^1.2.5",
+ "minimist": "^1.2.8",
+ "prettier": "^3.2.4",
+ "ts-pegjs": "^4.2.1",
+ "tspeg": "^3.3.1"
+ }
+}
diff --git a/src/args.ts b/src/args.ts
new file mode 100644
index 0000000..c153c74
--- /dev/null
+++ b/src/args.ts
@@ -0,0 +1,9 @@
+const argv = require('minimist')(process.argv.slice(2));
+
+export type Args = {
+ devMode: boolean;
+};
+
+export const args: Args = {
+ devMode: argv.dev ?? false,
+};
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..09d952b
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,34 @@
+import { args, type Args } from '@/args';
+import { join } from 'path';
+import { watch } from 'fs/promises';
+import { generateParser, GRAMMAR_FILE, GENERATED_PARSER } from '@/parser';
+import { ConsoleTracingLogger } from '@/utils';
+
+const devMode = async (logger: ConsoleTracingLogger) => {
+ logger.info('Watching for changes in parser...');
+ const watcher = watch(import.meta.dir, { recursive: true });
+ for await (const event of watcher) {
+ if (event.filename?.endsWith(GRAMMAR_FILE)) {
+ const grammarFile = join(import.meta.dir, event.filename);
+ const outputFile = join(
+ import.meta.dir,
+ event.filename.replace(GRAMMAR_FILE, GENERATED_PARSER),
+ );
+ logger.info(
+ `Generating parser at Location=(${grammarFile}) to Source=(${outputFile})...`,
+ );
+ generateParser(grammarFile, outputFile);
+ }
+ }
+};
+
+export const main = async (args: Args) => {
+ const logger = new ConsoleTracingLogger('main');
+
+ if (args.devMode) {
+ logger.info('Starting in dev mode...');
+ await devMode(logger.createChild('devMode'));
+ }
+};
+
+main(args);
diff --git a/src/parser/generate.ts b/src/parser/generate.ts
new file mode 100644
index 0000000..e173b62
--- /dev/null
+++ b/src/parser/generate.ts
@@ -0,0 +1,8 @@
+import { $ } from 'bun';
+
+export const GRAMMAR_FILE = 'grammar.peg';
+export const GENERATED_PARSER = 'parser.ts';
+
+export const generateParser = async (file: string, output: string) => {
+ await $`bun run tspeg ${file} ${output} --enable-memo`;
+};
diff --git a/src/parser/grammar.peg b/src/parser/grammar.peg
new file mode 100644
index 0000000..4bb1454
--- /dev/null
+++ b/src/parser/grammar.peg
@@ -0,0 +1,67 @@
+Program := Statement* PROGRAM_END
+
+Statement := Enum | Interface | Module | Expression
+
+Module := 'EVERYTHING' _ 'CHANGED' _ 'WHEN' _ name=PASCAL_CASE _ 'EXISTS' _ SCOPE_START _ body=ModuleBody _ SCOPE_END
+ModuleBody := Constructor? _? Declaration*
+Constructor := 'PRACTICALLY' _ 'IMPOSSIBLE' _ 'TO' _ 'HAVE' _ module=Identifier _ 'WITHOUT' _ args=ArgList _ SCOPE_START _ body=FunctionBody _ SCOPE_END
+
+Expression := FunctionCall | BinaryExpression | UnaryOperation | Literal | Declaration
+
+FunctionCall := name=Identifier _ 'OF' _ args={{Expression _? COMMA _?}* Expression}
+
+BinaryExpression := left=Expression op=BinaryOperation right=Expression
+BinaryOperation := ArithmeticOperation | ComparisonOperation | BooleanOperation
+ArithmeticOperation := '\+' | '\-' | '/' | '\%' | '\*\*' | '\*' | '>>' | '<<'
+ComparisonOperation := '<' | '>' | '<=' | '>='
+BooleanOperation := '||' | '|' | '&&' | '&'
+
+Declaration := VarDeclaration | FunctionDeclaration
+VarDeclaration := 'EXPERTS' _ 'CLAIM' _ var=CAMEL_CASE _ 'TO' _ 'BE' _ Type _ val={option=OptionMatch | 'OF' _ expr=Expression}
+OptionMatch := 'WHO' _ 'IS' _ 'DATING' _ SCOPE_START _ {some=SomeMatch _ none=NoneMatch} | {none=NoneMatch _ some=SomeMatch} _ SCOPE_END
+SomeMatch := 'Someone' LPAREN name=Identifier RPAREN _ 'SO' _ expr=Expression
+NoneMatch := 'Nobody' _ 'SO' _ expr=Expression
+
+Literal := String | Integer | Float | StructInit | Identifier
+String := '(["\'])(?:(?=(\\?))\2.)*?\1'
+Integer := '^-?0*\d+$'
+Float := '^-?\d+(\.\d+)?$'
+
+UnaryOperation := PrefixOperation Expression | Expression PostfixOperation
+PrefixOperation := '!' | '~'
+PostfixOperation := LBRACKET index=POSITIVE_INT RBRACKET
+
+StructInit := 'STUFF' _ 'MADE' _ 'OF' _ SCOPE_START _ init=Declaration* _ SCOPE_END
+
+Type := name={PASCAL_CASE} | {name=PASCAL_CASE _ generic=Generic} | {tupleType=Type _ LBRACKET _ tupleLength=POSITIVE_INT _ RBRACKET} | union={Type _ 'OR' _ Type}
+Generic := LPAREN _? generic={{Type _? COMMA _?}* Type} RPAREN
+
+FunctionDeclaration := FunctionSignature _ SCOPE_START _ body=FunctionBody _ SCOPE_END
+FunctionBody := {Expression | ReturnStatement}*
+FunctionSignature := 'DISCOVER' _ 'HOW' _ 'TO' _ name=CAMEL_CASE _ 'WITH' _ args=ArgList _ 'GIVES' _ 'YOU' _ return=Type
+ArgList := args={{type=Type name=CAMEL_CASE COMMA _?}* type=Type name=CAMEL_CASE}
+
+ReturnStatement := 'SHOCKING' _ 'DEVELOPMENT' _ Expression
+
+Interface := 'STUFF' _ 'OF' _ name=PASCAL_CASE _ 'LOOKS' _ 'LIKE' SCOPE_START methods={ FunctionSignature* }
+
+Enum := 'ONLY' _ 'OPTIONS' _ 'OF' name=PASCAL_CASE _ 'ARE' _ SCOPE_START _ options=EnumBody* _ SCOPE_END
+EnumBody := name=Identifier COMMA
+
+Identifier := '[a-zA-Z][\w\d|\.]*'
+
+SCOPE_START := 'RUMOR' _ 'HAS' _ 'IT'
+SCOPE_END := 'END' _ 'OF' _ 'STORY'
+PROGRAM_END := 'PLEASE' _ 'LIKE' _ 'AND' _ 'SUBSCRIBE'
+PASCAL_CASE := '[A-Z][\w\d]*'
+CAMEL_CASE := '[a-z][\w\d]*'
+
+LPAREN := '\('
+RPAREN := '\)'
+LBRACKET := '\['
+RBRACKET := '\]'
+COMMA := ','
+
+POSITIVE_INT := '^[1-9][0-9]*$'
+
+_ := '\s' \ No newline at end of file
diff --git a/src/parser/grammar.peg.new b/src/parser/grammar.peg.new
new file mode 100644
index 0000000..f0db122
--- /dev/null
+++ b/src/parser/grammar.peg.new
@@ -0,0 +1,67 @@
+Program = Statement* PROGRAM_END
+
+Statement = Enum / Interface / Module / Expression
+
+Module = "EVERYTHING" _ "CHANGED" _ "WHEN" _ name:PASCAL_CASE _ "EXISTS" _ SCOPE_START _ body:ModuleBody _ SCOPE_END
+ModuleBody = Constructor? _? Declaration*
+Constructor = "PRACTICALLY" _ "IMPOSSIBLE" _ "TO" _ "HAVE" _ module:Identifier _ "WITHOUT" _ args:ArgList _ SCOPE_START _ body:FunctionBody _ SCOPE_END
+
+Expression = FunctionCall / BinaryExpression / UnaryOperation / Literal / Declaration
+
+FunctionCall = name:Identifier _ "OF" _ args:(Expression _? COMMA _?)* Expression
+
+BinaryExpression = left:Expression op:BinaryOperation right:Expression
+BinaryOperation = ArithmeticOperation / ComparisonOperation / BooleanOperation
+ArithmeticOperation = "\\+" / "\\-" / "/" / "\\%" / "\\*\\*" / "\\*" / ">>" / "<<"
+ComparisonOperation = "<" / ">" / "<=" / ">="
+BooleanOperation = "\\|\\|" / "\\|" / "&&" / "&"
+
+Declaration = VarDeclaration / FunctionDeclaration
+VarDeclaration = "EXPERTS" _ "CLAIM" _ name:CAMEL_CASE _ "TO" _ "BE" _ Type _ val:(option:OptionMatch / "OF" _ expr:Expression)?
+OptionMatch = "WHO" _ "IS" _ "DATING" _ SCOPE_START _ (some:SomeMatch _ none:NoneMatch) / (none:NoneMatch _ some:SomeMatch) _ SCOPE_END
+SomeMatch = "Someone" LPAREN name:Identifier RPAREN _ "SO" _ expr:Expression
+NoneMatch = "Nobody" _ "SO" _ expr:Expression
+
+Literal = String / Integer / Float / StructInit / Identifier
+String = '(["\'])(?:(?=(\\\\?))\\2.)*?\\1'
+Integer = "^-?0*\\d+$"
+Float = "^-?\\d+(\\.\\d+)?$"
+
+UnaryOperation = PrefixOperation Expression / Expression PostfixOperation
+PrefixOperation = "!" / "~"
+PostfixOperation = LBRACKET index:POSITIVE_INT RBRACKET
+
+StructInit = "STUFF" _ "MADE" _ "OF" _ SCOPE_START _ init:Declaration* _ SCOPE_END
+
+Type = name:(PASCAL_CASE / (PASCAL_CASE _ generic:Generic) / (tupleType:Type _ LBRACKET _ tupleLength:POSITIVE_INT _ RBRACKET) / union:(Type _ "OR" _ Type))
+Generic = LPAREN _? generic:(Type _? COMMA _?)* Type RPAREN
+
+FunctionDeclaration = FunctionSignature _ SCOPE_START _ body:FunctionBody _ SCOPE_END
+FunctionBody = (Expression / ReturnStatement)*
+FunctionSignature = "DISCOVER" _ "HOW" _ "TO" _ name:CAMEL_CASE _ "WITH" _ args:ArgList _ "GIVES" _ "YOU" _ type:Type
+ArgList = args:(type:Type name:CAMEL_CASE COMMA _?)* type:Type name:CAMEL_CASE
+
+ReturnStatement = "SHOCKING" _ "DEVELOPMENT" _ Expression
+
+Interface = "STUFF" _ "OF" _ name:PASCAL_CASE _ "LOOKS" _ "LIKE" SCOPE_START methods:FunctionSignature*
+
+Enum = "ONLY" _ "OPTIONS" _ "OF" name:PASCAL_CASE _ "ARE" _ SCOPE_START _ options:EnumBody* _ SCOPE_END
+EnumBody = name:Identifier COMMA
+
+Identifier = [a-zA-Z][\w\d|.]*
+
+SCOPE_START = "RUMOR" _ "HAS" _ "IT"
+SCOPE_END = "END" _ "OF" _ "STORY"
+PROGRAM_END = "PLEASE" _ "LIKE" _ "AND" _ "SUBSCRIBE"
+PASCAL_CASE = [A-Z][\w\d]*
+CAMEL_CASE = [a-z][\w\d]*
+
+LPAREN = "("
+RPAREN = ")"
+LBRACKET = "["
+RBRACKET = "]"
+COMMA = ","
+
+POSITIVE_INT = [1-9][0-9]*
+
+_ = [\s]+ \ No newline at end of file
diff --git a/src/parser/index.ts b/src/parser/index.ts
new file mode 100644
index 0000000..b451f4f
--- /dev/null
+++ b/src/parser/index.ts
@@ -0,0 +1,2 @@
+export * from './generate';
+export * from './parser';
diff --git a/src/parser/parser.ts b/src/parser/parser.ts
new file mode 100644
index 0000000..4378b71
--- /dev/null
+++ b/src/parser/parser.ts
@@ -0,0 +1,2082 @@
+/* AutoGenerated Code, changes may be overwritten
+* INPUT GRAMMAR:
+* Program := Statement* PROGRAM_END
+* Statement := Enum | Interface | Module | Expression
+* Module := 'EVERYTHING' _ 'CHANGED' _ 'WHEN' _ name=PASCAL_CASE _ 'EXISTS' _ SCOPE_START _ body=ModuleBody _ SCOPE_END
+* ModuleBody := Constructor? _? Declaration*
+* Constructor := 'PRACTICALLY' _ 'IMPOSSIBLE' _ 'TO' _ 'HAVE' _ module=Identifier _ 'WITHOUT' _ args=ArgList _ SCOPE_START _ body=FunctionBody _ SCOPE_END
+* Expression := FunctionCall | BinaryExpression | UnaryOperation | Literal | Declaration
+* FunctionCall := name=Identifier _ 'OF' _ args={{Expression _? COMMA _?}* Expression}
+* BinaryExpression := left=Expression op=BinaryOperation right=Expression
+* BinaryOperation := ArithmeticOperation | ComparisonOperation | BooleanOperation
+* ArithmeticOperation := '\+' | '\-' | '/' | '\%' | '\*\*' | '\*' | '>>' | '<<'
+* ComparisonOperation := '<' | '>' | '<=' | '>='
+* BooleanOperation := '||' | '|' | '&&' | '&'
+* Declaration := VarDeclaration | FunctionDeclaration
+* VarDeclaration := 'EXPERTS' _ 'CLAIM' _ var=CAMEL_CASE _ 'TO' _ 'BE' _ Type _ val={option=OptionMatch | 'OF' _ expr=Expression}
+* OptionMatch := 'WHO' _ 'IS' _ 'DATING' _ SCOPE_START _ {some=SomeMatch _ none=NoneMatch} | {none=NoneMatch _ some=SomeMatch} _ SCOPE_END
+* SomeMatch := 'Someone' LPAREN name=Identifier RPAREN _ 'SO' _ expr=Expression
+* NoneMatch := 'Nobody' _ 'SO' _ expr=Expression
+* Literal := String | Integer | Float | StructInit | Identifier
+* String := '(["\'])(?:(?=(\\?))\2.)*?\1'
+* Integer := '^-?0*\d+$'
+* Float := '^-?\d+(\.\d+)?$'
+* UnaryOperation := PrefixOperation Expression | Expression PostfixOperation
+* PrefixOperation := '!' | '~'
+* PostfixOperation := LBRACKET index=POSITIVE_INT RBRACKET
+* StructInit := 'STUFF' _ 'MADE' _ 'OF' _ SCOPE_START _ init=Declaration* _ SCOPE_END
+* Type := name={PASCAL_CASE} | {name=PASCAL_CASE _ generic=Generic} | {tupleType=Type _ LBRACKET _ tupleLength=POSITIVE_INT _ RBRACKET} | union={Type _ 'OR' _ Type}
+* Generic := LPAREN _? generic={{Type _? COMMA _?}* Type} RPAREN
+* FunctionDeclaration := FunctionSignature _ SCOPE_START _ body=FunctionBody _ SCOPE_END
+* FunctionBody := {Expression | ReturnStatement}*
+* FunctionSignature := 'DISCOVER' _ 'HOW' _ 'TO' _ name=CAMEL_CASE _ 'WITH' _ args=ArgList _ 'GIVES' _ 'YOU' _ return=Type
+* ArgList := args={{type=Type name=CAMEL_CASE COMMA _?}* type=Type name=CAMEL_CASE}
+* ReturnStatement := 'SHOCKING' _ 'DEVELOPMENT' _ Expression
+* Interface := 'STUFF' _ 'OF' _ name=PASCAL_CASE _ 'LOOKS' _ 'LIKE' SCOPE_START methods={ FunctionSignature* }
+* Enum := 'ONLY' _ 'OPTIONS' _ 'OF' name=PASCAL_CASE _ 'ARE' _ SCOPE_START _ options=EnumBody* _ SCOPE_END
+* EnumBody := name=Identifier COMMA
+* Identifier := '[a-zA-Z][\w\d|\.]*'
+* SCOPE_START := 'RUMOR' _ 'HAS' _ 'IT'
+* SCOPE_END := 'END' _ 'OF' _ 'STORY'
+* PROGRAM_END := 'PLEASE' _ 'LIKE' _ 'AND' _ 'SUBSCRIBE'
+* PASCAL_CASE := '[A-Z][\w\d]*'
+* CAMEL_CASE := '[a-z][\w\d]*'
+* LPAREN := '\('
+* RPAREN := '\)'
+* LBRACKET := '\['
+* RBRACKET := '\]'
+* COMMA := ','
+* POSITIVE_INT := '^[1-9][0-9]*$'
+* _ := '\s'
+*/
+type Nullable<T> = T | null;
+type $$RuleType<T> = () => Nullable<T>;
+export interface ASTNodeIntf {
+ kind: ASTKinds;
+}
+export enum ASTKinds {
+ Program = "Program",
+ Statement_1 = "Statement_1",
+ Statement_2 = "Statement_2",
+ Statement_3 = "Statement_3",
+ Statement_4 = "Statement_4",
+ Module = "Module",
+ ModuleBody = "ModuleBody",
+ Constructor = "Constructor",
+ Expression_1 = "Expression_1",
+ Expression_2 = "Expression_2",
+ Expression_3 = "Expression_3",
+ Expression_4 = "Expression_4",
+ Expression_5 = "Expression_5",
+ FunctionCall = "FunctionCall",
+ FunctionCall_$0 = "FunctionCall_$0",
+ FunctionCall_$0_$0 = "FunctionCall_$0_$0",
+ BinaryExpression = "BinaryExpression",
+ BinaryOperation_1 = "BinaryOperation_1",
+ BinaryOperation_2 = "BinaryOperation_2",
+ BinaryOperation_3 = "BinaryOperation_3",
+ ArithmeticOperation_1 = "ArithmeticOperation_1",
+ ArithmeticOperation_2 = "ArithmeticOperation_2",
+ ArithmeticOperation_3 = "ArithmeticOperation_3",
+ ArithmeticOperation_4 = "ArithmeticOperation_4",
+ ArithmeticOperation_5 = "ArithmeticOperation_5",
+ ArithmeticOperation_6 = "ArithmeticOperation_6",
+ ArithmeticOperation_7 = "ArithmeticOperation_7",
+ ArithmeticOperation_8 = "ArithmeticOperation_8",
+ ComparisonOperation_1 = "ComparisonOperation_1",
+ ComparisonOperation_2 = "ComparisonOperation_2",
+ ComparisonOperation_3 = "ComparisonOperation_3",
+ ComparisonOperation_4 = "ComparisonOperation_4",
+ BooleanOperation_1 = "BooleanOperation_1",
+ BooleanOperation_2 = "BooleanOperation_2",
+ BooleanOperation_3 = "BooleanOperation_3",
+ BooleanOperation_4 = "BooleanOperation_4",
+ Declaration_1 = "Declaration_1",
+ Declaration_2 = "Declaration_2",
+ VarDeclaration = "VarDeclaration",
+ VarDeclaration_$0_1 = "VarDeclaration_$0_1",
+ VarDeclaration_$0_2 = "VarDeclaration_$0_2",
+ OptionMatch_1 = "OptionMatch_1",
+ OptionMatch_2 = "OptionMatch_2",
+ OptionMatch_$0 = "OptionMatch_$0",
+ OptionMatch_$1 = "OptionMatch_$1",
+ SomeMatch = "SomeMatch",
+ NoneMatch = "NoneMatch",
+ Literal_1 = "Literal_1",
+ Literal_2 = "Literal_2",
+ Literal_3 = "Literal_3",
+ Literal_4 = "Literal_4",
+ Literal_5 = "Literal_5",
+ String = "String",
+ Integer = "Integer",
+ Float = "Float",
+ UnaryOperation_1 = "UnaryOperation_1",
+ UnaryOperation_2 = "UnaryOperation_2",
+ PrefixOperation_1 = "PrefixOperation_1",
+ PrefixOperation_2 = "PrefixOperation_2",
+ PostfixOperation = "PostfixOperation",
+ StructInit = "StructInit",
+ Type_1 = "Type_1",
+ Type_2 = "Type_2",
+ Type_3 = "Type_3",
+ Type_4 = "Type_4",
+ Type_$0 = "Type_$0",
+ Type_$1 = "Type_$1",
+ Type_$2 = "Type_$2",
+ Type_$3 = "Type_$3",
+ Generic = "Generic",
+ Generic_$0 = "Generic_$0",
+ Generic_$0_$0 = "Generic_$0_$0",
+ FunctionDeclaration = "FunctionDeclaration",
+ FunctionBody = "FunctionBody",
+ FunctionBody_$0_1 = "FunctionBody_$0_1",
+ FunctionBody_$0_2 = "FunctionBody_$0_2",
+ FunctionSignature = "FunctionSignature",
+ ArgList = "ArgList",
+ ArgList_$0 = "ArgList_$0",
+ ArgList_$0_$0 = "ArgList_$0_$0",
+ ReturnStatement = "ReturnStatement",
+ Interface = "Interface",
+ Interface_$0 = "Interface_$0",
+ Enum = "Enum",
+ EnumBody = "EnumBody",
+ Identifier = "Identifier",
+ SCOPE_START = "SCOPE_START",
+ SCOPE_END = "SCOPE_END",
+ PROGRAM_END = "PROGRAM_END",
+ PASCAL_CASE = "PASCAL_CASE",
+ CAMEL_CASE = "CAMEL_CASE",
+ LPAREN = "LPAREN",
+ RPAREN = "RPAREN",
+ LBRACKET = "LBRACKET",
+ RBRACKET = "RBRACKET",
+ COMMA = "COMMA",
+ POSITIVE_INT = "POSITIVE_INT",
+ _ = "_",
+}
+export interface Program {
+ kind: ASTKinds.Program;
+}
+export type Statement = Statement_1 | Statement_2 | Statement_3 | Statement_4;
+export type Statement_1 = Enum;
+export type Statement_2 = Interface;
+export type Statement_3 = Module;
+export type Statement_4 = Expression;
+export interface Module {
+ kind: ASTKinds.Module;
+ name: PASCAL_CASE;
+ body: ModuleBody;
+}
+export interface ModuleBody {
+ kind: ASTKinds.ModuleBody;
+}
+export interface Constructor {
+ kind: ASTKinds.Constructor;
+ module: Identifier;
+ args: ArgList;
+ body: FunctionBody;
+}
+export type Expression = Expression_1 | Expression_2 | Expression_3 | Expression_4 | Expression_5;
+export type Expression_1 = FunctionCall;
+export type Expression_2 = BinaryExpression;
+export type Expression_3 = UnaryOperation;
+export type Expression_4 = Literal;
+export type Expression_5 = Declaration;
+export interface FunctionCall {
+ kind: ASTKinds.FunctionCall;
+ name: Identifier;
+ args: FunctionCall_$0;
+}
+export interface FunctionCall_$0 {
+ kind: ASTKinds.FunctionCall_$0;
+}
+export interface FunctionCall_$0_$0 {
+ kind: ASTKinds.FunctionCall_$0_$0;
+}
+export interface BinaryExpression {
+ kind: ASTKinds.BinaryExpression;
+ left: Expression;
+ op: BinaryOperation;
+ right: Expression;
+}
+export type BinaryOperation = BinaryOperation_1 | BinaryOperation_2 | BinaryOperation_3;
+export type BinaryOperation_1 = ArithmeticOperation;
+export type BinaryOperation_2 = ComparisonOperation;
+export type BinaryOperation_3 = BooleanOperation;
+export type ArithmeticOperation = ArithmeticOperation_1 | ArithmeticOperation_2 | ArithmeticOperation_3 | ArithmeticOperation_4 | ArithmeticOperation_5 | ArithmeticOperation_6 | ArithmeticOperation_7 | ArithmeticOperation_8;
+export type ArithmeticOperation_1 = string;
+export type ArithmeticOperation_2 = string;
+export type ArithmeticOperation_3 = string;
+export type ArithmeticOperation_4 = string;
+export type ArithmeticOperation_5 = string;
+export type ArithmeticOperation_6 = string;
+export type ArithmeticOperation_7 = string;
+export type ArithmeticOperation_8 = string;
+export type ComparisonOperation = ComparisonOperation_1 | ComparisonOperation_2 | ComparisonOperation_3 | ComparisonOperation_4;
+export type ComparisonOperation_1 = string;
+export type ComparisonOperation_2 = string;
+export type ComparisonOperation_3 = string;
+export type ComparisonOperation_4 = string;
+export type BooleanOperation = BooleanOperation_1 | BooleanOperation_2 | BooleanOperation_3 | BooleanOperation_4;
+export type BooleanOperation_1 = string;
+export type BooleanOperation_2 = string;
+export type BooleanOperation_3 = string;
+export type BooleanOperation_4 = string;
+export type Declaration = Declaration_1 | Declaration_2;
+export type Declaration_1 = VarDeclaration;
+export type Declaration_2 = FunctionDeclaration;
+export interface VarDeclaration {
+ kind: ASTKinds.VarDeclaration;
+ var: CAMEL_CASE;
+ val: VarDeclaration_$0;
+}
+export type VarDeclaration_$0 = VarDeclaration_$0_1 | VarDeclaration_$0_2;
+export interface VarDeclaration_$0_1 {
+ kind: ASTKinds.VarDeclaration_$0_1;
+ option: OptionMatch;
+}
+export interface VarDeclaration_$0_2 {
+ kind: ASTKinds.VarDeclaration_$0_2;
+ expr: Expression;
+}
+export type OptionMatch = OptionMatch_1 | OptionMatch_2;
+export interface OptionMatch_1 {
+ kind: ASTKinds.OptionMatch_1;
+}
+export interface OptionMatch_2 {
+ kind: ASTKinds.OptionMatch_2;
+}
+export interface OptionMatch_$0 {
+ kind: ASTKinds.OptionMatch_$0;
+ some: SomeMatch;
+ none: NoneMatch;
+}
+export interface OptionMatch_$1 {
+ kind: ASTKinds.OptionMatch_$1;
+ none: NoneMatch;
+ some: SomeMatch;
+}
+export interface SomeMatch {
+ kind: ASTKinds.SomeMatch;
+ name: Identifier;
+ expr: Expression;
+}
+export interface NoneMatch {
+ kind: ASTKinds.NoneMatch;
+ expr: Expression;
+}
+export type Literal = Literal_1 | Literal_2 | Literal_3 | Literal_4 | Literal_5;
+export type Literal_1 = String;
+export type Literal_2 = Integer;
+export type Literal_3 = Float;
+export type Literal_4 = StructInit;
+export type Literal_5 = Identifier;
+export type String = string;
+export type Integer = string;
+export type Float = string;
+export type UnaryOperation = UnaryOperation_1 | UnaryOperation_2;
+export interface UnaryOperation_1 {
+ kind: ASTKinds.UnaryOperation_1;
+}
+export interface UnaryOperation_2 {
+ kind: ASTKinds.UnaryOperation_2;
+}
+export type PrefixOperation = PrefixOperation_1 | PrefixOperation_2;
+export type PrefixOperation_1 = string;
+export type PrefixOperation_2 = string;
+export interface PostfixOperation {
+ kind: ASTKinds.PostfixOperation;
+ index: POSITIVE_INT;
+}
+export interface StructInit {
+ kind: ASTKinds.StructInit;
+ init: Declaration[];
+}
+export type Type = Type_1 | Type_2 | Type_3 | Type_4;
+export interface Type_1 {
+ kind: ASTKinds.Type_1;
+ name: Type_$0;
+}
+export type Type_2 = Type_$1;
+export type Type_3 = Type_$2;
+export interface Type_4 {
+ kind: ASTKinds.Type_4;
+ union: Type_$3;
+}
+export type Type_$0 = PASCAL_CASE;
+export interface Type_$1 {
+ kind: ASTKinds.Type_$1;
+ name: PASCAL_CASE;
+ generic: Generic;
+}
+export interface Type_$2 {
+ kind: ASTKinds.Type_$2;
+ tupleType: Type;
+ tupleLength: POSITIVE_INT;
+}
+export interface Type_$3 {
+ kind: ASTKinds.Type_$3;
+}
+export interface Generic {
+ kind: ASTKinds.Generic;
+ generic: Generic_$0;
+}
+export interface Generic_$0 {
+ kind: ASTKinds.Generic_$0;
+}
+export interface Generic_$0_$0 {
+ kind: ASTKinds.Generic_$0_$0;
+}
+export interface FunctionDeclaration {
+ kind: ASTKinds.FunctionDeclaration;
+ body: FunctionBody;
+}
+export type FunctionBody = FunctionBody_$0[];
+export type FunctionBody_$0 = FunctionBody_$0_1 | FunctionBody_$0_2;
+export type FunctionBody_$0_1 = Expression;
+export type FunctionBody_$0_2 = ReturnStatement;
+export interface FunctionSignature {
+ kind: ASTKinds.FunctionSignature;
+ name: CAMEL_CASE;
+ args: ArgList;
+ return: Type;
+}
+export interface ArgList {
+ kind: ASTKinds.ArgList;
+ args: ArgList_$0;
+}
+export interface ArgList_$0 {
+ kind: ASTKinds.ArgList_$0;
+ type: Type;
+ name: CAMEL_CASE;
+}
+export interface ArgList_$0_$0 {
+ kind: ASTKinds.ArgList_$0_$0;
+ type: Type;
+ name: CAMEL_CASE;
+}
+export interface ReturnStatement {
+ kind: ASTKinds.ReturnStatement;
+}
+export interface Interface {
+ kind: ASTKinds.Interface;
+ name: PASCAL_CASE;
+ methods: Interface_$0;
+}
+export type Interface_$0 = FunctionSignature[];
+export interface Enum {
+ kind: ASTKinds.Enum;
+ name: PASCAL_CASE;
+ options: EnumBody[];
+}
+export interface EnumBody {
+ kind: ASTKinds.EnumBody;
+ name: Identifier;
+}
+export type Identifier = string;
+export interface SCOPE_START {
+ kind: ASTKinds.SCOPE_START;
+}
+export interface SCOPE_END {
+ kind: ASTKinds.SCOPE_END;
+}
+export interface PROGRAM_END {
+ kind: ASTKinds.PROGRAM_END;
+}
+export type PASCAL_CASE = string;
+export type CAMEL_CASE = string;
+export type LPAREN = string;
+export type RPAREN = string;
+export type LBRACKET = string;
+export type RBRACKET = string;
+export type COMMA = string;
+export type POSITIVE_INT = string;
+export type _ = string;
+export class Parser {
+ private readonly input: string;
+ private pos: PosInfo;
+ private negating: boolean = false;
+ private memoSafe: boolean = true;
+ constructor(input: string) {
+ this.pos = {overallPos: 0, line: 1, offset: 0};
+ this.input = input;
+ }
+ public reset(pos: PosInfo) {
+ this.pos = pos;
+ }
+ public finished(): boolean {
+ return this.pos.overallPos === this.input.length;
+ }
+ public clearMemos(): void {
+ this.$scope$Program$memo.clear();
+ this.$scope$Statement$memo.clear();
+ this.$scope$Module$memo.clear();
+ this.$scope$ModuleBody$memo.clear();
+ this.$scope$Constructor$memo.clear();
+ this.$scope$Expression$memo.clear();
+ this.$scope$FunctionCall$memo.clear();
+ this.$scope$FunctionCall_$0$memo.clear();
+ this.$scope$FunctionCall_$0_$0$memo.clear();
+ this.$scope$BinaryExpression$memo.clear();
+ this.$scope$BinaryOperation$memo.clear();
+ this.$scope$ArithmeticOperation$memo.clear();
+ this.$scope$ComparisonOperation$memo.clear();
+ this.$scope$BooleanOperation$memo.clear();
+ this.$scope$Declaration$memo.clear();
+ this.$scope$VarDeclaration$memo.clear();
+ this.$scope$VarDeclaration_$0$memo.clear();
+ this.$scope$OptionMatch$memo.clear();
+ this.$scope$OptionMatch_$0$memo.clear();
+ this.$scope$OptionMatch_$1$memo.clear();
+ this.$scope$SomeMatch$memo.clear();
+ this.$scope$NoneMatch$memo.clear();
+ this.$scope$Literal$memo.clear();
+ this.$scope$String$memo.clear();
+ this.$scope$Integer$memo.clear();
+ this.$scope$Float$memo.clear();
+ this.$scope$UnaryOperation$memo.clear();
+ this.$scope$PrefixOperation$memo.clear();
+ this.$scope$PostfixOperation$memo.clear();
+ this.$scope$StructInit$memo.clear();
+ this.$scope$Type$memo.clear();
+ this.$scope$Type_$0$memo.clear();
+ this.$scope$Type_$1$memo.clear();
+ this.$scope$Type_$2$memo.clear();
+ this.$scope$Type_$3$memo.clear();
+ this.$scope$Generic$memo.clear();
+ this.$scope$Generic_$0$memo.clear();
+ this.$scope$Generic_$0_$0$memo.clear();
+ this.$scope$FunctionDeclaration$memo.clear();
+ this.$scope$FunctionBody$memo.clear();
+ this.$scope$FunctionBody_$0$memo.clear();
+ this.$scope$FunctionSignature$memo.clear();
+ this.$scope$ArgList$memo.clear();
+ this.$scope$ArgList_$0$memo.clear();
+ this.$scope$ArgList_$0_$0$memo.clear();
+ this.$scope$ReturnStatement$memo.clear();
+ this.$scope$Interface$memo.clear();
+ this.$scope$Interface_$0$memo.clear();
+ this.$scope$Enum$memo.clear();
+ this.$scope$EnumBody$memo.clear();
+ this.$scope$Identifier$memo.clear();
+ this.$scope$SCOPE_START$memo.clear();
+ this.$scope$SCOPE_END$memo.clear();
+ this.$scope$PROGRAM_END$memo.clear();
+ this.$scope$PASCAL_CASE$memo.clear();
+ this.$scope$CAMEL_CASE$memo.clear();
+ this.$scope$LPAREN$memo.clear();
+ this.$scope$RPAREN$memo.clear();
+ this.$scope$LBRACKET$memo.clear();
+ this.$scope$RBRACKET$memo.clear();
+ this.$scope$COMMA$memo.clear();
+ this.$scope$POSITIVE_INT$memo.clear();
+ this.$scope$_$memo.clear();
+ }
+ protected $scope$Program$memo: Map<number, [Nullable<Program>, PosInfo]> = new Map();
+ protected $scope$Statement$memo: Map<number, [Nullable<Statement>, PosInfo]> = new Map();
+ protected $scope$Module$memo: Map<number, [Nullable<Module>, PosInfo]> = new Map();
+ protected $scope$ModuleBody$memo: Map<number, [Nullable<ModuleBody>, PosInfo]> = new Map();
+ protected $scope$Constructor$memo: Map<number, [Nullable<Constructor>, PosInfo]> = new Map();
+ protected $scope$Expression$memo: Map<number, [Nullable<Expression>, PosInfo]> = new Map();
+ protected $scope$FunctionCall$memo: Map<number, [Nullable<FunctionCall>, PosInfo]> = new Map();
+ protected $scope$FunctionCall_$0$memo: Map<number, [Nullable<FunctionCall_$0>, PosInfo]> = new Map();
+ protected $scope$FunctionCall_$0_$0$memo: Map<number, [Nullable<FunctionCall_$0_$0>, PosInfo]> = new Map();
+ protected $scope$BinaryExpression$memo: Map<number, [Nullable<BinaryExpression>, PosInfo]> = new Map();
+ protected $scope$BinaryOperation$memo: Map<number, [Nullable<BinaryOperation>, PosInfo]> = new Map();
+ protected $scope$ArithmeticOperation$memo: Map<number, [Nullable<ArithmeticOperation>, PosInfo]> = new Map();
+ protected $scope$ComparisonOperation$memo: Map<number, [Nullable<ComparisonOperation>, PosInfo]> = new Map();
+ protected $scope$BooleanOperation$memo: Map<number, [Nullable<BooleanOperation>, PosInfo]> = new Map();
+ protected $scope$Declaration$memo: Map<number, [Nullable<Declaration>, PosInfo]> = new Map();
+ protected $scope$VarDeclaration$memo: Map<number, [Nullable<VarDeclaration>, PosInfo]> = new Map();
+ protected $scope$VarDeclaration_$0$memo: Map<number, [Nullable<VarDeclaration_$0>, PosInfo]> = new Map();
+ protected $scope$OptionMatch$memo: Map<number, [Nullable<OptionMatch>, PosInfo]> = new Map();
+ protected $scope$OptionMatch_$0$memo: Map<number, [Nullable<OptionMatch_$0>, PosInfo]> = new Map();
+ protected $scope$OptionMatch_$1$memo: Map<number, [Nullable<OptionMatch_$1>, PosInfo]> = new Map();
+ protected $scope$SomeMatch$memo: Map<number, [Nullable<SomeMatch>, PosInfo]> = new Map();
+ protected $scope$NoneMatch$memo: Map<number, [Nullable<NoneMatch>, PosInfo]> = new Map();
+ protected $scope$Literal$memo: Map<number, [Nullable<Literal>, PosInfo]> = new Map();
+ protected $scope$String$memo: Map<number, [Nullable<String>, PosInfo]> = new Map();
+ protected $scope$Integer$memo: Map<number, [Nullable<Integer>, PosInfo]> = new Map();
+ protected $scope$Float$memo: Map<number, [Nullable<Float>, PosInfo]> = new Map();
+ protected $scope$UnaryOperation$memo: Map<number, [Nullable<UnaryOperation>, PosInfo]> = new Map();
+ protected $scope$PrefixOperation$memo: Map<number, [Nullable<PrefixOperation>, PosInfo]> = new Map();
+ protected $scope$PostfixOperation$memo: Map<number, [Nullable<PostfixOperation>, PosInfo]> = new Map();
+ protected $scope$StructInit$memo: Map<number, [Nullable<StructInit>, PosInfo]> = new Map();
+ protected $scope$Type$memo: Map<number, [Nullable<Type>, PosInfo]> = new Map();
+ protected $scope$Type_$0$memo: Map<number, [Nullable<Type_$0>, PosInfo]> = new Map();
+ protected $scope$Type_$1$memo: Map<number, [Nullable<Type_$1>, PosInfo]> = new Map();
+ protected $scope$Type_$2$memo: Map<number, [Nullable<Type_$2>, PosInfo]> = new Map();
+ protected $scope$Type_$3$memo: Map<number, [Nullable<Type_$3>, PosInfo]> = new Map();
+ protected $scope$Generic$memo: Map<number, [Nullable<Generic>, PosInfo]> = new Map();
+ protected $scope$Generic_$0$memo: Map<number, [Nullable<Generic_$0>, PosInfo]> = new Map();
+ protected $scope$Generic_$0_$0$memo: Map<number, [Nullable<Generic_$0_$0>, PosInfo]> = new Map();
+ protected $scope$FunctionDeclaration$memo: Map<number, [Nullable<FunctionDeclaration>, PosInfo]> = new Map();
+ protected $scope$FunctionBody$memo: Map<number, [Nullable<FunctionBody>, PosInfo]> = new Map();
+ protected $scope$FunctionBody_$0$memo: Map<number, [Nullable<FunctionBody_$0>, PosInfo]> = new Map();
+ protected $scope$FunctionSignature$memo: Map<number, [Nullable<FunctionSignature>, PosInfo]> = new Map();
+ protected $scope$ArgList$memo: Map<number, [Nullable<ArgList>, PosInfo]> = new Map();
+ protected $scope$ArgList_$0$memo: Map<number, [Nullable<ArgList_$0>, PosInfo]> = new Map();
+ protected $scope$ArgList_$0_$0$memo: Map<number, [Nullable<ArgList_$0_$0>, PosInfo]> = new Map();
+ protected $scope$ReturnStatement$memo: Map<number, [Nullable<ReturnStatement>, PosInfo]> = new Map();
+ protected $scope$Interface$memo: Map<number, [Nullable<Interface>, PosInfo]> = new Map();
+ protected $scope$Interface_$0$memo: Map<number, [Nullable<Interface_$0>, PosInfo]> = new Map();
+ protected $scope$Enum$memo: Map<number, [Nullable<Enum>, PosInfo]> = new Map();
+ protected $scope$EnumBody$memo: Map<number, [Nullable<EnumBody>, PosInfo]> = new Map();
+ protected $scope$Identifier$memo: Map<number, [Nullable<Identifier>, PosInfo]> = new Map();
+ protected $scope$SCOPE_START$memo: Map<number, [Nullable<SCOPE_START>, PosInfo]> = new Map();
+ protected $scope$SCOPE_END$memo: Map<number, [Nullable<SCOPE_END>, PosInfo]> = new Map();
+ protected $scope$PROGRAM_END$memo: Map<number, [Nullable<PROGRAM_END>, PosInfo]> = new Map();
+ protected $scope$PASCAL_CASE$memo: Map<number, [Nullable<PASCAL_CASE>, PosInfo]> = new Map();
+ protected $scope$CAMEL_CASE$memo: Map<number, [Nullable<CAMEL_CASE>, PosInfo]> = new Map();
+ protected $scope$LPAREN$memo: Map<number, [Nullable<LPAREN>, PosInfo]> = new Map();
+ protected $scope$RPAREN$memo: Map<number, [Nullable<RPAREN>, PosInfo]> = new Map();
+ protected $scope$LBRACKET$memo: Map<number, [Nullable<LBRACKET>, PosInfo]> = new Map();
+ protected $scope$RBRACKET$memo: Map<number, [Nullable<RBRACKET>, PosInfo]> = new Map();
+ protected $scope$COMMA$memo: Map<number, [Nullable<COMMA>, PosInfo]> = new Map();
+ protected $scope$POSITIVE_INT$memo: Map<number, [Nullable<POSITIVE_INT>, PosInfo]> = new Map();
+ protected $scope$_$memo: Map<number, [Nullable<_>, PosInfo]> = new Map();
+ public matchProgram($$dpth: number, $$cr?: ErrorTracker): Nullable<Program> {
+ return this.memoise(
+ () => {
+ return this.run<Program>($$dpth,
+ () => {
+ let $$res: Nullable<Program> = null;
+ if (true
+ && this.loop<Statement>(() => this.matchStatement($$dpth + 1, $$cr), 0, -1) !== null
+ && this.matchPROGRAM_END($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.Program, };
+ }
+ return $$res;
+ });
+ },
+ this.$scope$Program$memo,
+ );
+ }
+ public matchStatement($$dpth: number, $$cr?: ErrorTracker): Nullable<Statement> {
+ return this.memoise(
+ () => {
+ return this.choice<Statement>([
+ () => this.matchStatement_1($$dpth + 1, $$cr),
+ () => this.matchStatement_2($$dpth + 1, $$cr),
+ () => this.matchStatement_3($$dpth + 1, $$cr),
+ () => this.matchStatement_4($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$Statement$memo,
+ );
+ }
+ public matchStatement_1($$dpth: number, $$cr?: ErrorTracker): Nullable<Statement_1> {
+ return this.matchEnum($$dpth + 1, $$cr);
+ }
+ public matchStatement_2($$dpth: number, $$cr?: ErrorTracker): Nullable<Statement_2> {
+ return this.matchInterface($$dpth + 1, $$cr);
+ }
+ public matchStatement_3($$dpth: number, $$cr?: ErrorTracker): Nullable<Statement_3> {
+ return this.matchModule($$dpth + 1, $$cr);
+ }
+ public matchStatement_4($$dpth: number, $$cr?: ErrorTracker): Nullable<Statement_4> {
+ return this.matchExpression($$dpth + 1, $$cr);
+ }
+ public matchModule($$dpth: number, $$cr?: ErrorTracker): Nullable<Module> {
+ return this.memoise(
+ () => {
+ return this.run<Module>($$dpth,
+ () => {
+ let $scope$name: Nullable<PASCAL_CASE>;
+ let $scope$body: Nullable<ModuleBody>;
+ let $$res: Nullable<Module> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:EVERYTHING)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:CHANGED)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:WHEN)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$name = this.matchPASCAL_CASE($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:EXISTS)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_START($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$body = this.matchModuleBody($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_END($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.Module, name: $scope$name, body: $scope$body};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$Module$memo,
+ );
+ }
+ public matchModuleBody($$dpth: number, $$cr?: ErrorTracker): Nullable<ModuleBody> {
+ return this.memoise(
+ () => {
+ return this.run<ModuleBody>($$dpth,
+ () => {
+ let $$res: Nullable<ModuleBody> = null;
+ if (true
+ && ((this.matchConstructor($$dpth + 1, $$cr)) || true)
+ && ((this.match_($$dpth + 1, $$cr)) || true)
+ && this.loop<Declaration>(() => this.matchDeclaration($$dpth + 1, $$cr), 0, -1) !== null
+ ) {
+ $$res = {kind: ASTKinds.ModuleBody, };
+ }
+ return $$res;
+ });
+ },
+ this.$scope$ModuleBody$memo,
+ );
+ }
+ public matchConstructor($$dpth: number, $$cr?: ErrorTracker): Nullable<Constructor> {
+ return this.memoise(
+ () => {
+ return this.run<Constructor>($$dpth,
+ () => {
+ let $scope$module: Nullable<Identifier>;
+ let $scope$args: Nullable<ArgList>;
+ let $scope$body: Nullable<FunctionBody>;
+ let $$res: Nullable<Constructor> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:PRACTICALLY)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:IMPOSSIBLE)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:TO)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:HAVE)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$module = this.matchIdentifier($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:WITHOUT)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$args = this.matchArgList($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_START($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$body = this.matchFunctionBody($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_END($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.Constructor, module: $scope$module, args: $scope$args, body: $scope$body};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$Constructor$memo,
+ );
+ }
+ public matchExpression($$dpth: number, $$cr?: ErrorTracker): Nullable<Expression> {
+ const fn = () => {
+ return this.choice<Expression>([
+ () => this.matchExpression_1($$dpth + 1, $$cr),
+ () => this.matchExpression_2($$dpth + 1, $$cr),
+ () => this.matchExpression_3($$dpth + 1, $$cr),
+ () => this.matchExpression_4($$dpth + 1, $$cr),
+ () => this.matchExpression_5($$dpth + 1, $$cr),
+ ]);
+ };
+ const $scope$pos = this.mark();
+ const memo = this.$scope$Expression$memo.get($scope$pos.overallPos);
+ if(memo !== undefined) {
+ this.reset(memo[1]);
+ return memo[0];
+ }
+ const $scope$oldMemoSafe = this.memoSafe;
+ this.memoSafe = false;
+ this.$scope$Expression$memo.set($scope$pos.overallPos, [null, $scope$pos]);
+ let lastRes: Nullable<Expression> = null;
+ let lastPos: PosInfo = $scope$pos;
+ for(;;) {
+ this.reset($scope$pos);
+ const res = fn();
+ const end = this.mark();
+ if(end.overallPos <= lastPos.overallPos)
+ break;
+ lastRes = res;
+ lastPos = end;
+ this.$scope$Expression$memo.set($scope$pos.overallPos, [lastRes, lastPos]);
+ }
+ this.reset(lastPos);
+ this.memoSafe = $scope$oldMemoSafe;
+ return lastRes;
+ }
+ public matchExpression_1($$dpth: number, $$cr?: ErrorTracker): Nullable<Expression_1> {
+ return this.matchFunctionCall($$dpth + 1, $$cr);
+ }
+ public matchExpression_2($$dpth: number, $$cr?: ErrorTracker): Nullable<Expression_2> {
+ return this.matchBinaryExpression($$dpth + 1, $$cr);
+ }
+ public matchExpression_3($$dpth: number, $$cr?: ErrorTracker): Nullable<Expression_3> {
+ return this.matchUnaryOperation($$dpth + 1, $$cr);
+ }
+ public matchExpression_4($$dpth: number, $$cr?: ErrorTracker): Nullable<Expression_4> {
+ return this.matchLiteral($$dpth + 1, $$cr);
+ }
+ public matchExpression_5($$dpth: number, $$cr?: ErrorTracker): Nullable<Expression_5> {
+ return this.matchDeclaration($$dpth + 1, $$cr);
+ }
+ public matchFunctionCall($$dpth: number, $$cr?: ErrorTracker): Nullable<FunctionCall> {
+ return this.memoise(
+ () => {
+ return this.run<FunctionCall>($$dpth,
+ () => {
+ let $scope$name: Nullable<Identifier>;
+ let $scope$args: Nullable<FunctionCall_$0>;
+ let $$res: Nullable<FunctionCall> = null;
+ if (true
+ && ($scope$name = this.matchIdentifier($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:OF)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$args = this.matchFunctionCall_$0($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.FunctionCall, name: $scope$name, args: $scope$args};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$FunctionCall$memo,
+ );
+ }
+ public matchFunctionCall_$0($$dpth: number, $$cr?: ErrorTracker): Nullable<FunctionCall_$0> {
+ return this.memoise(
+ () => {
+ return this.run<FunctionCall_$0>($$dpth,
+ () => {
+ let $$res: Nullable<FunctionCall_$0> = null;
+ if (true
+ && this.loop<FunctionCall_$0_$0>(() => this.matchFunctionCall_$0_$0($$dpth + 1, $$cr), 0, -1) !== null
+ && this.matchExpression($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.FunctionCall_$0, };
+ }
+ return $$res;
+ });
+ },
+ this.$scope$FunctionCall_$0$memo,
+ );
+ }
+ public matchFunctionCall_$0_$0($$dpth: number, $$cr?: ErrorTracker): Nullable<FunctionCall_$0_$0> {
+ return this.memoise(
+ () => {
+ return this.run<FunctionCall_$0_$0>($$dpth,
+ () => {
+ let $$res: Nullable<FunctionCall_$0_$0> = null;
+ if (true
+ && this.matchExpression($$dpth + 1, $$cr) !== null
+ && ((this.match_($$dpth + 1, $$cr)) || true)
+ && this.matchCOMMA($$dpth + 1, $$cr) !== null
+ && ((this.match_($$dpth + 1, $$cr)) || true)
+ ) {
+ $$res = {kind: ASTKinds.FunctionCall_$0_$0, };
+ }
+ return $$res;
+ });
+ },
+ this.$scope$FunctionCall_$0_$0$memo,
+ );
+ }
+ public matchBinaryExpression($$dpth: number, $$cr?: ErrorTracker): Nullable<BinaryExpression> {
+ return this.memoise(
+ () => {
+ return this.run<BinaryExpression>($$dpth,
+ () => {
+ let $scope$left: Nullable<Expression>;
+ let $scope$op: Nullable<BinaryOperation>;
+ let $scope$right: Nullable<Expression>;
+ let $$res: Nullable<BinaryExpression> = null;
+ if (true
+ && ($scope$left = this.matchExpression($$dpth + 1, $$cr)) !== null
+ && ($scope$op = this.matchBinaryOperation($$dpth + 1, $$cr)) !== null
+ && ($scope$right = this.matchExpression($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.BinaryExpression, left: $scope$left, op: $scope$op, right: $scope$right};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$BinaryExpression$memo,
+ );
+ }
+ public matchBinaryOperation($$dpth: number, $$cr?: ErrorTracker): Nullable<BinaryOperation> {
+ return this.memoise(
+ () => {
+ return this.choice<BinaryOperation>([
+ () => this.matchBinaryOperation_1($$dpth + 1, $$cr),
+ () => this.matchBinaryOperation_2($$dpth + 1, $$cr),
+ () => this.matchBinaryOperation_3($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$BinaryOperation$memo,
+ );
+ }
+ public matchBinaryOperation_1($$dpth: number, $$cr?: ErrorTracker): Nullable<BinaryOperation_1> {
+ return this.matchArithmeticOperation($$dpth + 1, $$cr);
+ }
+ public matchBinaryOperation_2($$dpth: number, $$cr?: ErrorTracker): Nullable<BinaryOperation_2> {
+ return this.matchComparisonOperation($$dpth + 1, $$cr);
+ }
+ public matchBinaryOperation_3($$dpth: number, $$cr?: ErrorTracker): Nullable<BinaryOperation_3> {
+ return this.matchBooleanOperation($$dpth + 1, $$cr);
+ }
+ public matchArithmeticOperation($$dpth: number, $$cr?: ErrorTracker): Nullable<ArithmeticOperation> {
+ return this.memoise(
+ () => {
+ return this.choice<ArithmeticOperation>([
+ () => this.matchArithmeticOperation_1($$dpth + 1, $$cr),
+ () => this.matchArithmeticOperation_2($$dpth + 1, $$cr),
+ () => this.matchArithmeticOperation_3($$dpth + 1, $$cr),
+ () => this.matchArithmeticOperation_4($$dpth + 1, $$cr),
+ () => this.matchArithmeticOperation_5($$dpth + 1, $$cr),
+ () => this.matchArithmeticOperation_6($$dpth + 1, $$cr),
+ () => this.matchArithmeticOperation_7($$dpth + 1, $$cr),
+ () => this.matchArithmeticOperation_8($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$ArithmeticOperation$memo,
+ );
+ }
+ public matchArithmeticOperation_1($$dpth: number, $$cr?: ErrorTracker): Nullable<ArithmeticOperation_1> {
+ return this.regexAccept(String.raw`(?:\+)`, "", $$dpth + 1, $$cr);
+ }
+ public matchArithmeticOperation_2($$dpth: number, $$cr?: ErrorTracker): Nullable<ArithmeticOperation_2> {
+ return this.regexAccept(String.raw`(?:\-)`, "", $$dpth + 1, $$cr);
+ }
+ public matchArithmeticOperation_3($$dpth: number, $$cr?: ErrorTracker): Nullable<ArithmeticOperation_3> {
+ return this.regexAccept(String.raw`(?:/)`, "", $$dpth + 1, $$cr);
+ }
+ public matchArithmeticOperation_4($$dpth: number, $$cr?: ErrorTracker): Nullable<ArithmeticOperation_4> {
+ return this.regexAccept(String.raw`(?:\%)`, "", $$dpth + 1, $$cr);
+ }
+ public matchArithmeticOperation_5($$dpth: number, $$cr?: ErrorTracker): Nullable<ArithmeticOperation_5> {
+ return this.regexAccept(String.raw`(?:\*\*)`, "", $$dpth + 1, $$cr);
+ }
+ public matchArithmeticOperation_6($$dpth: number, $$cr?: ErrorTracker): Nullable<ArithmeticOperation_6> {
+ return this.regexAccept(String.raw`(?:\*)`, "", $$dpth + 1, $$cr);
+ }
+ public matchArithmeticOperation_7($$dpth: number, $$cr?: ErrorTracker): Nullable<ArithmeticOperation_7> {
+ return this.regexAccept(String.raw`(?:>>)`, "", $$dpth + 1, $$cr);
+ }
+ public matchArithmeticOperation_8($$dpth: number, $$cr?: ErrorTracker): Nullable<ArithmeticOperation_8> {
+ return this.regexAccept(String.raw`(?:<<)`, "", $$dpth + 1, $$cr);
+ }
+ public matchComparisonOperation($$dpth: number, $$cr?: ErrorTracker): Nullable<ComparisonOperation> {
+ return this.memoise(
+ () => {
+ return this.choice<ComparisonOperation>([
+ () => this.matchComparisonOperation_1($$dpth + 1, $$cr),
+ () => this.matchComparisonOperation_2($$dpth + 1, $$cr),
+ () => this.matchComparisonOperation_3($$dpth + 1, $$cr),
+ () => this.matchComparisonOperation_4($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$ComparisonOperation$memo,
+ );
+ }
+ public matchComparisonOperation_1($$dpth: number, $$cr?: ErrorTracker): Nullable<ComparisonOperation_1> {
+ return this.regexAccept(String.raw`(?:<)`, "", $$dpth + 1, $$cr);
+ }
+ public matchComparisonOperation_2($$dpth: number, $$cr?: ErrorTracker): Nullable<ComparisonOperation_2> {
+ return this.regexAccept(String.raw`(?:>)`, "", $$dpth + 1, $$cr);
+ }
+ public matchComparisonOperation_3($$dpth: number, $$cr?: ErrorTracker): Nullable<ComparisonOperation_3> {
+ return this.regexAccept(String.raw`(?:<=)`, "", $$dpth + 1, $$cr);
+ }
+ public matchComparisonOperation_4($$dpth: number, $$cr?: ErrorTracker): Nullable<ComparisonOperation_4> {
+ return this.regexAccept(String.raw`(?:>=)`, "", $$dpth + 1, $$cr);
+ }
+ public matchBooleanOperation($$dpth: number, $$cr?: ErrorTracker): Nullable<BooleanOperation> {
+ return this.memoise(
+ () => {
+ return this.choice<BooleanOperation>([
+ () => this.matchBooleanOperation_1($$dpth + 1, $$cr),
+ () => this.matchBooleanOperation_2($$dpth + 1, $$cr),
+ () => this.matchBooleanOperation_3($$dpth + 1, $$cr),
+ () => this.matchBooleanOperation_4($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$BooleanOperation$memo,
+ );
+ }
+ public matchBooleanOperation_1($$dpth: number, $$cr?: ErrorTracker): Nullable<BooleanOperation_1> {
+ return this.regexAccept(String.raw`(?:||)`, "", $$dpth + 1, $$cr);
+ }
+ public matchBooleanOperation_2($$dpth: number, $$cr?: ErrorTracker): Nullable<BooleanOperation_2> {
+ return this.regexAccept(String.raw`(?:|)`, "", $$dpth + 1, $$cr);
+ }
+ public matchBooleanOperation_3($$dpth: number, $$cr?: ErrorTracker): Nullable<BooleanOperation_3> {
+ return this.regexAccept(String.raw`(?:&&)`, "", $$dpth + 1, $$cr);
+ }
+ public matchBooleanOperation_4($$dpth: number, $$cr?: ErrorTracker): Nullable<BooleanOperation_4> {
+ return this.regexAccept(String.raw`(?:&)`, "", $$dpth + 1, $$cr);
+ }
+ public matchDeclaration($$dpth: number, $$cr?: ErrorTracker): Nullable<Declaration> {
+ return this.memoise(
+ () => {
+ return this.choice<Declaration>([
+ () => this.matchDeclaration_1($$dpth + 1, $$cr),
+ () => this.matchDeclaration_2($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$Declaration$memo,
+ );
+ }
+ public matchDeclaration_1($$dpth: number, $$cr?: ErrorTracker): Nullable<Declaration_1> {
+ return this.matchVarDeclaration($$dpth + 1, $$cr);
+ }
+ public matchDeclaration_2($$dpth: number, $$cr?: ErrorTracker): Nullable<Declaration_2> {
+ return this.matchFunctionDeclaration($$dpth + 1, $$cr);
+ }
+ public matchVarDeclaration($$dpth: number, $$cr?: ErrorTracker): Nullable<VarDeclaration> {
+ return this.memoise(
+ () => {
+ return this.run<VarDeclaration>($$dpth,
+ () => {
+ let $scope$var: Nullable<CAMEL_CASE>;
+ let $scope$val: Nullable<VarDeclaration_$0>;
+ let $$res: Nullable<VarDeclaration> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:EXPERTS)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:CLAIM)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$var = this.matchCAMEL_CASE($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:TO)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:BE)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchType($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$val = this.matchVarDeclaration_$0($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.VarDeclaration, var: $scope$var, val: $scope$val};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$VarDeclaration$memo,
+ );
+ }
+ public matchVarDeclaration_$0($$dpth: number, $$cr?: ErrorTracker): Nullable<VarDeclaration_$0> {
+ return this.memoise(
+ () => {
+ return this.choice<VarDeclaration_$0>([
+ () => this.matchVarDeclaration_$0_1($$dpth + 1, $$cr),
+ () => this.matchVarDeclaration_$0_2($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$VarDeclaration_$0$memo,
+ );
+ }
+ public matchVarDeclaration_$0_1($$dpth: number, $$cr?: ErrorTracker): Nullable<VarDeclaration_$0_1> {
+ return this.run<VarDeclaration_$0_1>($$dpth,
+ () => {
+ let $scope$option: Nullable<OptionMatch>;
+ let $$res: Nullable<VarDeclaration_$0_1> = null;
+ if (true
+ && ($scope$option = this.matchOptionMatch($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.VarDeclaration_$0_1, option: $scope$option};
+ }
+ return $$res;
+ });
+ }
+ public matchVarDeclaration_$0_2($$dpth: number, $$cr?: ErrorTracker): Nullable<VarDeclaration_$0_2> {
+ return this.run<VarDeclaration_$0_2>($$dpth,
+ () => {
+ let $scope$expr: Nullable<Expression>;
+ let $$res: Nullable<VarDeclaration_$0_2> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:OF)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$expr = this.matchExpression($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.VarDeclaration_$0_2, expr: $scope$expr};
+ }
+ return $$res;
+ });
+ }
+ public matchOptionMatch($$dpth: number, $$cr?: ErrorTracker): Nullable<OptionMatch> {
+ return this.memoise(
+ () => {
+ return this.choice<OptionMatch>([
+ () => this.matchOptionMatch_1($$dpth + 1, $$cr),
+ () => this.matchOptionMatch_2($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$OptionMatch$memo,
+ );
+ }
+ public matchOptionMatch_1($$dpth: number, $$cr?: ErrorTracker): Nullable<OptionMatch_1> {
+ return this.run<OptionMatch_1>($$dpth,
+ () => {
+ let $$res: Nullable<OptionMatch_1> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:WHO)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:IS)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:DATING)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_START($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchOptionMatch_$0($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.OptionMatch_1, };
+ }
+ return $$res;
+ });
+ }
+ public matchOptionMatch_2($$dpth: number, $$cr?: ErrorTracker): Nullable<OptionMatch_2> {
+ return this.run<OptionMatch_2>($$dpth,
+ () => {
+ let $$res: Nullable<OptionMatch_2> = null;
+ if (true
+ && this.matchOptionMatch_$1($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_END($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.OptionMatch_2, };
+ }
+ return $$res;
+ });
+ }
+ public matchOptionMatch_$0($$dpth: number, $$cr?: ErrorTracker): Nullable<OptionMatch_$0> {
+ return this.memoise(
+ () => {
+ return this.run<OptionMatch_$0>($$dpth,
+ () => {
+ let $scope$some: Nullable<SomeMatch>;
+ let $scope$none: Nullable<NoneMatch>;
+ let $$res: Nullable<OptionMatch_$0> = null;
+ if (true
+ && ($scope$some = this.matchSomeMatch($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$none = this.matchNoneMatch($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.OptionMatch_$0, some: $scope$some, none: $scope$none};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$OptionMatch_$0$memo,
+ );
+ }
+ public matchOptionMatch_$1($$dpth: number, $$cr?: ErrorTracker): Nullable<OptionMatch_$1> {
+ return this.memoise(
+ () => {
+ return this.run<OptionMatch_$1>($$dpth,
+ () => {
+ let $scope$none: Nullable<NoneMatch>;
+ let $scope$some: Nullable<SomeMatch>;
+ let $$res: Nullable<OptionMatch_$1> = null;
+ if (true
+ && ($scope$none = this.matchNoneMatch($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$some = this.matchSomeMatch($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.OptionMatch_$1, none: $scope$none, some: $scope$some};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$OptionMatch_$1$memo,
+ );
+ }
+ public matchSomeMatch($$dpth: number, $$cr?: ErrorTracker): Nullable<SomeMatch> {
+ return this.memoise(
+ () => {
+ return this.run<SomeMatch>($$dpth,
+ () => {
+ let $scope$name: Nullable<Identifier>;
+ let $scope$expr: Nullable<Expression>;
+ let $$res: Nullable<SomeMatch> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:Someone)`, "", $$dpth + 1, $$cr) !== null
+ && this.matchLPAREN($$dpth + 1, $$cr) !== null
+ && ($scope$name = this.matchIdentifier($$dpth + 1, $$cr)) !== null
+ && this.matchRPAREN($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:SO)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$expr = this.matchExpression($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.SomeMatch, name: $scope$name, expr: $scope$expr};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$SomeMatch$memo,
+ );
+ }
+ public matchNoneMatch($$dpth: number, $$cr?: ErrorTracker): Nullable<NoneMatch> {
+ return this.memoise(
+ () => {
+ return this.run<NoneMatch>($$dpth,
+ () => {
+ let $scope$expr: Nullable<Expression>;
+ let $$res: Nullable<NoneMatch> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:Nobody)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:SO)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$expr = this.matchExpression($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.NoneMatch, expr: $scope$expr};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$NoneMatch$memo,
+ );
+ }
+ public matchLiteral($$dpth: number, $$cr?: ErrorTracker): Nullable<Literal> {
+ return this.memoise(
+ () => {
+ return this.choice<Literal>([
+ () => this.matchLiteral_1($$dpth + 1, $$cr),
+ () => this.matchLiteral_2($$dpth + 1, $$cr),
+ () => this.matchLiteral_3($$dpth + 1, $$cr),
+ () => this.matchLiteral_4($$dpth + 1, $$cr),
+ () => this.matchLiteral_5($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$Literal$memo,
+ );
+ }
+ public matchLiteral_1($$dpth: number, $$cr?: ErrorTracker): Nullable<Literal_1> {
+ return this.matchString($$dpth + 1, $$cr);
+ }
+ public matchLiteral_2($$dpth: number, $$cr?: ErrorTracker): Nullable<Literal_2> {
+ return this.matchInteger($$dpth + 1, $$cr);
+ }
+ public matchLiteral_3($$dpth: number, $$cr?: ErrorTracker): Nullable<Literal_3> {
+ return this.matchFloat($$dpth + 1, $$cr);
+ }
+ public matchLiteral_4($$dpth: number, $$cr?: ErrorTracker): Nullable<Literal_4> {
+ return this.matchStructInit($$dpth + 1, $$cr);
+ }
+ public matchLiteral_5($$dpth: number, $$cr?: ErrorTracker): Nullable<Literal_5> {
+ return this.matchIdentifier($$dpth + 1, $$cr);
+ }
+ public matchString($$dpth: number, $$cr?: ErrorTracker): Nullable<String> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:(["\'])(?:(?=(\\?))\2.)*?\1)`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$String$memo,
+ );
+ }
+ public matchInteger($$dpth: number, $$cr?: ErrorTracker): Nullable<Integer> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:^-?0*\d+$)`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$Integer$memo,
+ );
+ }
+ public matchFloat($$dpth: number, $$cr?: ErrorTracker): Nullable<Float> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:^-?\d+(\.\d+)?$)`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$Float$memo,
+ );
+ }
+ public matchUnaryOperation($$dpth: number, $$cr?: ErrorTracker): Nullable<UnaryOperation> {
+ return this.memoise(
+ () => {
+ return this.choice<UnaryOperation>([
+ () => this.matchUnaryOperation_1($$dpth + 1, $$cr),
+ () => this.matchUnaryOperation_2($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$UnaryOperation$memo,
+ );
+ }
+ public matchUnaryOperation_1($$dpth: number, $$cr?: ErrorTracker): Nullable<UnaryOperation_1> {
+ return this.run<UnaryOperation_1>($$dpth,
+ () => {
+ let $$res: Nullable<UnaryOperation_1> = null;
+ if (true
+ && this.matchPrefixOperation($$dpth + 1, $$cr) !== null
+ && this.matchExpression($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.UnaryOperation_1, };
+ }
+ return $$res;
+ });
+ }
+ public matchUnaryOperation_2($$dpth: number, $$cr?: ErrorTracker): Nullable<UnaryOperation_2> {
+ return this.run<UnaryOperation_2>($$dpth,
+ () => {
+ let $$res: Nullable<UnaryOperation_2> = null;
+ if (true
+ && this.matchExpression($$dpth + 1, $$cr) !== null
+ && this.matchPostfixOperation($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.UnaryOperation_2, };
+ }
+ return $$res;
+ });
+ }
+ public matchPrefixOperation($$dpth: number, $$cr?: ErrorTracker): Nullable<PrefixOperation> {
+ return this.memoise(
+ () => {
+ return this.choice<PrefixOperation>([
+ () => this.matchPrefixOperation_1($$dpth + 1, $$cr),
+ () => this.matchPrefixOperation_2($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$PrefixOperation$memo,
+ );
+ }
+ public matchPrefixOperation_1($$dpth: number, $$cr?: ErrorTracker): Nullable<PrefixOperation_1> {
+ return this.regexAccept(String.raw`(?:!)`, "", $$dpth + 1, $$cr);
+ }
+ public matchPrefixOperation_2($$dpth: number, $$cr?: ErrorTracker): Nullable<PrefixOperation_2> {
+ return this.regexAccept(String.raw`(?:~)`, "", $$dpth + 1, $$cr);
+ }
+ public matchPostfixOperation($$dpth: number, $$cr?: ErrorTracker): Nullable<PostfixOperation> {
+ return this.memoise(
+ () => {
+ return this.run<PostfixOperation>($$dpth,
+ () => {
+ let $scope$index: Nullable<POSITIVE_INT>;
+ let $$res: Nullable<PostfixOperation> = null;
+ if (true
+ && this.matchLBRACKET($$dpth + 1, $$cr) !== null
+ && ($scope$index = this.matchPOSITIVE_INT($$dpth + 1, $$cr)) !== null
+ && this.matchRBRACKET($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.PostfixOperation, index: $scope$index};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$PostfixOperation$memo,
+ );
+ }
+ public matchStructInit($$dpth: number, $$cr?: ErrorTracker): Nullable<StructInit> {
+ return this.memoise(
+ () => {
+ return this.run<StructInit>($$dpth,
+ () => {
+ let $scope$init: Nullable<Declaration[]>;
+ let $$res: Nullable<StructInit> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:STUFF)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:MADE)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:OF)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_START($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$init = this.loop<Declaration>(() => this.matchDeclaration($$dpth + 1, $$cr), 0, -1)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_END($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.StructInit, init: $scope$init};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$StructInit$memo,
+ );
+ }
+ public matchType($$dpth: number, $$cr?: ErrorTracker): Nullable<Type> {
+ const fn = () => {
+ return this.choice<Type>([
+ () => this.matchType_1($$dpth + 1, $$cr),
+ () => this.matchType_2($$dpth + 1, $$cr),
+ () => this.matchType_3($$dpth + 1, $$cr),
+ () => this.matchType_4($$dpth + 1, $$cr),
+ ]);
+ };
+ const $scope$pos = this.mark();
+ const memo = this.$scope$Type$memo.get($scope$pos.overallPos);
+ if(memo !== undefined) {
+ this.reset(memo[1]);
+ return memo[0];
+ }
+ const $scope$oldMemoSafe = this.memoSafe;
+ this.memoSafe = false;
+ this.$scope$Type$memo.set($scope$pos.overallPos, [null, $scope$pos]);
+ let lastRes: Nullable<Type> = null;
+ let lastPos: PosInfo = $scope$pos;
+ for(;;) {
+ this.reset($scope$pos);
+ const res = fn();
+ const end = this.mark();
+ if(end.overallPos <= lastPos.overallPos)
+ break;
+ lastRes = res;
+ lastPos = end;
+ this.$scope$Type$memo.set($scope$pos.overallPos, [lastRes, lastPos]);
+ }
+ this.reset(lastPos);
+ this.memoSafe = $scope$oldMemoSafe;
+ return lastRes;
+ }
+ public matchType_1($$dpth: number, $$cr?: ErrorTracker): Nullable<Type_1> {
+ return this.run<Type_1>($$dpth,
+ () => {
+ let $scope$name: Nullable<Type_$0>;
+ let $$res: Nullable<Type_1> = null;
+ if (true
+ && ($scope$name = this.matchType_$0($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.Type_1, name: $scope$name};
+ }
+ return $$res;
+ });
+ }
+ public matchType_2($$dpth: number, $$cr?: ErrorTracker): Nullable<Type_2> {
+ return this.matchType_$1($$dpth + 1, $$cr);
+ }
+ public matchType_3($$dpth: number, $$cr?: ErrorTracker): Nullable<Type_3> {
+ return this.matchType_$2($$dpth + 1, $$cr);
+ }
+ public matchType_4($$dpth: number, $$cr?: ErrorTracker): Nullable<Type_4> {
+ return this.run<Type_4>($$dpth,
+ () => {
+ let $scope$union: Nullable<Type_$3>;
+ let $$res: Nullable<Type_4> = null;
+ if (true
+ && ($scope$union = this.matchType_$3($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.Type_4, union: $scope$union};
+ }
+ return $$res;
+ });
+ }
+ public matchType_$0($$dpth: number, $$cr?: ErrorTracker): Nullable<Type_$0> {
+ return this.memoise(
+ () => {
+ return this.matchPASCAL_CASE($$dpth + 1, $$cr);
+ },
+ this.$scope$Type_$0$memo,
+ );
+ }
+ public matchType_$1($$dpth: number, $$cr?: ErrorTracker): Nullable<Type_$1> {
+ return this.memoise(
+ () => {
+ return this.run<Type_$1>($$dpth,
+ () => {
+ let $scope$name: Nullable<PASCAL_CASE>;
+ let $scope$generic: Nullable<Generic>;
+ let $$res: Nullable<Type_$1> = null;
+ if (true
+ && ($scope$name = this.matchPASCAL_CASE($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$generic = this.matchGeneric($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.Type_$1, name: $scope$name, generic: $scope$generic};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$Type_$1$memo,
+ );
+ }
+ public matchType_$2($$dpth: number, $$cr?: ErrorTracker): Nullable<Type_$2> {
+ return this.memoise(
+ () => {
+ return this.run<Type_$2>($$dpth,
+ () => {
+ let $scope$tupleType: Nullable<Type>;
+ let $scope$tupleLength: Nullable<POSITIVE_INT>;
+ let $$res: Nullable<Type_$2> = null;
+ if (true
+ && ($scope$tupleType = this.matchType($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchLBRACKET($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$tupleLength = this.matchPOSITIVE_INT($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchRBRACKET($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.Type_$2, tupleType: $scope$tupleType, tupleLength: $scope$tupleLength};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$Type_$2$memo,
+ );
+ }
+ public matchType_$3($$dpth: number, $$cr?: ErrorTracker): Nullable<Type_$3> {
+ return this.memoise(
+ () => {
+ return this.run<Type_$3>($$dpth,
+ () => {
+ let $$res: Nullable<Type_$3> = null;
+ if (true
+ && this.matchType($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:OR)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchType($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.Type_$3, };
+ }
+ return $$res;
+ });
+ },
+ this.$scope$Type_$3$memo,
+ );
+ }
+ public matchGeneric($$dpth: number, $$cr?: ErrorTracker): Nullable<Generic> {
+ return this.memoise(
+ () => {
+ return this.run<Generic>($$dpth,
+ () => {
+ let $scope$generic: Nullable<Generic_$0>;
+ let $$res: Nullable<Generic> = null;
+ if (true
+ && this.matchLPAREN($$dpth + 1, $$cr) !== null
+ && ((this.match_($$dpth + 1, $$cr)) || true)
+ && ($scope$generic = this.matchGeneric_$0($$dpth + 1, $$cr)) !== null
+ && this.matchRPAREN($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.Generic, generic: $scope$generic};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$Generic$memo,
+ );
+ }
+ public matchGeneric_$0($$dpth: number, $$cr?: ErrorTracker): Nullable<Generic_$0> {
+ return this.memoise(
+ () => {
+ return this.run<Generic_$0>($$dpth,
+ () => {
+ let $$res: Nullable<Generic_$0> = null;
+ if (true
+ && this.loop<Generic_$0_$0>(() => this.matchGeneric_$0_$0($$dpth + 1, $$cr), 0, -1) !== null
+ && this.matchType($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.Generic_$0, };
+ }
+ return $$res;
+ });
+ },
+ this.$scope$Generic_$0$memo,
+ );
+ }
+ public matchGeneric_$0_$0($$dpth: number, $$cr?: ErrorTracker): Nullable<Generic_$0_$0> {
+ return this.memoise(
+ () => {
+ return this.run<Generic_$0_$0>($$dpth,
+ () => {
+ let $$res: Nullable<Generic_$0_$0> = null;
+ if (true
+ && this.matchType($$dpth + 1, $$cr) !== null
+ && ((this.match_($$dpth + 1, $$cr)) || true)
+ && this.matchCOMMA($$dpth + 1, $$cr) !== null
+ && ((this.match_($$dpth + 1, $$cr)) || true)
+ ) {
+ $$res = {kind: ASTKinds.Generic_$0_$0, };
+ }
+ return $$res;
+ });
+ },
+ this.$scope$Generic_$0_$0$memo,
+ );
+ }
+ public matchFunctionDeclaration($$dpth: number, $$cr?: ErrorTracker): Nullable<FunctionDeclaration> {
+ return this.memoise(
+ () => {
+ return this.run<FunctionDeclaration>($$dpth,
+ () => {
+ let $scope$body: Nullable<FunctionBody>;
+ let $$res: Nullable<FunctionDeclaration> = null;
+ if (true
+ && this.matchFunctionSignature($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_START($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$body = this.matchFunctionBody($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_END($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.FunctionDeclaration, body: $scope$body};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$FunctionDeclaration$memo,
+ );
+ }
+ public matchFunctionBody($$dpth: number, $$cr?: ErrorTracker): Nullable<FunctionBody> {
+ return this.memoise(
+ () => {
+ return this.loop<FunctionBody_$0>(() => this.matchFunctionBody_$0($$dpth + 1, $$cr), 0, -1);
+ },
+ this.$scope$FunctionBody$memo,
+ );
+ }
+ public matchFunctionBody_$0($$dpth: number, $$cr?: ErrorTracker): Nullable<FunctionBody_$0> {
+ return this.memoise(
+ () => {
+ return this.choice<FunctionBody_$0>([
+ () => this.matchFunctionBody_$0_1($$dpth + 1, $$cr),
+ () => this.matchFunctionBody_$0_2($$dpth + 1, $$cr),
+ ]);
+ },
+ this.$scope$FunctionBody_$0$memo,
+ );
+ }
+ public matchFunctionBody_$0_1($$dpth: number, $$cr?: ErrorTracker): Nullable<FunctionBody_$0_1> {
+ return this.matchExpression($$dpth + 1, $$cr);
+ }
+ public matchFunctionBody_$0_2($$dpth: number, $$cr?: ErrorTracker): Nullable<FunctionBody_$0_2> {
+ return this.matchReturnStatement($$dpth + 1, $$cr);
+ }
+ public matchFunctionSignature($$dpth: number, $$cr?: ErrorTracker): Nullable<FunctionSignature> {
+ return this.memoise(
+ () => {
+ return this.run<FunctionSignature>($$dpth,
+ () => {
+ let $scope$name: Nullable<CAMEL_CASE>;
+ let $scope$args: Nullable<ArgList>;
+ let $scope$return: Nullable<Type>;
+ let $$res: Nullable<FunctionSignature> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:DISCOVER)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:HOW)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:TO)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$name = this.matchCAMEL_CASE($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:WITH)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$args = this.matchArgList($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:GIVES)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:YOU)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$return = this.matchType($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.FunctionSignature, name: $scope$name, args: $scope$args, return: $scope$return};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$FunctionSignature$memo,
+ );
+ }
+ public matchArgList($$dpth: number, $$cr?: ErrorTracker): Nullable<ArgList> {
+ return this.memoise(
+ () => {
+ return this.run<ArgList>($$dpth,
+ () => {
+ let $scope$args: Nullable<ArgList_$0>;
+ let $$res: Nullable<ArgList> = null;
+ if (true
+ && ($scope$args = this.matchArgList_$0($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.ArgList, args: $scope$args};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$ArgList$memo,
+ );
+ }
+ public matchArgList_$0($$dpth: number, $$cr?: ErrorTracker): Nullable<ArgList_$0> {
+ return this.memoise(
+ () => {
+ return this.run<ArgList_$0>($$dpth,
+ () => {
+ let $scope$type: Nullable<Type>;
+ let $scope$name: Nullable<CAMEL_CASE>;
+ let $$res: Nullable<ArgList_$0> = null;
+ if (true
+ && this.loop<ArgList_$0_$0>(() => this.matchArgList_$0_$0($$dpth + 1, $$cr), 0, -1) !== null
+ && ($scope$type = this.matchType($$dpth + 1, $$cr)) !== null
+ && ($scope$name = this.matchCAMEL_CASE($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.ArgList_$0, type: $scope$type, name: $scope$name};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$ArgList_$0$memo,
+ );
+ }
+ public matchArgList_$0_$0($$dpth: number, $$cr?: ErrorTracker): Nullable<ArgList_$0_$0> {
+ return this.memoise(
+ () => {
+ return this.run<ArgList_$0_$0>($$dpth,
+ () => {
+ let $scope$type: Nullable<Type>;
+ let $scope$name: Nullable<CAMEL_CASE>;
+ let $$res: Nullable<ArgList_$0_$0> = null;
+ if (true
+ && ($scope$type = this.matchType($$dpth + 1, $$cr)) !== null
+ && ($scope$name = this.matchCAMEL_CASE($$dpth + 1, $$cr)) !== null
+ && this.matchCOMMA($$dpth + 1, $$cr) !== null
+ && ((this.match_($$dpth + 1, $$cr)) || true)
+ ) {
+ $$res = {kind: ASTKinds.ArgList_$0_$0, type: $scope$type, name: $scope$name};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$ArgList_$0_$0$memo,
+ );
+ }
+ public matchReturnStatement($$dpth: number, $$cr?: ErrorTracker): Nullable<ReturnStatement> {
+ return this.memoise(
+ () => {
+ return this.run<ReturnStatement>($$dpth,
+ () => {
+ let $$res: Nullable<ReturnStatement> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:SHOCKING)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:DEVELOPMENT)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchExpression($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.ReturnStatement, };
+ }
+ return $$res;
+ });
+ },
+ this.$scope$ReturnStatement$memo,
+ );
+ }
+ public matchInterface($$dpth: number, $$cr?: ErrorTracker): Nullable<Interface> {
+ return this.memoise(
+ () => {
+ return this.run<Interface>($$dpth,
+ () => {
+ let $scope$name: Nullable<PASCAL_CASE>;
+ let $scope$methods: Nullable<Interface_$0>;
+ let $$res: Nullable<Interface> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:STUFF)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:OF)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$name = this.matchPASCAL_CASE($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:LOOKS)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:LIKE)`, "", $$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_START($$dpth + 1, $$cr) !== null
+ && ($scope$methods = this.matchInterface_$0($$dpth + 1, $$cr)) !== null
+ ) {
+ $$res = {kind: ASTKinds.Interface, name: $scope$name, methods: $scope$methods};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$Interface$memo,
+ );
+ }
+ public matchInterface_$0($$dpth: number, $$cr?: ErrorTracker): Nullable<Interface_$0> {
+ return this.memoise(
+ () => {
+ return this.loop<FunctionSignature>(() => this.matchFunctionSignature($$dpth + 1, $$cr), 0, -1);
+ },
+ this.$scope$Interface_$0$memo,
+ );
+ }
+ public matchEnum($$dpth: number, $$cr?: ErrorTracker): Nullable<Enum> {
+ return this.memoise(
+ () => {
+ return this.run<Enum>($$dpth,
+ () => {
+ let $scope$name: Nullable<PASCAL_CASE>;
+ let $scope$options: Nullable<EnumBody[]>;
+ let $$res: Nullable<Enum> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:ONLY)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:OPTIONS)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:OF)`, "", $$dpth + 1, $$cr) !== null
+ && ($scope$name = this.matchPASCAL_CASE($$dpth + 1, $$cr)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:ARE)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_START($$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && ($scope$options = this.loop<EnumBody>(() => this.matchEnumBody($$dpth + 1, $$cr), 0, -1)) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.matchSCOPE_END($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.Enum, name: $scope$name, options: $scope$options};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$Enum$memo,
+ );
+ }
+ public matchEnumBody($$dpth: number, $$cr?: ErrorTracker): Nullable<EnumBody> {
+ return this.memoise(
+ () => {
+ return this.run<EnumBody>($$dpth,
+ () => {
+ let $scope$name: Nullable<Identifier>;
+ let $$res: Nullable<EnumBody> = null;
+ if (true
+ && ($scope$name = this.matchIdentifier($$dpth + 1, $$cr)) !== null
+ && this.matchCOMMA($$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.EnumBody, name: $scope$name};
+ }
+ return $$res;
+ });
+ },
+ this.$scope$EnumBody$memo,
+ );
+ }
+ public matchIdentifier($$dpth: number, $$cr?: ErrorTracker): Nullable<Identifier> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:[a-zA-Z][\w\d|\.]*)`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$Identifier$memo,
+ );
+ }
+ public matchSCOPE_START($$dpth: number, $$cr?: ErrorTracker): Nullable<SCOPE_START> {
+ return this.memoise(
+ () => {
+ return this.run<SCOPE_START>($$dpth,
+ () => {
+ let $$res: Nullable<SCOPE_START> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:RUMOR)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:HAS)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:IT)`, "", $$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.SCOPE_START, };
+ }
+ return $$res;
+ });
+ },
+ this.$scope$SCOPE_START$memo,
+ );
+ }
+ public matchSCOPE_END($$dpth: number, $$cr?: ErrorTracker): Nullable<SCOPE_END> {
+ return this.memoise(
+ () => {
+ return this.run<SCOPE_END>($$dpth,
+ () => {
+ let $$res: Nullable<SCOPE_END> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:END)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:OF)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:STORY)`, "", $$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.SCOPE_END, };
+ }
+ return $$res;
+ });
+ },
+ this.$scope$SCOPE_END$memo,
+ );
+ }
+ public matchPROGRAM_END($$dpth: number, $$cr?: ErrorTracker): Nullable<PROGRAM_END> {
+ return this.memoise(
+ () => {
+ return this.run<PROGRAM_END>($$dpth,
+ () => {
+ let $$res: Nullable<PROGRAM_END> = null;
+ if (true
+ && this.regexAccept(String.raw`(?:PLEASE)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:LIKE)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:AND)`, "", $$dpth + 1, $$cr) !== null
+ && this.match_($$dpth + 1, $$cr) !== null
+ && this.regexAccept(String.raw`(?:SUBSCRIBE)`, "", $$dpth + 1, $$cr) !== null
+ ) {
+ $$res = {kind: ASTKinds.PROGRAM_END, };
+ }
+ return $$res;
+ });
+ },
+ this.$scope$PROGRAM_END$memo,
+ );
+ }
+ public matchPASCAL_CASE($$dpth: number, $$cr?: ErrorTracker): Nullable<PASCAL_CASE> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:[A-Z][\w\d]*)`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$PASCAL_CASE$memo,
+ );
+ }
+ public matchCAMEL_CASE($$dpth: number, $$cr?: ErrorTracker): Nullable<CAMEL_CASE> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:[a-z][\w\d]*)`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$CAMEL_CASE$memo,
+ );
+ }
+ public matchLPAREN($$dpth: number, $$cr?: ErrorTracker): Nullable<LPAREN> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:\()`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$LPAREN$memo,
+ );
+ }
+ public matchRPAREN($$dpth: number, $$cr?: ErrorTracker): Nullable<RPAREN> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:\))`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$RPAREN$memo,
+ );
+ }
+ public matchLBRACKET($$dpth: number, $$cr?: ErrorTracker): Nullable<LBRACKET> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:\[)`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$LBRACKET$memo,
+ );
+ }
+ public matchRBRACKET($$dpth: number, $$cr?: ErrorTracker): Nullable<RBRACKET> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:\])`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$RBRACKET$memo,
+ );
+ }
+ public matchCOMMA($$dpth: number, $$cr?: ErrorTracker): Nullable<COMMA> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:,)`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$COMMA$memo,
+ );
+ }
+ public matchPOSITIVE_INT($$dpth: number, $$cr?: ErrorTracker): Nullable<POSITIVE_INT> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:^[1-9][0-9]*$)`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$POSITIVE_INT$memo,
+ );
+ }
+ public match_($$dpth: number, $$cr?: ErrorTracker): Nullable<_> {
+ return this.memoise(
+ () => {
+ return this.regexAccept(String.raw`(?:\s)`, "", $$dpth + 1, $$cr);
+ },
+ this.$scope$_$memo,
+ );
+ }
+ public test(): boolean {
+ const mrk = this.mark();
+ const res = this.matchProgram(0);
+ const ans = res !== null;
+ this.reset(mrk);
+ return ans;
+ }
+ public parse(): ParseResult {
+ const mrk = this.mark();
+ const res = this.matchProgram(0);
+ if (res)
+ return {ast: res, errs: []};
+ this.reset(mrk);
+ const rec = new ErrorTracker();
+ this.clearMemos();
+ this.matchProgram(0, rec);
+ const err = rec.getErr()
+ return {ast: res, errs: err !== null ? [err] : []}
+ }
+ public mark(): PosInfo {
+ return this.pos;
+ }
+ // @ts-ignore: loopPlus may not be called
+ private loopPlus<T>(func: $$RuleType<T>): Nullable<[T, ...T[]]> {
+ return this.loop(func, 1, -1) as Nullable<[T, ...T[]]>;
+ }
+ private loop<T>(func: $$RuleType<T>, lb: number, ub: number): Nullable<T[]> {
+ const mrk = this.mark();
+ const res: T[] = [];
+ while (ub === -1 || res.length < ub) {
+ const preMrk = this.mark();
+ const t = func();
+ if (t === null || this.pos.overallPos === preMrk.overallPos) {
+ break;
+ }
+ res.push(t);
+ }
+ if (res.length >= lb) {
+ return res;
+ }
+ this.reset(mrk);
+ return null;
+ }
+ private run<T>($$dpth: number, fn: $$RuleType<T>): Nullable<T> {
+ const mrk = this.mark();
+ const res = fn()
+ if (res !== null)
+ return res;
+ this.reset(mrk);
+ return null;
+ }
+ // @ts-ignore: choice may not be called
+ private choice<T>(fns: Array<$$RuleType<T>>): Nullable<T> {
+ for (const f of fns) {
+ const res = f();
+ if (res !== null) {
+ return res;
+ }
+ }
+ return null;
+ }
+ private regexAccept(match: string, mods: string, dpth: number, cr?: ErrorTracker): Nullable<string> {
+ return this.run<string>(dpth,
+ () => {
+ const reg = new RegExp(match, "y" + mods);
+ const mrk = this.mark();
+ reg.lastIndex = mrk.overallPos;
+ const res = this.tryConsume(reg);
+ if(cr) {
+ cr.record(mrk, res, {
+ kind: "RegexMatch",
+ // We substring from 3 to len - 1 to strip off the
+ // non-capture group syntax added as a WebKit workaround
+ literal: match.substring(3, match.length - 1),
+ negated: this.negating,
+ });
+ }
+ return res;
+ });
+ }
+ private tryConsume(reg: RegExp): Nullable<string> {
+ const res = reg.exec(this.input);
+ if (res) {
+ let lineJmp = 0;
+ let lind = -1;
+ for (let i = 0; i < res[0].length; ++i) {
+ if (res[0][i] === "\n") {
+ ++lineJmp;
+ lind = i;
+ }
+ }
+ this.pos = {
+ overallPos: reg.lastIndex,
+ line: this.pos.line + lineJmp,
+ offset: lind === -1 ? this.pos.offset + res[0].length : (res[0].length - lind - 1)
+ };
+ return res[0];
+ }
+ return null;
+ }
+ // @ts-ignore: noConsume may not be called
+ private noConsume<T>(fn: $$RuleType<T>): Nullable<T> {
+ const mrk = this.mark();
+ const res = fn();
+ this.reset(mrk);
+ return res;
+ }
+ // @ts-ignore: negate may not be called
+ private negate<T>(fn: $$RuleType<T>): Nullable<boolean> {
+ const mrk = this.mark();
+ const oneg = this.negating;
+ this.negating = !oneg;
+ const res = fn();
+ this.negating = oneg;
+ this.reset(mrk);
+ return res === null ? true : null;
+ }
+ // @ts-ignore: Memoise may not be used
+ private memoise<K>(rule: $$RuleType<K>, memo: Map<number, [Nullable<K>, PosInfo]>): Nullable<K> {
+ const $scope$pos = this.mark();
+ const $scope$memoRes = memo.get($scope$pos.overallPos);
+ if(this.memoSafe && $scope$memoRes !== undefined) {
+ this.reset($scope$memoRes[1]);
+ return $scope$memoRes[0];
+ }
+ const $scope$result = rule();
+ if(this.memoSafe)
+ memo.set($scope$pos.overallPos, [$scope$result, this.mark()]);
+ return $scope$result;
+ }
+}
+export function parse(s: string): ParseResult {
+ const p = new Parser(s);
+ return p.parse();
+}
+export interface ParseResult {
+ ast: Nullable<Program>;
+ errs: SyntaxErr[];
+}
+export interface PosInfo {
+ readonly overallPos: number;
+ readonly line: number;
+ readonly offset: number;
+}
+export interface RegexMatch {
+ readonly kind: "RegexMatch";
+ readonly negated: boolean;
+ readonly literal: string;
+}
+export type EOFMatch = { kind: "EOF"; negated: boolean };
+export type MatchAttempt = RegexMatch | EOFMatch;
+export class SyntaxErr {
+ public pos: PosInfo;
+ public expmatches: MatchAttempt[];
+ constructor(pos: PosInfo, expmatches: MatchAttempt[]) {
+ this.pos = pos;
+ this.expmatches = [...expmatches];
+ }
+ public toString(): string {
+ return `Syntax Error at line ${this.pos.line}:${this.pos.offset}. Expected one of ${this.expmatches.map(x => x.kind === "EOF" ? " EOF" : ` ${x.negated ? 'not ': ''}'${x.literal}'`)}`;
+ }
+}
+class ErrorTracker {
+ private mxpos: PosInfo = {overallPos: -1, line: -1, offset: -1};
+ private regexset: Set<string> = new Set();
+ private pmatches: MatchAttempt[] = [];
+ public record(pos: PosInfo, result: any, att: MatchAttempt) {
+ if ((result === null) === att.negated)
+ return;
+ if (pos.overallPos > this.mxpos.overallPos) {
+ this.mxpos = pos;
+ this.pmatches = [];
+ this.regexset.clear()
+ }
+ if (this.mxpos.overallPos === pos.overallPos) {
+ if(att.kind === "RegexMatch") {
+ if(!this.regexset.has(att.literal))
+ this.pmatches.push(att);
+ this.regexset.add(att.literal);
+ } else {
+ this.pmatches.push(att);
+ }
+ }
+ }
+ public getErr(): SyntaxErr | null {
+ if (this.mxpos.overallPos !== -1)
+ return new SyntaxErr(this.mxpos, this.pmatches);
+ return null;
+ }
+} \ No newline at end of file
diff --git a/src/utils/index.ts b/src/utils/index.ts
new file mode 100644
index 0000000..1ff09ef
--- /dev/null
+++ b/src/utils/index.ts
@@ -0,0 +1 @@
+export * from './logger';
diff --git a/src/utils/logger.ts b/src/utils/logger.ts
new file mode 100644
index 0000000..11a24f7
--- /dev/null
+++ b/src/utils/logger.ts
@@ -0,0 +1,35 @@
+export interface TracingLogger {
+ info(log: string): void;
+ warn(log: string): void;
+ error(log: string): void;
+
+ createChild(prefix: string): TracingLogger;
+}
+
+export class ConsoleTracingLogger implements TracingLogger {
+ protected prefix: string;
+
+ constructor(prefix: string) {
+ this.prefix = prefix;
+ }
+
+ private makePrefix(level: 'info' | 'warn' | 'error'): string {
+ return `[${new Date().toISOString()}] ${level} (${this.prefix}) > `;
+ }
+
+ public info(log: string) {
+ console.log(this.makePrefix('info') + log);
+ }
+
+ public warn(log: string) {
+ console.warn(this.makePrefix('warn') + log);
+ }
+
+ public error(log: string) {
+ console.error(this.makePrefix('error') + log);
+ }
+
+ public createChild(prefix: string) {
+ return new ConsoleTracingLogger(`${this.prefix} -> ${prefix}`);
+ }
+}
diff --git a/test/parser.spec.ts b/test/parser.spec.ts
new file mode 100644
index 0000000..63ec65b
--- /dev/null
+++ b/test/parser.spec.ts
@@ -0,0 +1,12 @@
+import { expect, test } from 'bun:test';
+import { TestPrograms } from './programs';
+import { Parser } from '@/parser';
+
+test('fibonacci program', () => {
+ const parser = new Parser(TestPrograms.Fibonacci);
+ const result = parser.parse();
+
+ console.log(result);
+
+ expect(result.errs).toBeEmpty();
+});
diff --git a/test/programs/fib.ts b/test/programs/fib.ts
new file mode 100644
index 0000000..11a8b1f
--- /dev/null
+++ b/test/programs/fib.ts
@@ -0,0 +1 @@
+export const FIBONACCI_PROG = `PLEASE OF asdf`;
diff --git a/test/programs/index.ts b/test/programs/index.ts
new file mode 100644
index 0000000..af4170d
--- /dev/null
+++ b/test/programs/index.ts
@@ -0,0 +1,5 @@
+import { FIBONACCI_PROG } from './fib';
+
+export namespace TestPrograms {
+ export const Fibonacci = FIBONACCI_PROG;
+}
diff --git a/test/programs/module.ts b/test/programs/module.ts
new file mode 100644
index 0000000..a27b51f
--- /dev/null
+++ b/test/programs/module.ts
@@ -0,0 +1,37 @@
+export const MOD_PROG = `
+WE MADE Node<T> WITH
+ RUMOR HAS IT
+ T a AND
+ Cons<U> b
+ END OF STORY
+
+STUFF OF FibonacciI LOOKS LIKE
+ RUMOR HAS IT
+ DISCOVER HOW TO fibonacci
+ WITH Int a, Int b, Int n
+ GIVES YOU Int
+ END OF STORY
+
+EVERYTHING CHANGED WHEN FibonacciImpl
+ WHICH LOOKS LIKE FibonacciI
+ EXISTS
+RUMOR HAS IT
+ DISCOVER HOW TO fibonacci
+ WITH Int a, Int b, Int n
+ GIVES YOU Int
+ RUMOR HAS IT
+ WHAT IF n < 1
+ SHOCKING DEVELOPMENT b
+ LIES! RUMOR HAS IT
+ SHOCKING DEVELOPMENT
+ fibonacci OF b, a + b, n - 1
+ END OF STORY
+ END OF STORY
+END OF STORY
+
+EXPERTS CLAIM limit TO BE Int 10
+YOU WON'T WANT TO MISS 'First 10 Fibonacci numbers'
+EXPERTS CLAIM nothing TO BE fibonacci OF 0, 1, limit
+
+PLEASE LIKE AND SUBSCRIBE
+`;
diff --git a/test/programs/router.ts b/test/programs/router.ts
new file mode 100644
index 0000000..2d2dcb5
--- /dev/null
+++ b/test/programs/router.ts
@@ -0,0 +1,75 @@
+export const HTTP_BRAINSTORM_PROG = `
+WE MADE Cookie WITH
+RUMOR HAS IT
+ String key,
+ String value,
+ Maybe(String) expires,
+ Maybe(Boolean) secure,
+ Maybe(Boolean) httpOnly,
+ Maybe(String) sameSite,
+END OF STORY
+
+ONLY OPTIONS OF HttpMethod ARE
+RUMOR HAS IT
+ Get,
+ Post,
+ Delete,
+ Patch,
+ Put,
+END OF STORY
+
+WE MADE Request WITH
+RUMOR HAS IT
+ HttpMethod method,
+ String path,
+ Maybe(List(Cookie)) cookies,
+ List(String[2]) headers,
+ List(String[2]) query,
+END OF STORY
+
+WE MADE Response WITH
+RUMOR HAS IT
+ String response,
+ Maybe(List(String[2])) headers,
+ Maybe(List(String[2])) cookies,
+END OF STORY
+
+STUFF OF Controller LOOKS LIKE
+RUMOR HAS IT
+ DISCOVER HOW TO respond
+ WITH Request req
+ GIVES YOU Response
+END OF STORY
+
+EVERYTHING CHANGED WHEN BasicController
+ WHICH LOOKS LIKE Controller
+ EXISTS
+RUMOR HAS IT
+ PRACTICALLY IMPOSSIBLE TO HAVE BasicController
+ WITHOUT
+ Maybe(Int) initialCount
+ RUMOR HAS IT
+ EXPERTS CLAIM count TO BE Int
+ IS DATING initialCount WHO IS
+ RUMOR HAS IT
+ Someone(c) SO c
+ Nobody SO 0
+ END OF STORY
+ END OF STORY
+
+ DISCOVER HOW TO respond
+ WITH Request req
+ GIVES YOU Response
+ RUMOR HAS IT
+ EXPERTS CLAIM res TO BE Response MADE OF
+ RUMOR HAS IT
+ EXPERTS CLAIM response TO BE Int.toString OF
+ MY OWN count
+ END OF STORY
+
+ SHOCKING DEVELOPMENT res
+ END OF STORY
+END OF STORY
+
+PLEASE LIKE AND SUBSCRIBE
+`;
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..544b2b5
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "lib": ["ESNext"],
+ "target": "ESNext",
+ "module": "ESNext",
+ "moduleDetection": "force",
+ "jsx": "react-jsx",
+ "allowJs": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "noEmit": true,
+
+ /* Linting */
+ "skipLibCheck": true,
+ "strict": true,
+ "noFallthroughCasesInSwitch": true,
+ "forceConsistentCasingInFileNames": true,
+
+ "paths": {
+ "@/*": ["./src/*"],
+ "@t/*": ["./test/*"]
+ }
+ }
+}