@ohm-js/wasm 0.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.
- package/.mise.toml +2 -0
- package/AGENT.md +25 -0
- package/LICENSE +21 -0
- package/Makefile +23 -0
- package/README.md +34 -0
- package/TODO.md +28 -0
- package/package.json +32 -0
- package/runtime/ohmRuntime.ts +252 -0
- package/scripts/bundlewasm.ts +49 -0
- package/scripts/modparse.ts +397 -0
- package/src/cli.js +36 -0
- package/src/index.js +1195 -0
- package/test/data/_book-review.liquid +257 -0
- package/test/data/_es5.js +1057 -0
- package/test/data/_es5.wasm +0 -0
- package/test/data/_html5shiv-3.7.3.js +326 -0
- package/test/data/_liquid-html.ohm +605 -0
- package/test/go/README.md +67 -0
- package/test/go/cst.go +164 -0
- package/test/go/go.mod +5 -0
- package/test/go/go.sum +2 -0
- package/test/go/matcher.go +370 -0
- package/test/go/testmain.go +161 -0
- package/test/test-es5.js +104 -0
- package/test/test-liquid-html.js +27 -0
- package/test/test-wasm.js +764 -0
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
Helpers {
|
|
2
|
+
Node = (spaces TextNode)* spaces
|
|
3
|
+
TextNode = spaces AnyExceptPlus<openControl>
|
|
4
|
+
openControl = end
|
|
5
|
+
|
|
6
|
+
empty = /* nothing */
|
|
7
|
+
anyExcept<lit> = (~ lit any)
|
|
8
|
+
anyExceptStar<lit> = (~ lit any)*
|
|
9
|
+
anyExceptPlus<lit> = (~ lit any)+
|
|
10
|
+
AnyExcept<lit> = (spaces ~ lit any)
|
|
11
|
+
AnyExceptPlus<lit> = (spaces ~ lit any)+
|
|
12
|
+
AnyExceptStar<lit> = (spaces ~ lit any)*
|
|
13
|
+
identifierCharacter = alnum | "_" | "-"
|
|
14
|
+
|
|
15
|
+
orderedListOf<a, b, sep> =
|
|
16
|
+
| nonemptyOrderedListOf<a, b, sep>
|
|
17
|
+
| emptyListOf<a, sep>
|
|
18
|
+
nonemptyOrderedListOf<a, b, sep> =
|
|
19
|
+
| nonemptyListOf<b, sep>
|
|
20
|
+
| nonemptyOrderedListOfBoth<a, b, sep>
|
|
21
|
+
| nonemptyListOf<a, sep>
|
|
22
|
+
nonemptyOrderedListOfBoth<a, b, sep> =
|
|
23
|
+
nonemptyListOf<a, sep> (sep nonemptyListOf<b, sep>)
|
|
24
|
+
|
|
25
|
+
singleQuote = "'" | "‘" | "’"
|
|
26
|
+
doubleQuote = "\"" | "“" | "”"
|
|
27
|
+
controls = "\u{007F}".."\u{009F}"
|
|
28
|
+
noncharacters = "\u{FDD0}".."\u{FDEF}"
|
|
29
|
+
newline = "\r"? "\n"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Liquid <: Helpers {
|
|
33
|
+
Node := (spaces (liquidNode | TextNode))*
|
|
34
|
+
openControl := "{{" | "{%"
|
|
35
|
+
endOfTagName = &("-%}" | "-}}" | "%}" | "}}")
|
|
36
|
+
endOfVarName = ~identifierCharacter
|
|
37
|
+
endOfIdentifier = endOfTagName | endOfVarName
|
|
38
|
+
|
|
39
|
+
liquidNode =
|
|
40
|
+
| liquidDoc
|
|
41
|
+
| liquidBlockComment
|
|
42
|
+
| liquidRawTag
|
|
43
|
+
| liquidDrop
|
|
44
|
+
| liquidTagClose
|
|
45
|
+
| liquidTagOpen
|
|
46
|
+
| liquidTag
|
|
47
|
+
| liquidInlineComment
|
|
48
|
+
|
|
49
|
+
liquidTagStrict =
|
|
50
|
+
| liquidTagAssign
|
|
51
|
+
| liquidTagBreak
|
|
52
|
+
| liquidTagContinue
|
|
53
|
+
| liquidTagCycle
|
|
54
|
+
| liquidTagContentFor
|
|
55
|
+
| liquidTagDecrement
|
|
56
|
+
| liquidTagEcho
|
|
57
|
+
| liquidTagElse
|
|
58
|
+
| liquidTagElsif
|
|
59
|
+
| liquidTagInclude
|
|
60
|
+
| liquidTagIncrement
|
|
61
|
+
| liquidTagLayout
|
|
62
|
+
| liquidTagLiquid
|
|
63
|
+
| liquidTagRender
|
|
64
|
+
| liquidTagSection
|
|
65
|
+
| liquidTagSections
|
|
66
|
+
| liquidTagWhen
|
|
67
|
+
|
|
68
|
+
liquidTag =
|
|
69
|
+
| liquidTagStrict
|
|
70
|
+
| liquidTagBaseCase
|
|
71
|
+
|
|
72
|
+
liquidTagOpenStrict =
|
|
73
|
+
| liquidTagOpenCase
|
|
74
|
+
| liquidTagOpenCapture
|
|
75
|
+
| liquidTagOpenForm
|
|
76
|
+
| liquidTagOpenFor
|
|
77
|
+
| liquidTagOpenTablerow
|
|
78
|
+
| liquidTagOpenIf
|
|
79
|
+
| liquidTagOpenPaginate
|
|
80
|
+
| liquidTagOpenUnless
|
|
81
|
+
|
|
82
|
+
liquidTagOpen =
|
|
83
|
+
| liquidTagOpenStrict
|
|
84
|
+
| liquidTagOpenBaseCase
|
|
85
|
+
|
|
86
|
+
liquidTagClose = "{%" "-"? space* "end" blockName space* tagMarkup "-"? "%}"
|
|
87
|
+
|
|
88
|
+
// These two are the same but transformed differently
|
|
89
|
+
liquidTagRule<name, markup> =
|
|
90
|
+
"{%" "-"? space* (name endOfIdentifier) space* markup "-"? "%}"
|
|
91
|
+
liquidTagOpenRule<name, markup> =
|
|
92
|
+
"{%" "-"? space* (name endOfIdentifier) space* markup "-"? "%}"
|
|
93
|
+
|
|
94
|
+
liquidTagBaseCase = liquidTagRule<liquidTagName, tagMarkup>
|
|
95
|
+
|
|
96
|
+
liquidTagEcho = liquidTagRule<"echo", liquidTagEchoMarkup>
|
|
97
|
+
liquidTagEchoMarkup = liquidVariable<delimTag>
|
|
98
|
+
|
|
99
|
+
liquidTagAssign = liquidTagRule<"assign", liquidTagAssignMarkup>
|
|
100
|
+
liquidTagAssignMarkup = variableSegment space* "=" space* liquidVariable<delimTag>
|
|
101
|
+
|
|
102
|
+
liquidTagCycle = liquidTagRule<"cycle", liquidTagCycleMarkup>
|
|
103
|
+
liquidTagCycleMarkup = (liquidExpression<delimTag> ":")? space* nonemptyListOf<liquidExpression<delimTag>, argumentSeparator> space*
|
|
104
|
+
|
|
105
|
+
liquidTagIncrement = liquidTagRule<"increment", variableSegmentAsLookupMarkup>
|
|
106
|
+
liquidTagDecrement = liquidTagRule<"decrement", variableSegmentAsLookupMarkup>
|
|
107
|
+
liquidTagOpenCapture = liquidTagOpenRule<"capture", variableSegmentAsLookupMarkup>
|
|
108
|
+
variableSegmentAsLookupMarkup = variableSegmentAsLookup space*
|
|
109
|
+
|
|
110
|
+
liquidTagSection = liquidTagRule<"section", liquidTagSectionMarkup>
|
|
111
|
+
liquidTagSectionMarkup = liquidString<delimTag> space*
|
|
112
|
+
|
|
113
|
+
liquidTagSections = liquidTagRule<"sections", liquidTagSectionsMarkup>
|
|
114
|
+
liquidTagSectionsMarkup = liquidString<delimTag> space*
|
|
115
|
+
|
|
116
|
+
liquidTagLayout = liquidTagRule<"layout", liquidTagLayoutMarkup>
|
|
117
|
+
liquidTagLayoutMarkup = liquidExpression<delimTag> space*
|
|
118
|
+
|
|
119
|
+
// We'll black hole the statement and switch parser in the cst builder
|
|
120
|
+
// We do this because it's technically the same grammar (with minor redefinitions)
|
|
121
|
+
// and it would be a huge chore and maintenance hell to rewrite all the rules with
|
|
122
|
+
// hspace = " " | "\t"
|
|
123
|
+
//
|
|
124
|
+
// The alternative is that this grammar parses the {% liquid tagMarkup %} as its own string,
|
|
125
|
+
// and then we switch to the LiquidStatement grammar that
|
|
126
|
+
// redefines liquidTagOpenRule, liquidTagRule, and space.
|
|
127
|
+
liquidTagLiquid = liquidTagRule<"liquid", liquidTagLiquidMarkup>
|
|
128
|
+
liquidTagLiquidMarkup = tagMarkup
|
|
129
|
+
|
|
130
|
+
liquidTagContentFor = liquidTagRule<"content_for", liquidTagContentForMarkup>
|
|
131
|
+
|
|
132
|
+
liquidTagContentForMarkup =
|
|
133
|
+
contentForType (argumentSeparatorOptionalComma contentForTagArgument) (space* ",")? space*
|
|
134
|
+
|
|
135
|
+
contentForTagArgument = listOf<contentForNamedArgument<delimTag>, argumentSeparatorOptionalComma>
|
|
136
|
+
completionModeContentForTagArgument = listOf<contentForNamedArgument<delimTag>, argumentSeparatorOptionalComma> (argumentSeparator? (liquidVariableLookup<delimTag>))?
|
|
137
|
+
contentForNamedArgument<delim> = (variableSegment ("." variableSegment)*) space* ":" space* (liquidExpression<delim>)
|
|
138
|
+
|
|
139
|
+
contentForType = liquidString<delimTag>
|
|
140
|
+
|
|
141
|
+
liquidTagInclude = liquidTagRule<"include", liquidTagRenderMarkup>
|
|
142
|
+
liquidTagRender = liquidTagRule<"render", liquidTagRenderMarkup>
|
|
143
|
+
liquidTagRenderMarkup =
|
|
144
|
+
snippetExpression renderVariableExpression? renderAliasExpression? renderArguments
|
|
145
|
+
|
|
146
|
+
renderArguments = (argumentSeparatorOptionalComma tagArguments) (space* ",")? space*
|
|
147
|
+
completionModeRenderArguments = (argumentSeparatorOptionalComma tagArguments) (space* ",")? space* (argumentSeparator? liquidVariableLookup<delimTag> space*)?
|
|
148
|
+
snippetExpression = liquidString<delimTag> | variableSegmentAsLookup
|
|
149
|
+
renderVariableExpression = space+ ("for" | "with") space+ liquidExpression<delimTag>
|
|
150
|
+
renderAliasExpression = space+ "as" space+ variableSegment
|
|
151
|
+
|
|
152
|
+
liquidTagOpenBaseCase = liquidTagOpenRule<blockName, tagMarkup>
|
|
153
|
+
|
|
154
|
+
liquidTagOpenForm = liquidTagOpenRule<"form", liquidTagOpenFormMarkup>
|
|
155
|
+
liquidTagOpenFormMarkup = arguments<delimTag> (space* ",")? space*
|
|
156
|
+
|
|
157
|
+
liquidTagOpenFor = liquidTagOpenRule<"for", liquidTagOpenForMarkup>
|
|
158
|
+
liquidTagOpenForMarkup =
|
|
159
|
+
variableSegment space* "in" space* liquidExpression<delimTag>
|
|
160
|
+
(space* "reversed")? argumentSeparatorOptionalComma
|
|
161
|
+
tagArguments (space* ",")? space*
|
|
162
|
+
|
|
163
|
+
// It's the same, the difference is support for different named arguments<delim>
|
|
164
|
+
liquidTagOpenTablerow = liquidTagOpenRule<"tablerow", liquidTagOpenForMarkup>
|
|
165
|
+
|
|
166
|
+
liquidTagOpenCase = liquidTagOpenRule<"case", liquidTagOpenCaseMarkup>
|
|
167
|
+
liquidTagOpenCaseMarkup = liquidExpression<delimTag> space*
|
|
168
|
+
|
|
169
|
+
liquidTagWhen = liquidTagRule<"when", liquidTagWhenMarkup>
|
|
170
|
+
liquidTagWhenMarkup = nonemptyListOf<liquidExpression<delimTag>, whenMarkupSep> space*
|
|
171
|
+
whenMarkupSep = space* ("," | "or" ~identifier) space*
|
|
172
|
+
|
|
173
|
+
liquidTagOpenIf = liquidTagOpenRule<"if", liquidTagOpenConditionalMarkup>
|
|
174
|
+
liquidTagOpenUnless = liquidTagOpenRule<"unless", liquidTagOpenConditionalMarkup>
|
|
175
|
+
liquidTagElsif = liquidTagRule<"elsif", liquidTagOpenConditionalMarkup>
|
|
176
|
+
|
|
177
|
+
liquidTagBreak = liquidTagRule<"break", empty>
|
|
178
|
+
liquidTagContinue = liquidTagRule<"continue", empty>
|
|
179
|
+
liquidTagElse = liquidTagRule<"else", empty>
|
|
180
|
+
|
|
181
|
+
liquidTagOpenConditionalMarkup = nonemptyListOf<condition<delimTag>, conditionSeparator> space*
|
|
182
|
+
conditionSeparator = &logicalOperator
|
|
183
|
+
condition<delim> = logicalOperator? space* (comparison<delim> | liquidExpression<delim>) space*
|
|
184
|
+
logicalOperator = ("and" | "or") ~identifier
|
|
185
|
+
comparison<delim> = liquidExpression<delim> space* comparator space* liquidExpression<delim>
|
|
186
|
+
comparator =
|
|
187
|
+
( "=="
|
|
188
|
+
| "!="
|
|
189
|
+
| ">="
|
|
190
|
+
| "<="
|
|
191
|
+
| ">"
|
|
192
|
+
| "<")
|
|
193
|
+
| ("contains" ~identifier)
|
|
194
|
+
|
|
195
|
+
liquidTagOpenPaginate = liquidTagOpenRule<"paginate", liquidTagOpenPaginateMarkup>
|
|
196
|
+
liquidTagOpenPaginateMarkup =
|
|
197
|
+
liquidExpression<delimTag> space+ "by" space+ liquidExpression<delimTag> argumentSeparatorOptionalComma tagArguments (space* ",")? space*
|
|
198
|
+
|
|
199
|
+
liquidDrop = "{{" "-"? space* liquidDropCases "-"? "}}"
|
|
200
|
+
liquidDropCases = liquidVariable<delimVO> | liquidDropBaseCase
|
|
201
|
+
liquidDropBaseCase = anyExceptStar<delimVO>
|
|
202
|
+
liquidInlineComment = "{%" "-"? space* "#" space? tagMarkup "-"? "%}"
|
|
203
|
+
|
|
204
|
+
liquidRawTag =
|
|
205
|
+
| liquidRawTagImpl<"raw">
|
|
206
|
+
| liquidRawTagImpl<"javascript">
|
|
207
|
+
| liquidRawTagImpl<"schema">
|
|
208
|
+
| liquidRawTagImpl<"stylesheet">
|
|
209
|
+
| liquidRawTagImpl<"style">
|
|
210
|
+
liquidRawTagImpl<name> =
|
|
211
|
+
"{%" "-"? space* (name endOfIdentifier) space* tagMarkup "-"? "%}"
|
|
212
|
+
anyExceptStar<liquidRawTagClose<name>>
|
|
213
|
+
"{%" "-"? space* "end" (name endOfIdentifier) space* "-"? "%}"
|
|
214
|
+
liquidRawTagClose<name> =
|
|
215
|
+
"{%" "-"? space* "end" (name endOfIdentifier) space* "-"? "%}"
|
|
216
|
+
|
|
217
|
+
liquidBlockComment =
|
|
218
|
+
commentBlockStart
|
|
219
|
+
(liquidBlockComment | anyExceptPlus<commentBlockStart> | anyExceptPlus<commentBlockEnd>)*
|
|
220
|
+
commentBlockEnd
|
|
221
|
+
commentBlockStart = "{%" "-"? space* ("comment" endOfIdentifier) space* tagMarkup "-"? "%}"
|
|
222
|
+
commentBlockEnd = "{%" "-"? space* ("endcomment" endOfIdentifier) space* tagMarkup "-"? "%}"
|
|
223
|
+
|
|
224
|
+
liquidDoc =
|
|
225
|
+
liquidDocStart
|
|
226
|
+
liquidDocBody
|
|
227
|
+
liquidDocEnd
|
|
228
|
+
|
|
229
|
+
liquidDocStart = "{%" "-"? space* ("doc" endOfIdentifier) space* tagMarkup "-"? "%}"
|
|
230
|
+
liquidDocEnd = "{%" "-"? space* ("enddoc" endOfIdentifier) space* tagMarkup "-"? "%}"
|
|
231
|
+
liquidDocBody = anyExceptStar<liquidDocStart> | anyExceptStar<liquidDocEnd>
|
|
232
|
+
|
|
233
|
+
// In order for the grammar to "fallback" to the base case, this
|
|
234
|
+
// rule must pass if and only if we support what we parse. This
|
|
235
|
+
// implies that—since we don't support filters yet—we have a
|
|
236
|
+
// positive lookahead on "-}}" or "}}" in the rule. We do this
|
|
237
|
+
// because we'd otherwise positively match the following string
|
|
238
|
+
// instead of falling back to the other rule:
|
|
239
|
+
// {{ 'string' | some_filter }}
|
|
240
|
+
liquidVariable<delim> = liquidExpression<delim> liquidFilter<delim>* space* &delim
|
|
241
|
+
|
|
242
|
+
liquidExpression<delim> =
|
|
243
|
+
| liquidString<delim>
|
|
244
|
+
| liquidNumber
|
|
245
|
+
| liquidLiteral
|
|
246
|
+
| liquidRange<delim>
|
|
247
|
+
| liquidVariableLookup<delim>
|
|
248
|
+
|
|
249
|
+
liquidString<delim> = liquidSingleQuotedString<delim> | liquidDoubleQuotedString<delim>
|
|
250
|
+
liquidSingleQuotedString<delim> = "'" (anyExceptStar<"'"> | anyExceptStar<delim>) "'"
|
|
251
|
+
liquidDoubleQuotedString<delim> = "\"" (anyExceptStar<"\""> | anyExceptStar<delim>) "\""
|
|
252
|
+
|
|
253
|
+
liquidNumber = liquidFloat | liquidInteger
|
|
254
|
+
liquidInteger = "-"? digit+
|
|
255
|
+
liquidFloat = "-"? digit+ "." digit+
|
|
256
|
+
|
|
257
|
+
liquidLiteral =
|
|
258
|
+
( "true"
|
|
259
|
+
| "false"
|
|
260
|
+
| "blank"
|
|
261
|
+
| "empty"
|
|
262
|
+
| "nil"
|
|
263
|
+
| "null"
|
|
264
|
+
) endOfIdentifier
|
|
265
|
+
|
|
266
|
+
liquidRange<delim> =
|
|
267
|
+
"(" space* liquidExpression<delim> space* ".." space* liquidExpression<delim> space* ")"
|
|
268
|
+
|
|
269
|
+
liquidVariableLookup<delim> =
|
|
270
|
+
| variableSegment lookup<delim>*
|
|
271
|
+
| empty lookup<delim>+
|
|
272
|
+
lookup<delim> =
|
|
273
|
+
| indexLookup<delim>
|
|
274
|
+
| dotLookup
|
|
275
|
+
indexLookup<delim> = space* "[" space* liquidExpression<delim> space* "]"
|
|
276
|
+
dotLookup = space* "." space* identifier
|
|
277
|
+
|
|
278
|
+
liquidFilter<delim> = space* "|" space* identifier (space* ":" space* arguments<delim> (space* ",")?)?
|
|
279
|
+
|
|
280
|
+
arguments<delim> = nonemptyOrderedListOf<positionalArgument<delim>, namedArgument<delim>, argumentSeparator>
|
|
281
|
+
argumentSeparator = space* "," space*
|
|
282
|
+
argumentSeparatorOptionalComma = space* ","? space*
|
|
283
|
+
positionalArgument<delim> = liquidExpression<delim> ~(space* ":")
|
|
284
|
+
namedArgument<delim> = variableSegment space* ":" space* liquidExpression<delim>
|
|
285
|
+
tagArguments = listOf<namedArgument<delimTag>, argumentSeparatorOptionalComma>
|
|
286
|
+
filterArguments<delim> =
|
|
287
|
+
| complexArguments<delim>
|
|
288
|
+
| simpleArgument<delim>
|
|
289
|
+
complexArguments<delim> = arguments<delim> (space* "," space* simpleArgument<delim>)?
|
|
290
|
+
simpleArgument<delim> = liquidVariableLookup<delim>
|
|
291
|
+
|
|
292
|
+
variableSegment = (letter | "_") (~endOfTagName identifierCharacter)*
|
|
293
|
+
variableSegmentAsLookup = variableSegment
|
|
294
|
+
identifier = variableSegment "?"?
|
|
295
|
+
|
|
296
|
+
tagMarkup = anyExceptStar<delimTag>
|
|
297
|
+
|
|
298
|
+
liquidTagName =
|
|
299
|
+
letter (alnum | "_")*
|
|
300
|
+
|
|
301
|
+
blockName =
|
|
302
|
+
// Shopify blocks
|
|
303
|
+
( "form"
|
|
304
|
+
| "paginate"
|
|
305
|
+
// Base blocks
|
|
306
|
+
| "capture"
|
|
307
|
+
| "case"
|
|
308
|
+
| "for"
|
|
309
|
+
| "ifchanged"
|
|
310
|
+
| "if"
|
|
311
|
+
| "unless"
|
|
312
|
+
| "tablerow"
|
|
313
|
+
) endOfIdentifier
|
|
314
|
+
|
|
315
|
+
delimTag = "-%}" | "%}"
|
|
316
|
+
delimVO = "-}}" | "}}"
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
LiquidStatement <: Liquid {
|
|
320
|
+
Node := spaces listOf<LiquidStatement, statementSep> (space | newline)* spaces
|
|
321
|
+
|
|
322
|
+
// This is the big brains moment: we redefine space to exclude newlines.
|
|
323
|
+
//
|
|
324
|
+
// Which means that all our other Liquid rules can be reused
|
|
325
|
+
// without modification(!)
|
|
326
|
+
//
|
|
327
|
+
// We don't need to maintain rules like this:
|
|
328
|
+
// - liquidVariable<space>
|
|
329
|
+
// - liquidExpression<space>
|
|
330
|
+
// - variableLookup<space>
|
|
331
|
+
// - ... long list of stuff that takes space as param
|
|
332
|
+
// - liquidString<space>
|
|
333
|
+
//
|
|
334
|
+
// All we need is this little, VERY IMPORTANT, part right here that
|
|
335
|
+
// make it so we can parse the same way in Liquid tags.
|
|
336
|
+
//
|
|
337
|
+
// I'm putting in this huge comment so that it's more obvious.
|
|
338
|
+
space := " " | "\t"
|
|
339
|
+
|
|
340
|
+
LiquidStatement =
|
|
341
|
+
| spaces liquidBlockComment
|
|
342
|
+
| spaces liquidRawTag
|
|
343
|
+
| spaces liquidTagClose
|
|
344
|
+
| spaces liquidTagOpen
|
|
345
|
+
| spaces liquidTag
|
|
346
|
+
| spaces liquidInlineComment
|
|
347
|
+
|
|
348
|
+
liquidTagOpenRule<name, markup>
|
|
349
|
+
:= (name ~identifierCharacter) space* markup &liquidStatementEnd
|
|
350
|
+
|
|
351
|
+
liquidTagRule<name, markup>
|
|
352
|
+
:= (name ~identifierCharacter) space* markup &liquidStatementEnd
|
|
353
|
+
|
|
354
|
+
liquidTagClose
|
|
355
|
+
:= "end" (blockName ~identifierCharacter) space* tagMarkup &liquidStatementEnd
|
|
356
|
+
|
|
357
|
+
liquidRawTagImpl<name>
|
|
358
|
+
:= (name ~identifierCharacter) space* tagMarkup newline
|
|
359
|
+
anyExceptStar<liquidRawTagClose<name>>
|
|
360
|
+
"end" name space* &liquidStatementEnd
|
|
361
|
+
|
|
362
|
+
liquidRawTagClose<name>
|
|
363
|
+
:= "end" name space* &liquidStatementEnd
|
|
364
|
+
|
|
365
|
+
liquidBlockComment :=
|
|
366
|
+
commentBlockStart statementSep
|
|
367
|
+
(listOf<liquidCommentBlockStatement, statementSep> statementSep)?
|
|
368
|
+
commentBlockEnd
|
|
369
|
+
|
|
370
|
+
liquidCommentBlockStatement =
|
|
371
|
+
| liquidBlockComment
|
|
372
|
+
| nonTerminalCommentLine
|
|
373
|
+
|
|
374
|
+
commentBlockStart
|
|
375
|
+
:= ("comment" ~identifierCharacter) space* tagMarkup
|
|
376
|
+
|
|
377
|
+
commentBlockEnd
|
|
378
|
+
:= ("endcomment" ~identifierCharacter) space* tagMarkup
|
|
379
|
+
|
|
380
|
+
nonTerminalCommentLine
|
|
381
|
+
= ~commentBlockEnd anyExceptPlus<newline>
|
|
382
|
+
|
|
383
|
+
liquidInlineComment
|
|
384
|
+
:= "#" space? tagMarkup &liquidStatementEnd
|
|
385
|
+
|
|
386
|
+
tagMarkup := anyExceptStar<liquidStatementEnd>
|
|
387
|
+
|
|
388
|
+
// trailing whitespace, newline, + anything else before the next tag
|
|
389
|
+
statementSep = space* newline (space | newline)*
|
|
390
|
+
|
|
391
|
+
liquidStatementEnd = newline | end
|
|
392
|
+
delimTag := liquidStatementEnd
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
LiquidDoc <: Helpers {
|
|
396
|
+
Node := spaces ImplicitDescription (spaces (LiquidDocNode | TextNode))* spaces
|
|
397
|
+
LiquidDocNode =
|
|
398
|
+
| paramNode
|
|
399
|
+
| exampleNode
|
|
400
|
+
| descriptionNode
|
|
401
|
+
| fallbackNode
|
|
402
|
+
|
|
403
|
+
endOfDescription = strictSpace* openControl
|
|
404
|
+
descriptionContent = anyExceptStar<endOfDescription>
|
|
405
|
+
ImplicitDescription = descriptionContent
|
|
406
|
+
|
|
407
|
+
// By default, space matches new lines as well. We override it here to make writing rules easier.
|
|
408
|
+
strictSpace = " " | "\t"
|
|
409
|
+
// We use this as an escape hatch to stop matching TextNode and try again when one of these characters is encountered
|
|
410
|
+
openControl:= "@" | end
|
|
411
|
+
|
|
412
|
+
descriptionNode = "@description" space* descriptionContent
|
|
413
|
+
|
|
414
|
+
paramNode = "@param" strictSpace* paramType? strictSpace* (optionalParamName | paramName) (strictSpace* "-")? strictSpace* paramDescription
|
|
415
|
+
paramType = "{" strictSpace* paramTypeContent strictSpace* "}"
|
|
416
|
+
paramTypeContent = anyExceptStar<("}"| strictSpace)>
|
|
417
|
+
|
|
418
|
+
paramName = textValue
|
|
419
|
+
optionalParamName = "[" strictSpace* textValue strictSpace* "]"
|
|
420
|
+
textValue = identifierCharacter+
|
|
421
|
+
|
|
422
|
+
paramDescription = (~"]" anyExceptStar<endOfParam>)
|
|
423
|
+
endOfParam = strictSpace* (newline | end)
|
|
424
|
+
|
|
425
|
+
exampleNode = "@example" space* exampleContent
|
|
426
|
+
exampleContent = anyExceptStar<endOfExample>
|
|
427
|
+
endOfExample = strictSpace* ("@" | end)
|
|
428
|
+
|
|
429
|
+
fallbackNode = "@" anyExceptStar<endOfParam>
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
LiquidHTML <: Liquid {
|
|
433
|
+
Node := yamlFrontmatter? (spaces (HtmlNode | liquidNode | TextNode))*
|
|
434
|
+
openControl += "<"
|
|
435
|
+
|
|
436
|
+
yamlFrontmatter =
|
|
437
|
+
"---" newline anyExceptStar<"---"> "---" newline
|
|
438
|
+
|
|
439
|
+
HtmlNode =
|
|
440
|
+
| HtmlDoctype
|
|
441
|
+
| HtmlComment
|
|
442
|
+
| HtmlRawTag
|
|
443
|
+
| HtmlVoidElement
|
|
444
|
+
| HtmlSelfClosingElement
|
|
445
|
+
| HtmlTagClose
|
|
446
|
+
| HtmlTagOpen
|
|
447
|
+
|
|
448
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#the-doctype
|
|
449
|
+
HtmlDoctype =
|
|
450
|
+
"<!" ("doctype"|"DOCTYPE") space+ ("html"|"HTML") spaces legacyDoctypeString? spaces ">"
|
|
451
|
+
legacyDoctypeString
|
|
452
|
+
= anyExceptPlus<">">
|
|
453
|
+
|
|
454
|
+
HtmlComment = "<!--" anyExceptStar<"-->"> "-->"
|
|
455
|
+
|
|
456
|
+
// These are black holes, we'll ignore what's in them
|
|
457
|
+
HtmlRawTag =
|
|
458
|
+
| HtmlRawTagImpl<"script">
|
|
459
|
+
| HtmlRawTagImpl<"style">
|
|
460
|
+
| HtmlRawTagImpl<"svg">
|
|
461
|
+
|
|
462
|
+
HtmlRawTagImpl<name> =
|
|
463
|
+
spaces TagStart<name>
|
|
464
|
+
(spaces (HtmlRawTagImpl<name> | AnyExceptPlus<TagStartorEnd<name>>))*
|
|
465
|
+
spaces TagEnd<name>
|
|
466
|
+
TagStart<name> = spaces "<" spaces name spaces AttrList spaces ">"
|
|
467
|
+
TagEnd<name> = spaces "</" spaces name spaces ">"
|
|
468
|
+
TagStartorEnd<name> = TagStart<name> | TagEnd<name>
|
|
469
|
+
|
|
470
|
+
HtmlVoidElement =
|
|
471
|
+
spaces "<" voidElementName &(space | "/" | ">") spaces AttrList spaces "/"? spaces ">"
|
|
472
|
+
|
|
473
|
+
HtmlSelfClosingElement =
|
|
474
|
+
spaces "<" tagName spaces AttrList spaces "/>"
|
|
475
|
+
|
|
476
|
+
HtmlTagOpen =
|
|
477
|
+
spaces "<" tagName spaces AttrList spaces ">"
|
|
478
|
+
|
|
479
|
+
HtmlTagClose =
|
|
480
|
+
spaces "</" tagName spaces ">"
|
|
481
|
+
|
|
482
|
+
tagName = leadingTagNamePart trailingTagNamePart*
|
|
483
|
+
|
|
484
|
+
// The difference here is that the first text part must start
|
|
485
|
+
// with a letter, but trailing text parts don't have that
|
|
486
|
+
// requirement
|
|
487
|
+
leadingTagNamePart =
|
|
488
|
+
| liquidDrop
|
|
489
|
+
| leadingTagNameTextNode
|
|
490
|
+
|
|
491
|
+
trailingTagNamePart =
|
|
492
|
+
| liquidDrop
|
|
493
|
+
| trailingTagNameTextNode
|
|
494
|
+
|
|
495
|
+
leadingTagNameTextNode = letter (alnum | "-" | ":")*
|
|
496
|
+
trailingTagNameTextNode = (alnum | "-" | ":")+
|
|
497
|
+
|
|
498
|
+
AttrList = (spaces Attr)*
|
|
499
|
+
|
|
500
|
+
Attr =
|
|
501
|
+
spaces (AttrSingleQuoted | AttrDoubleQuoted | AttrUnquoted | liquidNode | attrEmpty)
|
|
502
|
+
|
|
503
|
+
attrEmpty = attrName
|
|
504
|
+
|
|
505
|
+
AttrUnquoted = spaces attrName spaces "=" spaces attrUnquotedValue
|
|
506
|
+
AttrSingleQuoted = spaces attrName spaces "=" spaces singleQuote attrSingleQuotedValue singleQuote
|
|
507
|
+
AttrDoubleQuoted = spaces attrName spaces "=" spaces doubleQuote attrDoubleQuotedValue doubleQuote
|
|
508
|
+
|
|
509
|
+
attrName = (liquidDrop | attrNameTextNode)+
|
|
510
|
+
|
|
511
|
+
// https://html.spec.whatwg.org/#attributes-2
|
|
512
|
+
fake1 = space | quotes | "=" | ">" | "/>" | "{{" | "{%" | controls | noncharacters
|
|
513
|
+
attrNameTextNode = anyExceptPlus<fake1>
|
|
514
|
+
attrUnquotedValue = (liquidDrop | attrUnquotedTextNode)*
|
|
515
|
+
attrSingleQuotedValue = (liquidNode | attrSingleQuotedTextNode)*
|
|
516
|
+
attrDoubleQuotedValue = (liquidNode | attrDoubleQuotedTextNode)*
|
|
517
|
+
|
|
518
|
+
fake2 = space | quotes | "=" | "<" | ">" | "`" | "{{" | "{%"
|
|
519
|
+
attrUnquotedTextNode = anyExceptPlus<fake2>
|
|
520
|
+
fake3 = singleQuote | "{{" | "{%"
|
|
521
|
+
fake4 = doubleQuote | "{{" | "{%"
|
|
522
|
+
attrSingleQuotedTextNode = anyExceptPlus<fake3>
|
|
523
|
+
attrDoubleQuotedTextNode = anyExceptPlus<fake4>
|
|
524
|
+
|
|
525
|
+
quotes = singleQuote | doubleQuote
|
|
526
|
+
|
|
527
|
+
// https://www.w3.org/TR/2011/WD-html-markup-20110113/syntax.html#void-element
|
|
528
|
+
voidElementName =
|
|
529
|
+
( "area"
|
|
530
|
+
| "base"
|
|
531
|
+
| "br"
|
|
532
|
+
| "col"
|
|
533
|
+
| "command"
|
|
534
|
+
| "embed"
|
|
535
|
+
| "hr"
|
|
536
|
+
| "img"
|
|
537
|
+
| "input"
|
|
538
|
+
| "keygen"
|
|
539
|
+
| "link"
|
|
540
|
+
| "meta"
|
|
541
|
+
| "param"
|
|
542
|
+
| "source"
|
|
543
|
+
| "track"
|
|
544
|
+
| "wbr"
|
|
545
|
+
) ~identifierCharacter
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
StrictLiquid <: Liquid {
|
|
549
|
+
liquidTag := liquidTagStrict
|
|
550
|
+
liquidTagOpen := liquidTagOpenStrict
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
StrictLiquidStatement <: LiquidStatement {
|
|
554
|
+
liquidTag := liquidTagStrict
|
|
555
|
+
liquidTagOpen := liquidTagOpenStrict
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
StrictLiquidHTML <: LiquidHTML {
|
|
559
|
+
liquidTag := liquidTagStrict
|
|
560
|
+
liquidTagOpen := liquidTagOpenStrict
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
WithPlaceholderLiquid <: Liquid {
|
|
564
|
+
liquidFilter<delim> := space* "|" space* identifier (space* ":" space* filterArguments<delim> (space* ",")?)?
|
|
565
|
+
liquidTagContentForMarkup :=
|
|
566
|
+
contentForType (argumentSeparatorOptionalComma completionModeContentForTagArgument) (space* ",")? space*
|
|
567
|
+
liquidTagRenderMarkup :=
|
|
568
|
+
snippetExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
|
|
569
|
+
liquidTagName := (letter | "█") (alnum | "_")*
|
|
570
|
+
variableSegment := (letter | "_" | "█") (identifierCharacter | "█")*
|
|
571
|
+
liquidDoc :=
|
|
572
|
+
liquidDocStart
|
|
573
|
+
liquidDocBody
|
|
574
|
+
liquidDocEnd?
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
WithPlaceholderLiquidStatement <: LiquidStatement {
|
|
578
|
+
liquidFilter<delim> := space* "|" space* identifier (space* ":" space* filterArguments<delim> (space* ",")?)?
|
|
579
|
+
liquidTagContentForMarkup :=
|
|
580
|
+
contentForType (argumentSeparatorOptionalComma completionModeContentForTagArgument) (space* ",")? space*
|
|
581
|
+
liquidTagRenderMarkup :=
|
|
582
|
+
snippetExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
|
|
583
|
+
liquidTagName := (letter | "█") (alnum | "_")*
|
|
584
|
+
variableSegment := (letter | "_" | "█") (identifierCharacter | "█")*
|
|
585
|
+
liquidDoc :=
|
|
586
|
+
liquidDocStart
|
|
587
|
+
liquidDocBody
|
|
588
|
+
liquidDocEnd?
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
WithPlaceholderLiquidHTML <: LiquidHTML {
|
|
592
|
+
liquidFilter<delim> := space* "|" space* identifier (space* ":" space* filterArguments<delim> (space* ",")?)?
|
|
593
|
+
liquidTagContentForMarkup :=
|
|
594
|
+
contentForType (argumentSeparatorOptionalComma completionModeContentForTagArgument) (space* ",")? space*
|
|
595
|
+
liquidTagRenderMarkup :=
|
|
596
|
+
snippetExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
|
|
597
|
+
liquidTagName := (letter | "█") (alnum | "_")*
|
|
598
|
+
variableSegment := (letter | "_" | "█") (identifierCharacter | "█")*
|
|
599
|
+
leadingTagNameTextNode := (letter | "█") (alnum | "-" | ":" | "█")*
|
|
600
|
+
trailingTagNameTextNode := (alnum | "-" | ":" | "█")+
|
|
601
|
+
liquidDoc :=
|
|
602
|
+
liquidDocStart
|
|
603
|
+
liquidDocBody
|
|
604
|
+
liquidDocEnd?
|
|
605
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Ohm-WASM Go Integration
|
|
2
|
+
|
|
3
|
+
This directory contains a Go implementation for running Ohm grammars compiled to WebAssembly. It provides a simple API to load grammar modules, match input against them, and access the resulting concrete syntax trees.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The implementation consists of two main components:
|
|
8
|
+
|
|
9
|
+
1. **matcher.go**: A Go implementation of the JavaScript `WasmMatcher` class from the Ohm `wasm` package
|
|
10
|
+
2. **testmain.go**: A command-line program that demonstrates how to use the WasmMatcher
|
|
11
|
+
|
|
12
|
+
## WasmMatcher
|
|
13
|
+
|
|
14
|
+
The `WasmMatcher` class provides a high-level API for working with Ohm grammars compiled to WebAssembly:
|
|
15
|
+
|
|
16
|
+
```go
|
|
17
|
+
// Create a new matcher
|
|
18
|
+
matcher := NewWasmMatcher(ctx)
|
|
19
|
+
|
|
20
|
+
// Load a grammar module
|
|
21
|
+
err := matcher.LoadModule("path/to/grammar.wasm")
|
|
22
|
+
|
|
23
|
+
// Set input text
|
|
24
|
+
matcher.SetInput("text to match")
|
|
25
|
+
|
|
26
|
+
// Match against the grammar
|
|
27
|
+
success, err := matcher.Match()
|
|
28
|
+
|
|
29
|
+
// Match against a specific rule
|
|
30
|
+
success, err := matcher.MatchRule("specificRule")
|
|
31
|
+
|
|
32
|
+
// Access the concrete syntax tree
|
|
33
|
+
cstRoot, err := matcher.GetCstRoot()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Command-Line Usage
|
|
37
|
+
|
|
38
|
+
You can use the command-line program to test Ohm grammars:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
# Test the simple add function (automatically detected)
|
|
42
|
+
./testmain -wasm ../data/_add.wasm
|
|
43
|
+
|
|
44
|
+
# Match input against a grammar
|
|
45
|
+
./testmain -wasm path/to/grammar.wasm -input "text to match"
|
|
46
|
+
|
|
47
|
+
# Specify a start rule
|
|
48
|
+
./testmain -wasm path/to/grammar.wasm -input "text to match" -rule "StartRule"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Example with ES5 Grammar
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
./testmain -wasm ../data/_es5.wasm -input "var x = 3;"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Build Instructions
|
|
58
|
+
|
|
59
|
+
Use the Makefile in the parent directory to build and test:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
# Build the testmain program
|
|
63
|
+
make test/go/testmain
|
|
64
|
+
|
|
65
|
+
# Run the test with the ES5 grammar
|
|
66
|
+
make go-test-es5
|
|
67
|
+
```
|