grammar-well 1.1.0

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.
Files changed (117) hide show
  1. package/.eslintrc.cjs +14 -0
  2. package/README.md +288 -0
  3. package/bootstrap.ts +35 -0
  4. package/build/compiler/compiler.d.ts +48 -0
  5. package/build/compiler/compiler.js +227 -0
  6. package/build/compiler/compiler.js.map +1 -0
  7. package/build/compiler/generator.d.ts +23 -0
  8. package/build/compiler/generator.js +213 -0
  9. package/build/compiler/generator.js.map +1 -0
  10. package/build/compiler/import-resolver.d.ts +15 -0
  11. package/build/compiler/import-resolver.js +37 -0
  12. package/build/compiler/import-resolver.js.map +1 -0
  13. package/build/compiler/outputs/javascript.d.ts +3 -0
  14. package/build/compiler/outputs/javascript.js +29 -0
  15. package/build/compiler/outputs/javascript.js.map +1 -0
  16. package/build/compiler/outputs/json.d.ts +2 -0
  17. package/build/compiler/outputs/json.js +8 -0
  18. package/build/compiler/outputs/json.js.map +1 -0
  19. package/build/compiler/outputs/typescript.d.ts +2 -0
  20. package/build/compiler/outputs/typescript.js +108 -0
  21. package/build/compiler/outputs/typescript.js.map +1 -0
  22. package/build/grammars/gwell.d.ts +997 -0
  23. package/build/grammars/gwell.js +537 -0
  24. package/build/grammars/gwell.js.map +1 -0
  25. package/build/grammars/json.d.ts +151 -0
  26. package/build/grammars/json.js +112 -0
  27. package/build/grammars/json.js.map +1 -0
  28. package/build/grammars/number.d.ts +239 -0
  29. package/build/grammars/number.js +115 -0
  30. package/build/grammars/number.js.map +1 -0
  31. package/build/grammars/number.json +1 -0
  32. package/build/grammars/string.d.ts +116 -0
  33. package/build/grammars/string.js +50 -0
  34. package/build/grammars/string.js.map +1 -0
  35. package/build/grammars/string.json +1 -0
  36. package/build/grammars/whitespace.d.ts +51 -0
  37. package/build/grammars/whitespace.js +30 -0
  38. package/build/grammars/whitespace.js.map +1 -0
  39. package/build/grammars/whitespace.json +1 -0
  40. package/build/index.d.ts +4 -0
  41. package/build/index.js +21 -0
  42. package/build/index.js.map +1 -0
  43. package/build/lexers/character-lexer.d.ts +27 -0
  44. package/build/lexers/character-lexer.js +71 -0
  45. package/build/lexers/character-lexer.js.map +1 -0
  46. package/build/lexers/stateful-lexer.d.ts +48 -0
  47. package/build/lexers/stateful-lexer.js +309 -0
  48. package/build/lexers/stateful-lexer.js.map +1 -0
  49. package/build/lexers/token-buffer.d.ts +32 -0
  50. package/build/lexers/token-buffer.js +92 -0
  51. package/build/lexers/token-buffer.js.map +1 -0
  52. package/build/parser/algorithms/cyk.d.ts +16 -0
  53. package/build/parser/algorithms/cyk.js +58 -0
  54. package/build/parser/algorithms/cyk.js.map +1 -0
  55. package/build/parser/algorithms/earley.d.ts +48 -0
  56. package/build/parser/algorithms/earley.js +158 -0
  57. package/build/parser/algorithms/earley.js.map +1 -0
  58. package/build/parser/algorithms/lr.d.ts +10 -0
  59. package/build/parser/algorithms/lr.js +34 -0
  60. package/build/parser/algorithms/lr.js.map +1 -0
  61. package/build/parser/parser.d.ts +26 -0
  62. package/build/parser/parser.js +74 -0
  63. package/build/parser/parser.js.map +1 -0
  64. package/build/typings.d.ts +198 -0
  65. package/build/typings.js +3 -0
  66. package/build/typings.js.map +1 -0
  67. package/build/utility/general.d.ts +46 -0
  68. package/build/utility/general.js +112 -0
  69. package/build/utility/general.js.map +1 -0
  70. package/build/utility/lint.d.ts +2 -0
  71. package/build/utility/lint.js +28 -0
  72. package/build/utility/lint.js.map +1 -0
  73. package/build/utility/lr.d.ts +56 -0
  74. package/build/utility/lr.js +131 -0
  75. package/build/utility/lr.js.map +1 -0
  76. package/build/utility/text-format.d.ts +11 -0
  77. package/build/utility/text-format.js +84 -0
  78. package/build/utility/text-format.js.map +1 -0
  79. package/licenses/LICENSE.txt +165 -0
  80. package/licenses/moo.license +29 -0
  81. package/licenses/nearley.license +21 -0
  82. package/package.json +52 -0
  83. package/src/compiler/compiler.ts +239 -0
  84. package/src/compiler/generator.ts +229 -0
  85. package/src/compiler/import-resolver.ts +36 -0
  86. package/src/compiler/outputs/javascript.ts +27 -0
  87. package/src/compiler/outputs/json.ts +5 -0
  88. package/src/compiler/outputs/typescript.ts +105 -0
  89. package/src/grammars/gwell.gwell +278 -0
  90. package/src/grammars/gwell.js +539 -0
  91. package/src/grammars/gwell.json +1 -0
  92. package/src/grammars/json.gwell +75 -0
  93. package/src/grammars/json.js +121 -0
  94. package/src/grammars/json.json +1 -0
  95. package/src/grammars/number.gwell +20 -0
  96. package/src/grammars/number.js +117 -0
  97. package/src/grammars/number.json +1 -0
  98. package/src/grammars/string.gwell +15 -0
  99. package/src/grammars/string.js +52 -0
  100. package/src/grammars/string.json +1 -0
  101. package/src/grammars/whitespace.gwell +6 -0
  102. package/src/grammars/whitespace.js +32 -0
  103. package/src/grammars/whitespace.json +1 -0
  104. package/src/index.ts +4 -0
  105. package/src/lexers/character-lexer.ts +73 -0
  106. package/src/lexers/stateful-lexer.ts +335 -0
  107. package/src/lexers/token-buffer.ts +102 -0
  108. package/src/parser/algorithms/cyk.ts +74 -0
  109. package/src/parser/algorithms/earley.ts +193 -0
  110. package/src/parser/algorithms/lr.ts +37 -0
  111. package/src/parser/parser.ts +77 -0
  112. package/src/typings.ts +221 -0
  113. package/src/utility/general.ts +120 -0
  114. package/src/utility/lint.ts +26 -0
  115. package/src/utility/lr.ts +153 -0
  116. package/src/utility/text-format.ts +84 -0
  117. package/testing.ts +18 -0
@@ -0,0 +1,105 @@
1
+ import { Generator } from "../generator";
2
+
3
+ export function TypescriptFormat(generator: Generator, exportName: string) {
4
+ return `// Generated automatically by Grammar-Well, version ${generator.state.version}
5
+ // https://github.com/0x6563/grammar-well
6
+
7
+ ${generator.serializeHead()}
8
+
9
+ interface LanguageDefinition {
10
+ lexer?: Lexer | LexerConfig;
11
+ grammar: {
12
+ start: string;
13
+ rules: GrammarRule[];
14
+ }
15
+ }
16
+
17
+ interface Lexer {
18
+ next(): LexerToken | undefined;
19
+ feed(chunk?: string, state?: ReturnType<Lexer['state']>): void;
20
+ state(): any;
21
+ flush?(): void;
22
+ }
23
+
24
+ interface LexerConfig {
25
+ start?: string
26
+ states: LexerStateDefinition[];
27
+ }
28
+
29
+ interface LexerToken {
30
+ type?: string;
31
+ value: string;
32
+ offset: number;
33
+ line: number;
34
+ column: number;
35
+ }
36
+
37
+ interface LexerStatus {
38
+ index: number;
39
+ line: number;
40
+ column: number;
41
+ state: string;
42
+ }
43
+
44
+ interface LexerStateDefinition {
45
+ name: string;
46
+ unmatched?: string;
47
+ default?: string;
48
+ rules: (LexerStateImportRule | LexerStateMatchRule)[];
49
+ }
50
+
51
+ interface LexerStateImportRule {
52
+ import: string[]
53
+ }
54
+
55
+ interface LexerStateMatchRule {
56
+ when: string | RegExp
57
+ type?: string;
58
+ pop?: number | 'all';
59
+ inset?: number;
60
+ goto?: string;
61
+ set?: string;
62
+ }
63
+
64
+ interface GrammarRule {
65
+ name: string;
66
+ symbols: RuleSymbol[];
67
+ postprocess?: PostProcessor;
68
+ }
69
+
70
+ type RuleSymbol = string | RegExp | RuleSymbolToken | RuleSymbolLexerToken | LexerTokenMatch | RuleSymbolTestable;
71
+
72
+ interface RuleSymbolToken {
73
+ literal: any;
74
+ }
75
+
76
+ interface RuleSymbolTestable {
77
+ test: (data: any) => boolean;
78
+ }
79
+
80
+ interface RuleSymbolLexerToken {
81
+ type: string;
82
+ }
83
+
84
+ interface LexerTokenMatch {
85
+ token: string;
86
+ }
87
+
88
+ type PostProcessor = (payload: PostProcessorPayload) => any;
89
+
90
+ interface PostProcessorPayload {
91
+ data: any[];
92
+ reference: number;
93
+ dot: number;
94
+ name: string;
95
+ }
96
+
97
+ function ${exportName}(): LanguageDefinition {
98
+ ${generator.serializeBody()}
99
+ return ${generator.serializeLanguage(1)}
100
+ }
101
+
102
+ export default ${exportName};
103
+
104
+ `;
105
+ }
@@ -0,0 +1,278 @@
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
7
+ - when: /grammar(?![a-zA-Z\d_])/ tag: "T_WORD" goto: grammar
8
+ - when: /config(?![a-zA-Z\d_])/ tag: "T_WORD" goto: config
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"
61
+ string2 ->
62
+ - when: /'(?:[^'\\\r\n]|\\.)*'/ tag: "T_STRING"
63
+ string3 ->
64
+ - when: /`(?:[^`\\]|\\.)*`/ tag: "T_STRING"
65
+ regex ->
66
+ - when: /\/(?:[^\/\\\r\n]|\\.)+\// tag: "T_REGEX"
67
+ integer ->
68
+ - when: /\d+/ tag: "T_INTEGER"
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"
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"
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"
97
+ l_dsign ->
98
+ - when: "$" tag: "L_DSIGN"
99
+ l_dash ->
100
+ - when: "-" tag: "L_DASH"
101
+ comment ->
102
+ - when: /\/\/[^\n]*/ tag: "T_COMMENT"
103
+ commentmulti ->
104
+ - when: /\/\*.*\*\// tag: "T_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 _ L_TEMPLATER : {{ { config: Object.assign(...$4) } }}
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_LEXER _ L_COLON _ L_TEMPLATEL _ lexer:lexer _ L_TEMPLATER : {{ { lexer: Object.assign(...$lexer) } }}
122
+ | K_GRAMMAR _ L_COLON _ L_TEMPLATEL _ grammar:grammar _ L_TEMPLATER : {{ { grammar: $grammar } }}
123
+ | K_BODY _ L_COLON _ T_JS:js : {{ { body: $js } }}
124
+ | K_BODY _ L_COLON _ T_STRING:js : {{ { body: $js, path: true } }}
125
+ | K_HEAD _ L_COLON _ T_JS:js : {{ { head: $js } }}
126
+ | K_HEAD _ L_COLON _ T_STRING:js : {{ { head: $js, path: true } }}
127
+
128
+ lexer ->
129
+ kv_list _ state_list : {{ $0.concat({ states: $2 }) }}
130
+ | state_list : {{ [{ states: $0 }] }}
131
+
132
+ state_list ->
133
+ state : {{ data }}
134
+ | state _ state_list : {{ [$0].concat($2) }}
135
+
136
+ state ->
137
+ state_declare _ state_definition : {{ Object.assign({ name: $0 }, $2) }}
138
+
139
+ state_declare ->
140
+ T_WORD _ L_ARROW : {{ $0 }}
141
+
142
+ state_definition ->
143
+ kv_list _ token_list : {{ Object.assign(...$0, { rules: $2 }) }}
144
+ | token_list : {{ { rules: $0 } }}
145
+
146
+ token_list ->
147
+ token : {{ data }}
148
+ | token _ token_list : {{ [$0].concat($2) }}
149
+
150
+ token ->
151
+ L_DASH _ K_IMPORT _ L_COLON _ word_list : {{ { import: $6 } }}
152
+ | L_DASH _ token_definition_list : {{ Object.assign(...$2) }}
153
+
154
+ token_definition_list ->
155
+ token_definition : {{ data }}
156
+ | token_definition _ token_definition_list : {{ [$0].concat($2) }}
157
+
158
+ token_definition ->
159
+ K_TAG _ L_COLON _ string_list : {{ { tag: $4 } }}
160
+ | K_WHEN _ L_COLON _ T_STRING : {{ { when: $4 } }}
161
+ | K_WHEN _ L_COLON _ T_REGEX : {{ { when: $4 } }}
162
+ | K_POP : {{ { pop: 1 } }}
163
+ | K_POP _ L_COLON _ T_INTEGER : {{ { pop: parseInt($4) } }}
164
+ | K_POP _ L_COLON _ K_ALL : {{ { pop: "all" } }}
165
+ | K_INSET : {{ { inset: 1 } }}
166
+ | K_INSET _ L_COLON _ T_INTEGER : {{ { inset: parseInt($4) } }}
167
+ | K_SET _ L_COLON _ T_WORD : {{ { set: $4 } }}
168
+ | K_GOTO _ L_COLON _ T_WORD : {{ { goto: $4 } }}
169
+ | K_TYPE _ L_COLON _ T_STRING : {{ { type: $4 } }}
170
+
171
+ grammar ->
172
+ kv_list _ grammar_rule_list : {{ { config: Object.assign(...$0), rules: $2 } }}
173
+ | grammar_rule_list : {{ { rules: $0 } }}
174
+
175
+ grammar_rule_list ->
176
+ grammar_rule : {{ [$0] }}
177
+ | grammar_rule _ grammar_rule_list : {{ [$0].concat($2) }}
178
+
179
+ grammar_rule ->
180
+ T_WORD _ L_ARROW _ expression_list : {{ { name: $0, expressions: $4 } }}
181
+ | T_WORD __ L_COLON _ T_JS:js _ L_ARROW _ expression_list:expressions : {{ { name: $0, expressions: $expressions, postprocess: $js } }}
182
+ | T_WORD __ L_COLON _ T_GRAMMAR_TEMPLATE:template _ L_ARROW _ expression_list:expressions : {{ { name: $0, expressions: $expressions, postprocess: $template } }}
183
+
184
+ expression_list ->
185
+ expression
186
+ | expression_list _ L_PIPE _ expression : {{ $0.concat([$4]) }}
187
+
188
+ expression ->
189
+ expression_symbol_list : {{ { symbols: $0 } }}
190
+ | expression_symbol_list __ L_COLON _ T_JS:js : {{ { symbols: $0, postprocess: $js } }}
191
+ | expression_symbol_list __ L_COLON _ T_GRAMMAR_TEMPLATE:template : {{ { symbols: $0, postprocess: $template } }}
192
+
193
+ expression_symbol_list ->
194
+ expression_symbol
195
+ | expression_symbol_list T_WS expression_symbol : {{ $0.concat([$2]) }}
196
+
197
+
198
+ expression_symbol ->
199
+ expression_symbol_match : {{ $0 }}
200
+ | expression_symbol_match L_COLON T_WORD : {{ { ...$0, alias: $2 } }}
201
+ | expression_symbol_match expression_repeater : {{ { expression: $0, repeat: $1 } }}
202
+ | expression_symbol_match expression_repeater L_COLON T_WORD : {{ { expression: $0, repeat: $1, alias: $4 } }}
203
+
204
+
205
+ expression_symbol_match ->
206
+ T_WORD : {{ { rule: $0 } }}
207
+ | T_STRING "i"? : {{ { literal: $0, insensitive: !!$1 } }}
208
+ | L_DSIGN T_WORD : {{ { token: $1} }}
209
+ | L_DSIGN T_STRING : {{ { token: $1} }}
210
+ | T_REGEX : {{ $0 }}
211
+ | L_PARENL _ expression_list _ L_PARENR : {{ { subexpression: $2 } }}
212
+ | T_JS : {{ $0 }}
213
+
214
+ expression_repeater : {{ $0[0].value }} ->
215
+ L_QMARK
216
+ | L_PLUS
217
+ | L_STAR
218
+
219
+ kv_list ->
220
+ kv : {{ data }}
221
+ | kv _ kv_list : {{ [$0].concat($2) }}
222
+
223
+ kv ->
224
+ T_WORD _ L_COLON _ ( T_WORD| T_STRING| T_INTEGER | T_JS | T_GRAMMAR_TEMPLATE) : {{ { [$0]: $4[0] } }}
225
+
226
+ string_list ->
227
+ T_STRING : {{ [$0] }}
228
+ | T_STRING _ L_COMMA _ string_list : {{ [$0].concat($4) }}
229
+
230
+ word_list ->
231
+ T_WORD : {{ [$0] }}
232
+ | T_WORD _ L_COMMA _ word_list : {{ [$0].concat($4) }}
233
+
234
+ _ ->
235
+ T_WS? : {{ null }}
236
+ __ ->
237
+ T_WS+ : {{ null }}
238
+
239
+ L_COLON -> $L_COLON
240
+ L_SCOLON -> $L_SCOLON
241
+ L_QMARK -> $L_QMARK
242
+ L_PLUS -> $L_PLUS
243
+ L_STAR -> $L_STAR
244
+ L_COMMA -> $L_COMMA
245
+ L_PIPE -> $L_PIPE
246
+ L_PARENL -> $L_PARENL
247
+ L_PARENR -> $L_PARENR
248
+ L_TEMPLATEL -> $L_TEMPLATEL
249
+ L_TEMPLATER -> $L_TEMPLATER
250
+ L_ARROW -> $L_ARROW
251
+ L_DSIGN -> $L_DSIGN
252
+ L_DASH -> $L_DASH
253
+
254
+ K_ALL -> "all"
255
+ K_TAG -> "tag"
256
+ K_FROM -> "from"
257
+ K_TYPE -> "type"
258
+ K_WHEN -> "when"
259
+ K_POP -> "pop"
260
+ K_INSET -> "inset"
261
+ K_SET -> "set"
262
+ K_GOTO -> "goto"
263
+ K_CONFIG -> "config"
264
+ K_LEXER -> "lexer"
265
+ K_GRAMMAR -> "grammar"
266
+ K_IMPORT -> "import"
267
+ K_BODY -> "body"
268
+ K_HEAD -> "head"
269
+
270
+ T_JS -> $L_JSL $T_JSBODY* $L_JSR : {{ { js: $1.map(v=>v.value).join('') } }}
271
+ T_GRAMMAR_TEMPLATE -> $L_TEMPLATEL _ $T_JSBODY* _ $L_TEMPLATER : {{ { template: $2.map(v=>v.value).join('').trim() } }}
272
+ T_STRING -> $T_STRING : {{ JSON.parse($0.value) }}
273
+ T_WORD -> $T_WORD : {{ $0.value }}
274
+ T_REGEX -> $T_REGEX /[gmiuy]/* : {{ { regex: $0.value.replace(/\\\\\//g,'/').slice(1,-1), flags: $1.join('') } }}
275
+ T_COMMENT -> $T_COMMENT
276
+ T_INTEGER -> $T_INTEGER : {{ $0.value }}
277
+ T_WS -> $T_WS : {{ null }}
278
+ }}