grammar-well 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grammar-well",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Cross-platform Parser written in TypeScript",
5
5
  "main": "build/index.js",
6
6
  "scripts": {
@@ -0,0 +1,74 @@
1
+ import * from whitespace;
2
+
3
+ lexer: {{
4
+ start: "json"
5
+
6
+ json ->
7
+ - import: whitespace
8
+ - when: /-?(?:[0-9]|[1-9][0-9]+)(?:\.[0-9]+)?(?:[eE][-+]?[0-9]+)?\b/ tag: "number"
9
+ - when: /"(?:\\["bfnrt\/\\]|\\u[a-fA-F0-9]{4}|[^"\\])*"/ tag: "string"
10
+ - when: "{" tag: "{"
11
+ - when: "}" tag: "}"
12
+ - when: "[" tag: "["
13
+ - when: "]" tag: "]"
14
+ - when: "," tag: ","
15
+ - when: ":" tag: ":"
16
+ - when: "true" tag: "true"
17
+ - when: "false" tag: "false"
18
+ - when: "null" tag: "null"
19
+ }}
20
+
21
+ grammar: {{
22
+ json -> _ (object | array) _ : {{ $1[0] }}
23
+
24
+ object -> "{" _ "}" : {{ {} }}
25
+ | "{" _ pair (_ "," _ pair)* _ "}" : ${ extractObject }
26
+
27
+ array -> "[" _ "]" : {{ [] }}
28
+ | "[" _ value (_ "," _ value)* _ "]" : ${ extractArray }
29
+
30
+ value : {{ $0 }} ->
31
+ object
32
+ | array
33
+ | number
34
+ | string
35
+ | "true" : {{ true }}
36
+ | "false" : {{ false }}
37
+ | "null" : {{ null }}
38
+
39
+ number -> $number : {{ parseFloat($0.value) }}
40
+
41
+ string -> $string : {{ JSON.parse($0.value) }}
42
+
43
+ pair -> key:k _ ":" _ value:v : {{ [$k, $v] }}
44
+
45
+ key -> string : {{ $0 }}
46
+ }}
47
+
48
+ head: ${
49
+ function extractPair(kv, output) {
50
+ if(kv[0]) { output[kv[0]] = kv[1]; }
51
+ }
52
+
53
+ function extractObject({data}) {
54
+ let output = {};
55
+
56
+ extractPair(data[2], output);
57
+
58
+ for (let i in data[3]) {
59
+ extractPair(data[3][i][3], output);
60
+ }
61
+
62
+ return output;
63
+ }
64
+
65
+ function extractArray({data}) {
66
+ let output = [data[2]];
67
+
68
+ for (let i in data[3]) {
69
+ output.push(data[3][i][3]);
70
+ }
71
+
72
+ return output;
73
+ }
74
+ }
@@ -0,0 +1,20 @@
1
+ grammar: {{
2
+
3
+ unsigned_int ->
4
+ /[0-9]/+ : {{ parseInt($0.join("")) }}
5
+
6
+ int ->
7
+ ("-"|"+")? /[0-9]/+ : {{ $0 ? parseInt($0[0]+$1.join("")) : parseInt($1.join("")) }}
8
+
9
+ unsigned_decimal ->
10
+ /[0-9]/+ ("." /[0-9]/+)? : {{ parseFloat($0.join("") + ($1 ? "."+$1[1].join("") : "")) }}
11
+
12
+ decimal ->
13
+ "-"? /[0-9]/+ ("." /[0-9]/+)? : {{ parseFloat( ($0 || "") + $1.join("") +($2 ? "."+$2[1].join("") : "")) }}
14
+
15
+ percentage ->
16
+ decimal "%" : {{ $0/100 }}
17
+
18
+ jsonfloat ->
19
+ "-"? /[0-9]/+ ("." /[0-9]/+)? (/[eE]/ /[+-]/? /[0-9]/+)? : {{ parseFloat( ($0 || "") + $1.join("") + ($2 ? "."+$2[1].join("") : "") + ($3 ? "e" + ($3[1] || "+") + $3[2].join("") : "")) }}
20
+ }}
@@ -0,0 +1,48 @@
1
+ lexer: {{
2
+ string ->
3
+ - import: singleQuoteString, doubleQuoteString
4
+
5
+ doubleQuoteString ->
6
+ - when: /"/ tag: "dquote" highlight:"string" goto: doubleQuoteStringEnd
7
+
8
+ singleQuoteString ->
9
+ - when: /'/ tag: "squote" highlight:"string" goto: singleQuoteStringEnd
10
+
11
+ doubleQuoteStringEnd ->
12
+ - when: /\\[\\\/bnrft]/ tag: "escaped" highlight:"constant"
13
+ - when: /\\"/ tag: "quoteEscape"
14
+ - when: /\\u[A-Fa-f\d]{4}/ tag: "escaped" highlight:"constant"
15
+ - when: /\\./ tag:"badEscape"
16
+ - when: /[^"\\]+/ tag: "string" highlight:"string"
17
+ - when: "\"" tag: "dquote" highlight:"string" pop
18
+
19
+ singleQuoteStringEnd ->
20
+ - when: /\\[\\\/bnrft]/ tag: "escaped"
21
+ - when: /\\'/ tag: "quoteEscape"
22
+ - when: /\\u[A-Fa-f\d]{4}/ tag: "escaped"
23
+ - when: /\\./ tag:"badEscape"
24
+ - when: /[^'\\]+/ tag: "string" highlight:"string"
25
+ - when: "'" tag: "squote" highlight:"string" pop
26
+ }}
27
+
28
+ grammar: {{
29
+ string : {{ $0 }}
30
+ -> singleQuoteString
31
+ | doubleQuoteString
32
+
33
+ doubleQuoteString
34
+ -> $dquote stringInner $dquote : {{ $1 }}
35
+ | $dquote $dquote : {{ '' }}
36
+
37
+ singleQuoteString
38
+ -> $squote stringInner $squote : {{ $1 }}
39
+ | $squote $squote : {{ '' }}
40
+
41
+ stringInner -> stringEscape : {{ $0 }}
42
+ | $string : {{ $0.value }}
43
+ | stringInner stringEscape : {{ $0 + $1 }}
44
+ | stringInner $string : {{ $0 + $1.value }}
45
+
46
+ stringEscape -> $escaped : {{ JSON.parse('"' +$0.value + '"') }}
47
+ | $quoteEscape : {{ $0.value[1] }}
48
+ }}
@@ -0,0 +1,10 @@
1
+ lexer: {{
2
+ start: "whitespace"
3
+ whitespace ->
4
+ - when: /\s+/ tag: "whitespace"
5
+ }}
6
+
7
+ grammar: {{
8
+ _ -> $whitespace* : {{ null }}
9
+ __ -> $whitespace+ : {{ null }}
10
+ }}
@@ -0,0 +1 @@
1
+ {"json":"import * from whitespace;\r\n\r\nlexer: {{\r\n start: \"json\"\r\n\r\n json ->\r\n - import: whitespace\r\n - when: /-?(?:[0-9]|[1-9][0-9]+)(?:\\.[0-9]+)?(?:[eE][-+]?[0-9]+)?\\b/ tag: \"number\"\r\n - when: /\"(?:\\\\[\"bfnrt\\/\\\\]|\\\\u[a-fA-F0-9]{4}|[^\"\\\\])*\"/ tag: \"string\"\r\n - when: \"{\" tag: \"{\"\r\n - when: \"}\" tag: \"}\"\r\n - when: \"[\" tag: \"[\"\r\n - when: \"]\" tag: \"]\"\r\n - when: \",\" tag: \",\"\r\n - when: \":\" tag: \":\"\r\n - when: \"true\" tag: \"true\"\r\n - when: \"false\" tag: \"false\"\r\n - when: \"null\" tag: \"null\"\r\n}}\r\n\r\ngrammar: {{\r\n json -> _ (object | array) _ : {{ $1[0] }}\r\n\r\n object -> \"{\" _ \"}\" : {{ {} }}\r\n | \"{\" _ pair (_ \",\" _ pair)* _ \"}\" : ${ extractObject }\r\n\r\n array -> \"[\" _ \"]\" : {{ [] }}\r\n | \"[\" _ value (_ \",\" _ value)* _ \"]\" : ${ extractArray }\r\n\r\n value : {{ $0 }} ->\r\n object\r\n | array\r\n | number\r\n | string\r\n | \"true\" : {{ true }}\r\n | \"false\" : {{ false }}\r\n | \"null\" : {{ null }}\r\n\r\n number -> $number : {{ parseFloat($0.value) }}\r\n\r\n string -> $string : {{ JSON.parse($0.value) }}\r\n\r\n pair -> key:k _ \":\" _ value:v : {{ [$k, $v] }}\r\n\r\n key -> string : {{ $0 }}\r\n}}\r\n\r\nhead: ${\r\n function extractPair(kv, output) {\r\n if(kv[0]) { output[kv[0]] = kv[1]; }\r\n }\r\n\r\n function extractObject({data}) {\r\n let output = {};\r\n\r\n extractPair(data[2], output);\r\n\r\n for (let i in data[3]) {\r\n extractPair(data[3][i][3], output);\r\n }\r\n\r\n return output;\r\n }\r\n\r\n function extractArray({data}) {\r\n let output = [data[2]];\r\n\r\n for (let i in data[3]) {\r\n output.push(data[3][i][3]);\r\n }\r\n\r\n return output;\r\n }\r\n}\r\n","number":"grammar: {{\r\n\r\n unsigned_int -> \r\n /[0-9]/+ : {{ parseInt($0.join(\"\")) }}\r\n\r\n int -> \r\n (\"-\"|\"+\")? /[0-9]/+ : {{ $0 ? parseInt($0[0]+$1.join(\"\")) : parseInt($1.join(\"\")) }}\r\n\r\n unsigned_decimal -> \r\n /[0-9]/+ (\".\" /[0-9]/+)? : {{ parseFloat($0.join(\"\") + ($1 ? \".\"+$1[1].join(\"\") : \"\")) }}\r\n\r\n decimal -> \r\n \"-\"? /[0-9]/+ (\".\" /[0-9]/+)? : {{ parseFloat( ($0 || \"\") + $1.join(\"\") +($2 ? \".\"+$2[1].join(\"\") : \"\")) }}\r\n\r\n percentage -> \r\n decimal \"%\" : {{ $0/100 }}\r\n \r\n jsonfloat -> \r\n \"-\"? /[0-9]/+ (\".\" /[0-9]/+)? (/[eE]/ /[+-]/? /[0-9]/+)? : {{ parseFloat( ($0 || \"\") + $1.join(\"\") + ($2 ? \".\"+$2[1].join(\"\") : \"\") + ($3 ? \"e\" + ($3[1] || \"+\") + $3[2].join(\"\") : \"\")) }}\r\n}}","string":"lexer: {{\r\n string ->\r\n - import: singleQuoteString, doubleQuoteString\r\n\r\n doubleQuoteString ->\r\n - when: /\"/ tag: \"dquote\" highlight:\"string\" goto: doubleQuoteStringEnd \r\n\r\n singleQuoteString ->\r\n - when: /'/ tag: \"squote\" highlight:\"string\" goto: singleQuoteStringEnd \r\n\r\n doubleQuoteStringEnd ->\r\n - when: /\\\\[\\\\\\/bnrft]/ tag: \"escaped\" highlight:\"constant\"\r\n - when: /\\\\\"/ tag: \"quoteEscape\"\r\n - when: /\\\\u[A-Fa-f\\d]{4}/ tag: \"escaped\" highlight:\"constant\"\r\n - when: /\\\\./ tag:\"badEscape\"\r\n - when: /[^\"\\\\]+/ tag: \"string\" highlight:\"string\"\r\n - when: \"\\\"\" tag: \"dquote\" highlight:\"string\" pop\r\n\r\n singleQuoteStringEnd ->\r\n - when: /\\\\[\\\\\\/bnrft]/ tag: \"escaped\"\r\n - when: /\\\\'/ tag: \"quoteEscape\"\r\n - when: /\\\\u[A-Fa-f\\d]{4}/ tag: \"escaped\" \r\n - when: /\\\\./ tag:\"badEscape\"\r\n - when: /[^'\\\\]+/ tag: \"string\" highlight:\"string\"\r\n - when: \"'\" tag: \"squote\" highlight:\"string\" pop\r\n}}\r\n\r\ngrammar: {{\r\n string : {{ $0 }} \r\n -> singleQuoteString \r\n | doubleQuoteString \r\n\r\n doubleQuoteString \r\n -> $dquote stringInner $dquote : {{ $1 }}\r\n | $dquote $dquote : {{ '' }}\r\n \r\n singleQuoteString \r\n -> $squote stringInner $squote : {{ $1 }}\r\n | $squote $squote : {{ '' }}\r\n\r\n stringInner -> stringEscape : {{ $0 }}\r\n | $string : {{ $0.value }}\r\n | stringInner stringEscape : {{ $0 + $1 }}\r\n | stringInner $string : {{ $0 + $1.value }}\r\n \r\n stringEscape -> $escaped : {{ JSON.parse('\"' +$0.value + '\"') }}\r\n | $quoteEscape : {{ $0.value[1] }}\r\n}}","whitespace":"lexer: {{\r\n start: \"whitespace\"\r\n whitespace ->\r\n - when: /\\s+/ tag: \"whitespace\" \r\n}}\r\n\r\ngrammar: {{\r\n _ -> $whitespace* : {{ null }}\r\n __ -> $whitespace+ : {{ null }}\r\n}}"}
@@ -2,22 +2,15 @@ import { CompileOptions, GrammarBuilderContext, TemplateFormat, LanguageDirectiv
2
2
 
3
3
  import { Parser } from "../parser/parser";
4
4
  import { FileSystemResolver } from "./import-resolver";
5
- import Language from '../grammars/gwell';
5
+ import Language from './gwell';
6
6
 
7
7
  import { ESMOutput, JavascriptOutput } from "./outputs/javascript";
8
8
  import { TypescriptFormat } from "./outputs/typescript";
9
9
  import { JSONFormatter } from "./outputs/json";
10
10
 
11
- import * as number from '../grammars/number.json';
12
- import * as string from '../grammars/string.json';
13
- import * as whitespace from '../grammars/whitespace.json';
14
11
  import { Generator } from "./generator/generator";
12
+ import * as BuiltInRegistry from "./builtin.json"
15
13
 
16
- const BuiltInRegistry = {
17
- number,
18
- string,
19
- whitespace,
20
- }
21
14
  const TemplateFormats = {
22
15
  _default: JavascriptOutput,
23
16
  object: (grammar, exportName) => ({ grammar, exportName }),
@@ -44,7 +37,7 @@ export class GrammarBuilder {
44
37
 
45
38
  generator = new Generator();
46
39
 
47
- constructor(private config: CompileOptions = {}, context?: GrammarBuilderContext) {
40
+ constructor(private config: CompileOptions = {}, context?: GrammarBuilderContext, private alias: string = '') {
48
41
  this.context = context || {
49
42
  alreadyCompiled: new Set(),
50
43
  resolver: config.resolverInstance ? config.resolverInstance : config.resolver ? new config.resolver(config.basedir) : new FileSystemResolver(config.basedir),
@@ -90,7 +83,7 @@ export class GrammarBuilder {
90
83
 
91
84
  private async processImportDirective(directive: ImportDirective) {
92
85
  if (directive.path) {
93
- await this.importGrammar(directive.import);
86
+ await this.importGrammar(directive.import, directive.alias);
94
87
  } else {
95
88
  this.importBuiltIn(directive.import);
96
89
  }
@@ -102,15 +95,22 @@ export class GrammarBuilder {
102
95
 
103
96
  private processGrammarDirective(directive: GrammarDirective) {
104
97
  if (directive.grammar.config) {
105
- this.generator.state.grammar.start = directive.grammar.config.start || this.generator.state.grammar.start;
98
+ if (directive.grammar.config.start) {
99
+ this.generator.state.grammar.start = this.alias + directive.grammar.config.start;
100
+ }
101
+
106
102
  Object.assign(this.generator.state.grammar.config, directive.grammar.config);
107
103
  // this.generator.state.grammar.postprocessDefault = directive.grammar.config.postprocessDefault || this.generator.state.grammar.postprocessDefault;
108
104
  // this.generator.state.grammar.postprocessOverride = directive.grammar.config.postprocessOverride || this.generator.state.grammar.postprocessOverride;
109
105
  }
110
106
 
107
+ if (!this.generator.state.grammar.start && directive.grammar.rules.length) {
108
+ this.generator.state.grammar.start = this.alias + directive.grammar.rules[0].name;
109
+ }
110
+
111
111
  for (const rule of directive.grammar.rules) {
112
+ rule.name = this.alias + rule.name;
112
113
  this.buildRules(rule.name, rule.expressions, rule);
113
- this.generator.state.grammar.start = this.generator.state.grammar.start || rule.name;
114
114
  }
115
115
  }
116
116
 
@@ -121,33 +121,54 @@ export class GrammarBuilder {
121
121
  states: {}
122
122
  };
123
123
  }
124
- this.generator.state.lexer.start = directive.lexer.start || this.generator.state.lexer.start || (directive.lexer.states.length ? directive.lexer.states[0].name : '');
124
+ if (directive.lexer.start) {
125
+ this.generator.state.lexer.start = this.alias + directive.lexer.start;
126
+ }
127
+
128
+ if (!this.generator.state.lexer.start && directive.lexer.states.length) {
129
+ this.generator.state.lexer.start = this.alias + directive.lexer.states[0].name
130
+ }
131
+
125
132
  for (const state of directive.lexer.states) {
133
+ state.name = this.alias + state.name;
134
+ if (this.alias) {
135
+ state.rules.forEach(v => {
136
+ if ('import' in v) {
137
+ v.import = v.import.map(v2 => this.alias + v2);
138
+ }
139
+ if ('set' in v) {
140
+ v.set = this.alias + v.set;
141
+ }
142
+ if ('goto' in v) {
143
+ v.goto = this.alias + v.goto;
144
+ }
145
+ })
146
+ }
126
147
  this.generator.addLexerState(state);
127
148
  }
128
149
  }
129
150
 
130
- private importBuiltIn(name: string) {
151
+ private async importBuiltIn(name: string, alias?: string) {
131
152
  name = name.toLowerCase();
132
153
  if (!this.context.alreadyCompiled.has(name)) {
133
154
  this.context.alreadyCompiled.add(name);
134
155
  if (!BuiltInRegistry[name])
135
156
  return;
136
- this.generator.merge(BuiltInRegistry[name].state);
157
+ await this.mergeLanguageDefinitionString(BuiltInRegistry[name], alias);
137
158
  }
138
159
  }
139
160
 
140
- private async importGrammar(name) {
161
+ private async importGrammar(path: string, alias?: string) {
141
162
  const resolver = this.context.resolver;
142
- const path = resolver.path(name);
143
- if (!this.context.alreadyCompiled.has(path)) {
144
- this.context.alreadyCompiled.add(path);
145
- await this.mergeLanguageDefinitionString(await resolver.body(path))
163
+ const fullPath = resolver.path(path);
164
+ if (!this.context.alreadyCompiled.has(fullPath)) {
165
+ this.context.alreadyCompiled.add(fullPath);
166
+ await this.mergeLanguageDefinitionString(await resolver.body(fullPath), alias);
146
167
  }
147
168
  }
148
169
 
149
- private async mergeLanguageDefinitionString(body: string) {
150
- const builder = new GrammarBuilder(this.config, this.context);
170
+ private async mergeLanguageDefinitionString(body: string, alias: string = '') {
171
+ const builder = new GrammarBuilder(this.config, this.context, alias);
151
172
  await builder.import(this.parser.run(body).results[0]);
152
173
  this.generator.merge(builder.generator.state);
153
174
  return;
@@ -174,7 +195,7 @@ export class GrammarBuilder {
174
195
  return this.buildRepeatRules(name, symbol);
175
196
  }
176
197
  if ('rule' in symbol) {
177
- return symbol;
198
+ return { ...symbol, rule: this.alias + symbol.rule };
178
199
  }
179
200
  if ('regex' in symbol) {
180
201
  return symbol;
@@ -0,0 +1,283 @@
1
+ lexer: {{
2
+ start: "start"
3
+
4
+ start ->
5
+ - import: string, js, ws, comment, l_scolon, l_star
6
+ - when: /lexer(?![a-zA-Z\d_])/ tag: "T_WORD" goto: lexer highlight: "type"
7
+ - when: /grammar(?![a-zA-Z\d_])/ tag: "T_WORD" goto: grammar highlight: "type"
8
+ - when: /config(?![a-zA-Z\d_])/ tag: "T_WORD" goto: config highlight: "type"
9
+ - import: kv
10
+ config ->
11
+ - import: ws, l_colon
12
+ - when: "{{" tag: "L_TEMPLATEL" set: config_inner
13
+ config_inner ->
14
+ - import: comment, kv
15
+ - when: "}}" tag: "L_TEMPLATER" pop: 1
16
+ grammar ->
17
+ - import: ws, l_colon
18
+ - when: "{{" tag: "L_TEMPLATEL" set: grammar_inner
19
+ grammar_inner ->
20
+ - import: comment, js, js_template, ws, regex, l_qmark, l_plus, l_star, kv, l_colon, l_comma, l_pipe, l_parenl, l_parenr, l_arrow, l_dsign, l_dash
21
+ - when: "}}" tag: "L_TEMPLATER" pop: 1
22
+ lexer ->
23
+ - import: ws, l_colon
24
+ - when: "{{" tag: "L_TEMPLATEL" set: lexer_inner
25
+ lexer_inner ->
26
+ - import: ws, comment, regex, l_comma, l_arrow, l_dash, kv, js
27
+ - when: "}}" tag: "L_TEMPLATER" pop: 1
28
+ js ->
29
+ - when: "${" tag: "L_JSL" goto: js_wrap
30
+ js_wrap ->
31
+ default: "T_JSBODY"
32
+ unmatched: "T_JSBODY"
33
+ - import: jsignore
34
+ - when: "{" tag: "T_JSBODY" goto: js_literal
35
+ - when: "}" tag: "L_JSR" pop: 1
36
+ js_literal ->
37
+ default: "T_JSBODY"
38
+ unmatched: "T_JSBODY"
39
+ - import: jsignore
40
+ - when: "{" tag: "T_JSBODY" goto: js_literal
41
+ - when: "}" tag: "T_JSBODY" pop: 1
42
+ js_template ->
43
+ - when: "{{" tag: "L_TEMPLATEL" goto: js_template_inner
44
+ js_template_inner ->
45
+ default: "T_JSBODY"
46
+ unmatched: "T_JSBODY"
47
+ - import: jsignore
48
+ - when: "{" tag: "T_JSBODY" goto: js_literal
49
+ - when: "}}" tag: "L_TEMPLATER" pop: 1
50
+ kv ->
51
+ - import: string, ws, word, l_colon, integer
52
+ jsignore ->
53
+ - when: /"(?:[^"\\\r\n]|\\.)*"/ tag: "T_JSBODY"
54
+ - when: /'(?:[^'\\\r\n]|\\.)*'/ tag: "T_JSBODY"
55
+ - when: /`(?:[^`\\]|\\.)*`/ tag: "T_JSBODY"
56
+ - when: /\/(?:[^\/\\\r\n]|\\.)+\/[gmiyu]*/ tag: "T_JSBODY"
57
+ - when: /\/\/[^\n]*/ tag: "T_JSBODY"
58
+ - when: /\/\*.*\*\// tag: "T_JSBODY"
59
+ string ->
60
+ - when: /"(?:[^"\\\r\n]|\\.)*"/ tag: "T_STRING" highlight: "string"
61
+ string2 ->
62
+ - when: /'(?:[^'\\\r\n]|\\.)*'/ tag: "T_STRING" highlight: "string"
63
+ string3 ->
64
+ - when: /`(?:[^`\\]|\\.)*`/ tag: "T_STRING" highlight: "string"
65
+ regex ->
66
+ - when: /\/(?:[^\/\\\r\n]|\\.)+\// tag: "T_REGEX" highlight: "regexp"
67
+ integer ->
68
+ - when: /\d+/ tag: "T_INTEGER" highlight: "number"
69
+ word ->
70
+ - when: /[a-zA-Z_][a-zA-Z_\d]*/ tag: "T_WORD"
71
+ ws ->
72
+ - when: /\s+/ tag: "T_WS"
73
+ l_colon ->
74
+ - when: ":" tag: "L_COLON" highlight: "keyword"
75
+ l_scolon ->
76
+ - when: ";" tag: "L_SCOLON"
77
+ l_qmark ->
78
+ - when: "?" tag: "L_QMARK"
79
+ l_plus ->
80
+ - when: "+" tag: "L_PLUS"
81
+ l_star ->
82
+ - when: "*" tag: "L_STAR"
83
+ l_comma ->
84
+ - when: "," tag: "L_COMMA"
85
+ l_pipe ->
86
+ - when: "|" tag: "L_PIPE" highlight: "keyword"
87
+ l_parenl ->
88
+ - when: "(" tag: "L_PARENL"
89
+ l_parenr ->
90
+ - when: ")" tag: "L_PARENR"
91
+ l_templatel ->
92
+ - when: "{{" tag: "L_TEMPLATEL"
93
+ l_templater ->
94
+ - when: "}}" tag: "L_TEMPLATER"
95
+ l_arrow ->
96
+ - when: "->" tag: "L_ARROW" highlight: "keyword"
97
+ l_dsign ->
98
+ - when: "$" tag: "L_DSIGN"
99
+ l_dash ->
100
+ - when: "-" tag: "L_DASH"
101
+ comment ->
102
+ - when: /\/\/[^\n]*/ tag: "T_COMMENT" highlight: "comment"
103
+ commentmulti ->
104
+ - when: /\/\*.*\*\// tag: "T_COMMENT" highlight: "comment"
105
+
106
+ }}
107
+
108
+ grammar: {{
109
+
110
+ main ->
111
+ _ section_list _ : {{ $1 }}
112
+
113
+ section_list ->
114
+ section : {{ [$0] }}
115
+ | section T_WS section_list : {{ [$0].concat($2) }}
116
+
117
+ section ->
118
+ K_CONFIG _ L_COLON _ L_TEMPLATEL _ kv_list:list _ L_TEMPLATER : {{ { config: Object.assign(...$list) } }}
119
+ | K_IMPORT _ L_STAR _ K_FROM __ T_WORD:import _ L_SCOLON : {{ { import: $import } }}
120
+ | K_IMPORT _ L_STAR _ K_FROM __ T_STRING:import _ L_SCOLON : {{ { import: $import, path: true } }}
121
+ | K_IMPORT _ L_STAR _ "as" _ T_WORD:alias _ K_FROM __ T_WORD:import _ L_SCOLON : {{ { import: $import, alias: $alias} }}
122
+ | K_IMPORT _ L_STAR _ "as" _ T_WORD:alias _ K_FROM __ T_STRING:import _ L_SCOLON : {{ { import: $import, path: true, alias: $alias} }}
123
+ | K_LEXER _ L_COLON _ L_TEMPLATEL _ lexer:lexer _ L_TEMPLATER : {{ { lexer: Object.assign(...$lexer) } }}
124
+ | K_GRAMMAR _ L_COLON _ L_TEMPLATEL _ grammar:grammar _ L_TEMPLATER : {{ { grammar: $grammar } }}
125
+ | K_BODY _ L_COLON _ T_JS:js : {{ { body: $js } }}
126
+ | K_BODY _ L_COLON _ T_STRING:js : {{ { body: $js, path: true } }}
127
+ | K_HEAD _ L_COLON _ T_JS:js : {{ { head: $js } }}
128
+ | K_HEAD _ L_COLON _ T_STRING:js : {{ { head: $js, path: true } }}
129
+
130
+ lexer ->
131
+ kv_list _ state_list : {{ $0.concat({ states: $2 }) }}
132
+ | state_list : {{ [{ states: $0 }] }}
133
+
134
+ state_list ->
135
+ state : {{ data }}
136
+ | state _ state_list : {{ [$0].concat($2) }}
137
+
138
+ state ->
139
+ state_declare _ state_definition : {{ Object.assign({ name: $0 }, $2) }}
140
+
141
+ state_declare ->
142
+ T_WORD _ L_ARROW : {{ $0 }}
143
+
144
+ state_definition ->
145
+ kv_list _ token_list : {{ Object.assign(...$0, { rules: $2 }) }}
146
+ | token_list : {{ { rules: $0 } }}
147
+
148
+ token_list ->
149
+ token : {{ data }}
150
+ | token _ token_list : {{ [$0].concat($2) }}
151
+
152
+ token ->
153
+ L_DASH _ K_IMPORT _ L_COLON _ word_list : {{ { import: $6 } }}
154
+ | L_DASH _ token_definition_list : {{ Object.assign(...$2) }}
155
+
156
+ token_definition_list ->
157
+ token_definition : {{ data }}
158
+ | token_definition _ token_definition_list : {{ [$0].concat($2) }}
159
+
160
+ token_definition ->
161
+ K_TAG _ L_COLON _ string_list : {{ { tag: $4 } }}
162
+ | K_WHEN _ L_COLON _ T_STRING : {{ { when: $4 } }}
163
+ | K_WHEN _ L_COLON _ T_REGEX : {{ { when: $4 } }}
164
+ | K_POP : {{ { pop: 1 } }}
165
+ | K_POP _ L_COLON _ T_INTEGER : {{ { pop: parseInt($4) } }}
166
+ | K_POP _ L_COLON _ K_ALL : {{ { pop: "all" } }}
167
+ | K_HIGHLIGHT _ L_COLON _ T_STRING : {{ { highlight: $4 } }}
168
+ | K_INSET : {{ { inset: 1 } }}
169
+ | K_INSET _ L_COLON _ T_INTEGER : {{ { inset: parseInt($4) } }}
170
+ | K_SET _ L_COLON _ T_WORD : {{ { set: $4 } }}
171
+ | K_GOTO _ L_COLON _ T_WORD : {{ { goto: $4 } }}
172
+ | K_TYPE _ L_COLON _ T_STRING : {{ { type: $4 } }}
173
+
174
+ grammar ->
175
+ kv_list _ grammar_rule_list : {{ { config: Object.assign(...$0), rules: $2 } }}
176
+ | grammar_rule_list : {{ { rules: $0 } }}
177
+
178
+ grammar_rule_list ->
179
+ grammar_rule : {{ [$0] }}
180
+ | grammar_rule _ grammar_rule_list : {{ [$0].concat($2) }}
181
+
182
+ grammar_rule ->
183
+ T_WORD _ L_ARROW _ expression_list : {{ { name: $0, expressions: $4 } }}
184
+ | T_WORD __ L_COLON _ T_JS:js _ L_ARROW _ expression_list:expressions : {{ { name: $0, expressions: $expressions, postprocess: $js } }}
185
+ | T_WORD __ L_COLON _ T_GRAMMAR_TEMPLATE:template _ L_ARROW _ expression_list:expressions : {{ { name: $0, expressions: $expressions, postprocess: $template } }}
186
+
187
+ expression_list ->
188
+ expression
189
+ | expression_list _ L_PIPE _ expression : {{ $0.concat([$4]) }}
190
+
191
+ expression ->
192
+ expression_symbol_list : {{ { symbols: $0 } }}
193
+ | expression_symbol_list __ L_COLON _ T_JS:js : {{ { symbols: $0, postprocess: $js } }}
194
+ | expression_symbol_list __ L_COLON _ T_GRAMMAR_TEMPLATE:template : {{ { symbols: $0, postprocess: $template } }}
195
+
196
+ expression_symbol_list ->
197
+ expression_symbol
198
+ | expression_symbol_list T_WS expression_symbol : {{ $0.concat([$2]) }}
199
+
200
+
201
+ expression_symbol ->
202
+ expression_symbol_match : {{ $0 }}
203
+ | expression_symbol_match L_COLON T_WORD : {{ { ...$0, alias: $2 } }}
204
+ | expression_symbol_match expression_repeater : {{ { expression: $0, repeat: $1 } }}
205
+ | expression_symbol_match expression_repeater L_COLON T_WORD : {{ { expression: $0, repeat: $1, alias: $4 } }}
206
+
207
+
208
+ expression_symbol_match ->
209
+ T_WORD : {{ { rule: $0 } }}
210
+ | T_STRING "i"? : {{ { literal: $0, insensitive: !!$1 } }}
211
+ | L_DSIGN T_WORD : {{ { token: $1} }}
212
+ | L_DSIGN T_STRING : {{ { token: $1} }}
213
+ | T_REGEX : {{ $0 }}
214
+ | L_PARENL _ expression_list _ L_PARENR : {{ { subexpression: $2 } }}
215
+ | T_JS : {{ $0 }}
216
+
217
+ expression_repeater : {{ $0[0].value }} ->
218
+ L_QMARK
219
+ | L_PLUS
220
+ | L_STAR
221
+
222
+ kv_list ->
223
+ kv : {{ data }}
224
+ | kv _ kv_list : {{ [$0].concat($2) }}
225
+
226
+ kv ->
227
+ T_WORD _ L_COLON _ ( T_WORD| T_STRING| T_INTEGER | T_JS | T_GRAMMAR_TEMPLATE) : {{ { [$0]: $4[0] } }}
228
+
229
+ string_list ->
230
+ T_STRING : {{ [$0] }}
231
+ | T_STRING _ L_COMMA _ string_list : {{ [$0].concat($4) }}
232
+
233
+ word_list ->
234
+ T_WORD : {{ [$0] }}
235
+ | T_WORD _ L_COMMA _ word_list : {{ [$0].concat($4) }}
236
+
237
+ _ ->
238
+ ( T_WS | T_COMMENT )* : {{ null }}
239
+
240
+ __ ->
241
+ ( T_WS | T_COMMENT )+ : {{ null }}
242
+
243
+ L_COLON -> $L_COLON
244
+ L_SCOLON -> $L_SCOLON
245
+ L_QMARK -> $L_QMARK
246
+ L_PLUS -> $L_PLUS
247
+ L_STAR -> $L_STAR
248
+ L_COMMA -> $L_COMMA
249
+ L_PIPE -> $L_PIPE
250
+ L_PARENL -> $L_PARENL
251
+ L_PARENR -> $L_PARENR
252
+ L_TEMPLATEL -> $L_TEMPLATEL
253
+ L_TEMPLATER -> $L_TEMPLATER
254
+ L_ARROW -> $L_ARROW
255
+ L_DSIGN -> $L_DSIGN
256
+ L_DASH -> $L_DASH
257
+
258
+ K_ALL -> "all"
259
+ K_TAG -> "tag"
260
+ K_FROM -> "from"
261
+ K_TYPE -> "type"
262
+ K_WHEN -> "when"
263
+ K_POP -> "pop"
264
+ K_HIGHLIGHT -> "highlight"
265
+ K_INSET -> "inset"
266
+ K_SET -> "set"
267
+ K_GOTO -> "goto"
268
+ K_CONFIG -> "config"
269
+ K_LEXER -> "lexer"
270
+ K_GRAMMAR -> "grammar"
271
+ K_IMPORT -> "import"
272
+ K_BODY -> "body"
273
+ K_HEAD -> "head"
274
+
275
+ T_JS -> $L_JSL $T_JSBODY* $L_JSR : {{ { js: $1.map(v=>v.value).join('') } }}
276
+ T_GRAMMAR_TEMPLATE -> $L_TEMPLATEL _ $T_JSBODY* _ $L_TEMPLATER : {{ { template: $2.map(v=>v.value).join('').trim() } }}
277
+ T_STRING -> $T_STRING : {{ JSON.parse($0.value) }}
278
+ T_WORD -> $T_WORD : {{ $0.value }}
279
+ T_REGEX -> $T_REGEX /[gmiuy]/* : {{ { regex: $0.value.replace(/\\\\\//g,'/').slice(1,-1), flags: $1.map(v=>v.value).join('').trim() } }}
280
+ T_COMMENT -> $T_COMMENT
281
+ T_INTEGER -> $T_INTEGER : {{ $0.value }}
282
+ T_WS -> $T_WS : {{ null }}
283
+ }}