diff options
author | Elizabeth Hunt <elizabeth.hunt@simponic.xyz> | 2024-01-24 18:59:13 -0700 |
---|---|---|
committer | Elizabeth Hunt <elizabeth.hunt@simponic.xyz> | 2024-01-24 18:59:13 -0700 |
commit | 203925d9a48d34537bdf6cd25502134df5e91ae7 (patch) | |
tree | afe8a12679568ba00bfa019b0a5b6f13a3778c00 | |
download | tabloid-compiler-main.tar.gz tabloid-compiler-main.zip |
-rw-r--r-- | .gitignore | 175 | ||||
-rw-r--r-- | .prettierrc | 17 | ||||
-rw-r--r-- | .tool-versions | 1 | ||||
-rwxr-xr-x | bun.lockb | bin | 0 -> 21962 bytes | |||
-rw-r--r-- | package.json | 18 | ||||
-rw-r--r-- | src/args.ts | 9 | ||||
-rw-r--r-- | src/index.ts | 34 | ||||
-rw-r--r-- | src/parser/generate.ts | 8 | ||||
-rw-r--r-- | src/parser/grammar.peg | 67 | ||||
-rw-r--r-- | src/parser/grammar.peg.new | 67 | ||||
-rw-r--r-- | src/parser/index.ts | 2 | ||||
-rw-r--r-- | src/parser/parser.ts | 2082 | ||||
-rw-r--r-- | src/utils/index.ts | 1 | ||||
-rw-r--r-- | src/utils/logger.ts | 35 | ||||
-rw-r--r-- | test/parser.spec.ts | 12 | ||||
-rw-r--r-- | test/programs/fib.ts | 1 | ||||
-rw-r--r-- | test/programs/index.ts | 5 | ||||
-rw-r--r-- | test/programs/module.ts | 37 | ||||
-rw-r--r-- | test/programs/router.ts | 75 | ||||
-rw-r--r-- | tsconfig.json | 27 |
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 Binary files differnew file mode 100755 index 0000000..c47b87a --- /dev/null +++ b/bun.lockb 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/*"] + } + } +} |