@felixtensor/tree-sitter-mlir 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/grammar.js ADDED
@@ -0,0 +1,506 @@
1
+ /// <reference types="tree-sitter-cli/dsl" />
2
+ // @ts-check
3
+
4
+ export default grammar({
5
+ name: 'mlir',
6
+ extras: $ => [/\s/, $.comment],
7
+ conflicts: $ => [
8
+ [$._static_dim_list, $._static_dim_list],
9
+ [$.dictionary_attribute, $.region],
10
+ [$.custom_op_name, $.attribute_entry],
11
+ [$.type_alias, $.dialect_namespace],
12
+ [$.dialect_namespace, $.attribute_alias],
13
+ [$.pretty_dialect_item],
14
+ [$.array_literal, $._custom_body_element],
15
+ [$._value_use_list, $._value_use_and_type],
16
+ [$._type_list_no_parens, $._type_or_func_type],
17
+ [$._type_list_parens, $._multi_dim_affine_expr_parens],
18
+ ],
19
+
20
+ // Token-level precedence constants (higher wins the token race):
21
+ // 20 — Tier-1 structural op keywords (func.func, llvm.func, module, builtin.module)
22
+ // Must beat _dotted_op_name (10) so the parser treats these as Tier-1 ops,
23
+ // not as generic dialect.op names.
24
+ // 10 — Tier-2 _dotted_op_name / _bare_op_name
25
+ // Must beat bare_id so op names at the start of a body element close
26
+ // the previous operation rather than extending it.
27
+ // 5 — Builtin type tokens (i32, f32, index, none, …)
28
+ // Must beat bare_id so primitive type names aren't swallowed as keywords.
29
+ // 2 — $.type inside _custom_body_element
30
+ // Gives type nodes priority over other body elements when both are
31
+ // syntactically valid.
32
+ rules: {
33
+ // =========================================================================
34
+ // Top level production:
35
+ // (operation | attribute-alias-def | type-alias-def)
36
+ // =========================================================================
37
+ toplevel: $ => seq($._toplevel, repeat($._toplevel)),
38
+ _toplevel: $ => choice($.operation, $.attribute_alias_def, $.type_alias_def,
39
+ $.external_resources),
40
+ external_resources: $ => seq('{-#', repeat($._pretty_dialect_item_contents), '#-}'),
41
+
42
+ // =========================================================================
43
+ // Common syntax (lang-ref)
44
+ // integer-literal ::= decimal-literal | hexadecimal-literal
45
+ // decimal-literal ::= digit+
46
+ // hexadecimal-literal ::= `0x` hex_digit+
47
+ // float-literal ::= [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?
48
+ // string-literal ::= `"` [^"\n\f\v\r]* `"`
49
+ // =========================================================================
50
+ _digit: $ => /[0-9]/,
51
+ integer_literal: $ => choice($._decimal_literal, $._hexadecimal_literal),
52
+ _decimal_literal: $ => token(seq(optional(/[-+]/), repeat1(/[0-9]/))),
53
+ _hexadecimal_literal: $ => token(seq('0x', repeat1(/[0-9a-fA-F]/))),
54
+ float_literal: $ => token(seq(
55
+ optional(/[-+]/), repeat1(/[0-9]/), '.', repeat(/[0-9]/),
56
+ optional(seq(/[eE]/, optional(/[-+]/), repeat1(/[0-9]/))))),
57
+ string_literal: $ => seq(
58
+ '"',
59
+ repeat(choice(/[^\\"\n\f\v\r]+/, $.escape_sequence, $.invalid_escape)),
60
+ '"'
61
+ ),
62
+ escape_sequence: $ => token(seq('\\', choice(/[nt"\\]/, /[0-9a-fA-F]{2}/))),
63
+ invalid_escape: $ => token(seq('\\', /[^\n\f\v\r]/)),
64
+ bool_literal: $ => token(choice('true', 'false')),
65
+ unit_literal: $ => token('unit'),
66
+ uninitialized_literal: $ => token('uninitialized'),
67
+ complex_literal: $ => seq('(', choice($.integer_literal, $.float_literal, $.bool_literal), ',',
68
+ choice($.integer_literal, $.float_literal, $.bool_literal), ')'),
69
+ tensor_literal: $ => seq(token(choice('dense', 'sparse')), '<',
70
+ optional(seq(
71
+ optional(seq($.type, ':')),
72
+ seq($._tensor_literal_element, repeat(seq(',', $._tensor_literal_element)))
73
+ )), '>'),
74
+ _tensor_literal_element: $ => choice($.nested_idx_list, $._primitive_element),
75
+ array_literal: $ => seq(token('array'), '<', $.type, optional(seq(':', $._idx_list)), '>'),
76
+ _literal: $ => choice($.integer_literal, $.float_literal, $.string_literal, $.bool_literal,
77
+ $.tensor_literal, $.array_literal, $.unit_literal, $.uninitialized_literal),
78
+
79
+ nested_idx_list: $ => seq('[', optional(choice($.nested_idx_list, $._idx_list)),
80
+ repeat(seq(',', $.nested_idx_list)), ']'),
81
+ _idx_list: $ => prec.right(seq($._primitive_element,
82
+ repeat(seq(',', $._primitive_element)))),
83
+ _primitive_element: $ => seq($._primitive_idx_literal, optional(seq(':', $.type))),
84
+ _primitive_idx_literal: $ => choice($.integer_literal, $.float_literal,
85
+ $.bool_literal, $.complex_literal, $.string_literal),
86
+
87
+ // =========================================================================
88
+ // Identifiers
89
+ // bare-id ::= (letter|[_]) (letter|digit|[_$.])*
90
+ // value-id ::= `%` suffix-id
91
+ // suffix-id ::= (digit+ | ((letter|id-punct) (letter|id-punct|digit)*))
92
+ // symbol-ref-id ::= `@` (suffix-id | string-literal) (`::` symbol-ref-id)?
93
+ // =========================================================================
94
+ bare_id: $ => token(seq(/[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$.]/))),
95
+ _alias_or_dialect_id: $ => token(seq(/[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$]/))),
96
+ bare_id_list: $ => seq($.bare_id, repeat(seq(',', $.bare_id))),
97
+ value_use: $ => seq('%', $._suffix_id),
98
+ _suffix_id: $ => token(seq(choice(repeat1(/[0-9]/),
99
+ seq(/[a-zA-Z_$.-]/, repeat(/[a-zA-Z0-9_$.-]/))),
100
+ optional(seq(choice(':', '#'), repeat1(/[0-9]/))))),
101
+ symbol_ref_id: $ => seq('@', choice($._suffix_id, $.string_literal),
102
+ optional(seq('::', $.symbol_ref_id))),
103
+ _value_use_list: $ => seq($.value_use, repeat(seq(',', $.value_use))),
104
+
105
+ // =========================================================================
106
+ // Operations
107
+ // operation ::= op-result-list? (generic-operation |
108
+ // custom-operation) trailing-location?
109
+ // generic-operation ::= string-literal `(` value-use-list? `)`
110
+ // successor-list? properties? region-list?
111
+ // dictionary-attribute? `:` function-type
112
+ // custom-operation ::= bare-id custom-operation-format
113
+ // =========================================================================
114
+ operation: $ => seq(
115
+ field('lhs', optional($._op_result_list)),
116
+ field('rhs', choice($.generic_operation, $.custom_operation)),
117
+ field('location', optional($.trailing_location))),
118
+
119
+ generic_operation: $ =>
120
+ seq($.string_literal, $._value_use_list_parens, optional($._successor_list),
121
+ optional($.properties), optional($._region_list), optional($.attribute),
122
+ ':', $.function_type),
123
+
124
+ _op_result_list: $ => seq($.op_result, repeat(seq(',', $.op_result)), '='),
125
+ op_result: $ => seq($.value_use, optional(seq(':', $.integer_literal))),
126
+ _successor_list: $ => seq('[', $.successor, repeat(seq(',', $.successor)), ']'),
127
+ successor: $ => prec.right(seq($.caret_id, optional($._value_arg_list))),
128
+ _region_list: $ => seq('(', $.region, repeat(seq(',', $.region)), ')'),
129
+ properties: $ => seq('<{', optional($.attribute_entry),
130
+ repeat(seq(',', $.attribute_entry)), '}>'),
131
+ dictionary_attribute: $ => seq('{', optional($.attribute_entry),
132
+ repeat(seq(',', $.attribute_entry)), '}'),
133
+ trailing_location: $ => seq(token('loc'), '(', $.location, ')'),
134
+ // LangRef "Source Locations": location ::= unknown | name | filelinecol |
135
+ // filelocrange | callsite | fused | loc-alias-ref
136
+ location: $ => choice(
137
+ $.unknown_location,
138
+ $._string_location,
139
+ $.callsite_location,
140
+ $.fused_location,
141
+ $.attribute_alias,
142
+ $.dialect_attribute,
143
+ ),
144
+ unknown_location: $ => token('unknown'),
145
+ callsite_location: $ => seq(token('callsite'), '(',
146
+ $.location, token('at'), $.location, ')'),
147
+ fused_location: $ => seq(token('fused'),
148
+ optional(seq('<', $.attribute_value, '>')),
149
+ '[', $.location, repeat(seq(',', $.location)), ']'),
150
+ // Combines name-location and filelinecol-location (LangRef uses the same
151
+ // string-literal prefix; what follows distinguishes them).
152
+ _string_location: $ => seq(
153
+ $.string_literal,
154
+ optional(choice(
155
+ $._filelinecol_suffix,
156
+ seq('(', $.location, ')'),
157
+ )),
158
+ ),
159
+ _filelinecol_suffix: $ => seq(
160
+ ':', $.integer_literal,
161
+ optional(seq(':', $.integer_literal)),
162
+ optional(seq(token('to'),
163
+ optional($.integer_literal),
164
+ ':', $.integer_literal)),
165
+ ),
166
+
167
+ // =========================================================================
168
+ // Three-tier custom operation system
169
+ //
170
+ // Tier 1: func_operation, module_operation — structural ops for navigation
171
+ // Tier 2: _generic_custom_operation — all other dialect.op_name patterns
172
+ // =========================================================================
173
+ custom_operation: $ => choice(
174
+ prec(2, $.func_operation),
175
+ prec(2, $.module_operation),
176
+ prec(2, $._affine_for_operation),
177
+ $._generic_custom_operation,
178
+ ),
179
+
180
+ // Tier 1: Function operations (func.func, llvm.func)
181
+ // Token prec 20 ensures these keywords win over _dotted_op_name (prec 10)
182
+ func_operation: $ => prec.right(seq(
183
+ field('name', choice(token(prec(20, 'func.func')), token(prec(20, 'llvm.func')))),
184
+ field('visibility', optional(choice('private', 'public'))),
185
+ field('sym_name', $.symbol_ref_id),
186
+ field('arguments', $.func_arg_list),
187
+ field('return', optional($.func_return)),
188
+ field('attributes', optional(seq(optional(token('attributes')), $.dictionary_attribute))),
189
+ field('body', optional($.region)),
190
+ )),
191
+
192
+ // Tier 1: Module operations (module, builtin.module)
193
+ module_operation: $ => prec.right(seq(
194
+ field('name', choice(token(prec(20, 'builtin.module')), token(prec(20, 'module')))),
195
+ field('sym_name', optional($.symbol_ref_id)),
196
+ field('attributes', optional(seq(optional(token('attributes')), $.attribute))),
197
+ field('body', $.region),
198
+ )),
199
+
200
+ // affine.for prints its induction-variable location before the body
201
+ // (`affine.for %i loc("iv") = 0 to 8 { ... } loc(...)`). The generic
202
+ // operation rule already attaches a single `trailing_location` to the
203
+ // operation; without this structured rule, that machinery would bind the
204
+ // induction loc to the operation slot and leave the operation's own
205
+ // trailing loc unparseable.
206
+ _affine_for_operation: $ => prec.right(seq(
207
+ field('name', alias(token(prec(20, 'affine.for')), $.custom_op_name)),
208
+ $.value_use,
209
+ optional(field('induction_location', $.trailing_location)),
210
+ repeat($._custom_body_element),
211
+ )),
212
+
213
+ // Tier 2: Generic custom operation — dialect.op_name + structural body
214
+ // Negative dynamic precedence makes the parser prefer ending the body
215
+ // and starting a new operation (with _op_result_list) over extending
216
+ // the body with more elements, when both paths are valid (GLR).
217
+ _generic_custom_operation: $ => prec.dynamic(-1, prec.right(seq(
218
+ field('name', $.custom_op_name),
219
+ repeat($._custom_body_element),
220
+ ))),
221
+
222
+ // Operation name: dotted form (arith.addi, scf.forall.in_parallel)
223
+ // or known bare names (return, call, constant, etc.)
224
+ // High token precedence (prec 10) ensures these win over bare_id at the
225
+ // token level, forcing the parser to start a new operation rather than
226
+ // continuing the body of the previous one.
227
+ // bare_id fallback: supports MLIR's "default dialect" mechanism where
228
+ // operations inside a region may omit the dialect prefix (e.g.
229
+ // `parse_integer_literal` instead of `test.parse_integer_literal`).
230
+ // prec.dynamic(-1) on _generic_custom_operation keeps bare_id as a body
231
+ // element when inside a custom op body; it only acts as an op name at
232
+ // region/block boundaries where operation+ is required.
233
+ custom_op_name: $ => choice($._dotted_op_name, $._bare_op_name, $.bare_id),
234
+ _dotted_op_name: $ => token(prec(10, seq(
235
+ /[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$]/),
236
+ repeat1(seq('.', /[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$.]/))),
237
+ ))),
238
+ // Bare operation names: spec-sanctioned no-prefix aliases only.
239
+ // All other dialect ops go through _dotted_op_name or _generic_custom_operation.
240
+ _bare_op_name: $ => token(prec(10, choice(
241
+ 'return', 'call', 'call_indirect', 'constant', 'unrealized_conversion_cast',
242
+ ))),
243
+
244
+ // Structural body elements that can appear in custom operation format.
245
+ // These are recognized by sigils (%,^,@,!,#) or by structural delimiters.
246
+ _custom_body_element: $ => choice(
247
+ $.value_use, // %foo, %0
248
+ $.symbol_ref_id, // @sym, @"string"
249
+ $.successor, // ^bb0, ^bb0(%arg : type)
250
+ prec(2, $.type), // !type, i32, memref<...>, etc.
251
+ $.attribute, // #attr, {dict}, affine_map<...>
252
+ $.region, // { ... } (regions with operations)
253
+ $._custom_body_paren, // ( ... )
254
+ $._custom_body_bracket, // [ ... ]
255
+ $._custom_body_angle_group, // < ... >
256
+ $._literal, // 42, 3.14, "string", true, dense<...>
257
+ 'array', // property names may collide with array<...>
258
+ 'ceildiv', 'floordiv', 'mod', // inline affine keywords
259
+ $.bare_id, // keywords: to, from, step, ins, outs, etc.
260
+ ',', '=', ':', '->', '*', '+', '-', '/', '&', '|', '~',
261
+ ),
262
+
263
+ _custom_body_paren: $ => seq('(', repeat($._nested_custom_body_element), ')'),
264
+ _custom_body_bracket: $ => seq('[', repeat($._nested_custom_body_element), ']'),
265
+ _custom_body_angle_group: $ => seq('<', repeat($._nested_custom_body_element), '>'),
266
+ // Only nested groups accept `trailing_location` as a body element.
267
+ // At the top level it is omitted on purpose so the operation rule
268
+ // captures a trailing `loc(...)` as the operation's location instead of
269
+ // it being swallowed by the body repetition.
270
+ _nested_custom_body_element: $ => choice($._custom_body_element, $.trailing_location),
271
+
272
+ // =========================================================================
273
+ // Blocks
274
+ // block ::= block-label operation+
275
+ // block-label ::= block-id block-arg-list? `:`
276
+ // caret-id ::= `^` suffix-id
277
+ // =========================================================================
278
+ block: $ => seq($.block_label, repeat1($.operation)),
279
+ block_label: $ => seq($._block_id, optional($.block_arg_list), ':'),
280
+ _block_id: $ => $.caret_id,
281
+ caret_id: $ => seq('^', $._suffix_id),
282
+ _value_use_and_type: $ => seq($.value_use, optional(seq(':', $.type)),
283
+ optional($.trailing_location)),
284
+ _value_use_and_type_list: $ => seq($._value_use_and_type,
285
+ repeat(seq(',', $._value_use_and_type))),
286
+ block_arg_list: $ => seq('(', optional($._value_use_and_type_list), ')'),
287
+ _value_arg_list: $ => seq('(', optional(choice(
288
+ $._value_use_type_list, // bulk format: (%v0, %v1 : t0, t1)
289
+ $._value_use_and_type_list, // per-pair format: (%v0 : t0, %v1 : t1)
290
+ )), ')'),
291
+ _value_use_type_list: $ => seq($._value_use_list, ':', $._type_list_no_parens),
292
+
293
+ // =========================================================================
294
+ // Regions
295
+ // region ::= `{` entry-block? block* `}`
296
+ // entry-block ::= operation+
297
+ // =========================================================================
298
+ region: $ => seq('{', optional($.entry_block), repeat($.block), '}'),
299
+ entry_block: $ => repeat1($.operation),
300
+
301
+ // =========================================================================
302
+ // Types
303
+ // type ::= type-alias | dialect-type | builtin-type
304
+ // function-type ::= (type | type-list-parens) `->` (type | type-list-parens)
305
+ // =========================================================================
306
+ type: $ => choice($.type_alias, $.dialect_type, $.builtin_type),
307
+ _type_list_no_parens: $ => prec.left(seq(choice($.type, $.function_type),
308
+ repeat(seq(',', choice($.type, $.function_type))))),
309
+ _type_list_parens: $ => seq('(', optional($._type_list_no_parens), ')'),
310
+ function_type: $ => seq(choice($.type, $._type_list_parens), $._function_return),
311
+ _function_return: $ => seq(token('->'), choice($.type, $._type_list_parens)),
312
+ _type_annotation: $ => seq(':', $._type_list_no_parens),
313
+ _function_type_annotation: $ => seq(':', $.function_type),
314
+ _literal_and_type: $ => seq($._literal, optional($._type_annotation)),
315
+
316
+ // Type aliases
317
+ type_alias_def: $ => seq('!', $._alias_or_dialect_id, '=', $.type),
318
+ type_alias: $ => seq('!', $._alias_or_dialect_id),
319
+
320
+ // Dialect Types
321
+ dialect_type: $ => seq(
322
+ '!', choice($.opaque_dialect_item, $.pretty_dialect_item, $.parametric_dialect_item)),
323
+ dialect_namespace: $ => $._alias_or_dialect_id,
324
+ dialect_ident: $ => token(seq(/[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$.-]/))),
325
+ opaque_dialect_item: $ => prec(1, seq($.dialect_namespace, '<', $.string_literal, '>')),
326
+ pretty_dialect_item: $ => seq($.dialect_namespace, '.', $.dialect_ident,
327
+ optional($.pretty_dialect_item_body)),
328
+ // Parametric dialect item: !namespace<...> or #namespace<...> without dot-separated ident
329
+ parametric_dialect_item: $ => seq($.dialect_namespace, $.pretty_dialect_item_body),
330
+ pretty_dialect_item_body: $ => seq('<', repeat($._pretty_dialect_item_contents), '>'),
331
+ _pretty_dialect_item_contents: $ => prec.left(choice(
332
+ $.pretty_dialect_item_body,
333
+ $._pretty_dialect_bang_body_token,
334
+ $._pretty_dialect_body_attribute,
335
+ $.dialect_dim_list,
336
+ $.type,
337
+ prec(2, $.attribute),
338
+ $._literal,
339
+ 'dense', 'sparse', 'array',
340
+ $.bare_id,
341
+ ',', ':', '=', '->', '(', ')', '[', ']', '{', '}', '*',
342
+ '@', '#',
343
+ token(prec(-1, /[^<>]/))
344
+ )),
345
+ _pretty_dialect_bang_body_token: $ => token(prec(1,
346
+ seq('!', /[^a-zA-Z_<>]/))),
347
+ _pretty_dialect_body_attribute: $ => choice(
348
+ alias($._pretty_dialect_attribute_token, $.dialect_attribute),
349
+ alias($._pretty_attribute_alias_token, $.attribute_alias)),
350
+ _pretty_attribute_alias_token: $ => token(prec(2,
351
+ seq('#', /[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$]/)))),
352
+ _pretty_dialect_attribute_token: $ => token(prec(2,
353
+ seq('#', /[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$]/), '.',
354
+ /[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$.-]/)))),
355
+ dimension_separator: $ => token(prec(10, 'x')),
356
+ dialect_dim_list: $ => prec.dynamic(1, seq($._dialect_dim_primitive,
357
+ repeat1(seq($.dimension_separator, $._dialect_dim_primitive)))),
358
+ _dialect_dim_primitive: $ => choice(
359
+ prec(1, $.type),
360
+ alias($.integer_literal, $.dimension_size),
361
+ '?',
362
+ '*'),
363
+
364
+ // Builtin types
365
+ builtin_type: $ => choice(
366
+ $.integer_type,
367
+ $.float_type,
368
+ $.complex_type,
369
+ $.index_type,
370
+ $.memref_type,
371
+ $.none_type,
372
+ $.tensor_type,
373
+ $.vector_type,
374
+ $.tuple_type,
375
+ $.opaque_type),
376
+
377
+ integer_type: $ => token(prec(5, seq(choice('si', 'ui', 'i'), /[0-9]/, repeat(/[0-9]/)))),
378
+ float_type: $ => token(prec(5, choice('f16', 'tf32', 'f32', 'f64', 'f80', 'f128', 'bf16',
379
+ 'f4E2M1FN', 'f6E2M3FN', 'f6E3M2FN', 'f8E3M4', 'f8E4M3', 'f8E4M3FN', 'f8E4M3FNUZ',
380
+ 'f8E4M3B11FNUZ', 'f8E5M2', 'f8E5M2FNUZ', 'f8E8M0FNU'))),
381
+ index_type: $ => token(prec(5, 'index')),
382
+ none_type: $ => token(prec(5, 'none')),
383
+ complex_type: $ => seq(token('complex'), '<', $._prim_type, '>'),
384
+ _prim_type: $ => choice($.integer_type, $.float_type, $.index_type,
385
+ $.complex_type, $.none_type, $.memref_type, $.vector_type, $.tensor_type,
386
+ $.tuple_type, $.opaque_type, $.dialect_type, $.type_alias),
387
+
388
+ memref_type: $ => seq(token('memref'), '<',
389
+ field('dimension_list', $.dim_list),
390
+ optional(seq(',', $.attribute_value)),
391
+ optional(seq(',', $.attribute_value)), '>'),
392
+ dim_list: $ => seq($._dim_primitive, repeat(seq('x', $._dim_primitive))),
393
+ // '*' represents the unranked form for both memref and tensor types
394
+ // (UnrankedMemRefType, UnrankedTensorType). Vector uses its own
395
+ // vector_dim_list / _static_dim_list and disallows '*' by construction.
396
+ dimension_size: $ => token(repeat1(/[0-9]/)),
397
+ _dim_primitive: $ => choice(prec(1, $.type), $.dimension_size, '?', '*'),
398
+
399
+ tensor_type: $ => seq(token('tensor'), '<', $.dim_list,
400
+ optional(seq(',', $.tensor_encoding)), '>'),
401
+ tensor_encoding: $ => $.attribute_value,
402
+
403
+ vector_type: $ => seq(token('vector'), '<', repeat($.vector_dim_list), $._prim_type, '>'),
404
+ vector_dim_list: $ => prec.left(choice(seq($._static_dim_list, 'x',
405
+ optional(seq('[', $._static_dim_list, ']', 'x'))), seq('[', $._static_dim_list, ']', 'x'))),
406
+ _static_dim_list: $ => seq($.dimension_size, repeat(seq('x', $.dimension_size))),
407
+
408
+ tuple_type: $ => seq(token('tuple'), '<', optional(seq($.tuple_dim, repeat(seq(',', $.tuple_dim)))), '>'),
409
+ tuple_dim: $ => $._prim_type,
410
+
411
+ // opaque-type ::= `opaque` `<` string-literal `,` string-literal `>`
412
+ // e.g. opaque<"llvm", "struct<(i32, float)>">
413
+ opaque_type: $ => seq(token('opaque'), '<', $.string_literal, ',', $.string_literal, '>'),
414
+
415
+ // =========================================================================
416
+ // Attributes
417
+ // attribute-entry ::= (bare-id | string-literal) `=` attribute-value
418
+ // attribute-value ::= attribute-alias | dialect-attribute | builtin-attribute
419
+ // =========================================================================
420
+ attribute_entry: $ => choice(
421
+ seq(choice($.bare_id, $.string_literal), optional(seq('=', $.attribute_value))),
422
+ // Array-valued entry (e.g. {["op.name"]} in transform dialect)
423
+ seq('[', optional($._attribute_value_nobracket),
424
+ repeat(seq(',', $._attribute_value_nobracket)), ']'),
425
+ ),
426
+ attribute_value: $ => choice(seq('[', optional($._attribute_value_nobracket),
427
+ repeat(seq(',', $._attribute_value_nobracket)), ']'), $._attribute_value_nobracket),
428
+ _attribute_value_nobracket: $ => choice($.attribute_alias, $.dialect_attribute,
429
+ $.builtin_attribute, $.dictionary_attribute, $._literal_and_type, $.type,
430
+ $.function_type, $._affine_map_like, $.symbol_ref_id, $.trailing_location,
431
+ seq(choice($.attribute_alias, $.dialect_attribute, $.builtin_attribute), $._type_annotation)),
432
+ attribute: $ => choice($.attribute_alias, $.dialect_attribute,
433
+ $.builtin_attribute, $.dictionary_attribute),
434
+
435
+ // Attribute aliases
436
+ attribute_alias_def: $ => seq('#', $._alias_or_dialect_id, '=', $.attribute_value),
437
+ attribute_alias: $ => seq('#', $._alias_or_dialect_id),
438
+
439
+ // Dialect attributes
440
+ dialect_attribute: $ => seq('#', choice($.opaque_dialect_item, $.pretty_dialect_item, $.parametric_dialect_item)),
441
+
442
+ // Builtin attributes
443
+ builtin_attribute: $ => choice(
444
+ $.strided_layout,
445
+ prec(1, $.affine_map),
446
+ prec(1, $.affine_set),
447
+ $.dense_resource_literal,
448
+ ),
449
+ dense_resource_literal: $ => seq(token('dense_resource'), '<',
450
+ choice($.bare_id, $.string_literal), '>'),
451
+ strided_layout: $ => seq(token('strided'), '<', '[', optional($._stride_list_comma), ']',
452
+ optional(seq(',', token('offset'), ':', $._stride_primitive)), '>'),
453
+ _stride_list_comma: $ => seq($._stride_primitive, repeat(seq(',', $._stride_primitive))),
454
+ _stride_primitive: $ => choice($.integer_literal, '?', '*'),
455
+
456
+ // =========================================================================
457
+ // Affine expressions
458
+ // =========================================================================
459
+ affine_map: $ => seq(token('affine_map'), '<', $._multi_dim_affine_expr_parens,
460
+ optional($._multi_dim_affine_expr_sq), token('->'), $._multi_dim_affine_expr_parens, '>'),
461
+ _affine_map_like: $ => seq($._multi_dim_affine_expr_parens,
462
+ optional($._multi_dim_affine_expr_sq), token('->'), $._multi_dim_affine_expr_parens),
463
+ affine_set: $ => seq(token('affine_set'), '<', $._multi_dim_affine_expr_parens,
464
+ optional($._multi_dim_affine_expr_sq), ':', $._multi_dim_affine_expr_parens, '>'),
465
+ _multi_dim_affine_expr_parens: $ => seq('(', optional($._multi_dim_affine_expr), ')'),
466
+ _multi_dim_affine_expr_sq: $ => seq('[', optional($._multi_dim_affine_expr), ']'),
467
+
468
+ _multi_dim_affine_expr: $ => seq($._affine_expr, repeat(seq(',', $._affine_expr))),
469
+ _affine_expr: $ => choice(
470
+ seq('(', $._affine_expr, ')'),
471
+ prec(4, seq('-', $._affine_expr)),
472
+ prec.left(3, seq($._affine_expr, choice('*', 'ceildiv', 'floordiv', 'mod'), $._affine_expr)),
473
+ prec.left(2, seq($._affine_expr, choice('+', '-'), $._affine_expr)),
474
+ prec.left(1, seq($._affine_expr, choice('==', '>=', '<='), $._affine_expr)),
475
+ $._affine_prim
476
+ ),
477
+ _affine_prim: $ => choice($.integer_literal, $.value_use,
478
+ seq(choice($.bare_id, 'dense', 'sparse'), optional(seq(':', choice($.bare_id, 'dense', 'sparse', 'compressed', 'singleton', 'loose_compressed', 'n_out_of_m')))),
479
+ seq('symbol', '(', $.value_use, ')'), seq(choice('max', 'min'), '(', $._value_use_list, ')')),
480
+
481
+ // =========================================================================
482
+ // Function-related rules (used by func_operation tier-1)
483
+ // =========================================================================
484
+ func_return: $ => seq(token('->'), $.type_list_attr_parens),
485
+ func_arg_list: $ => seq('(', optional(choice($.variadic,
486
+ $._value_id_and_type_attr_list)), ')'),
487
+ _value_id_and_type_attr_list: $ => seq($._value_id_and_type_attr,
488
+ repeat(seq(',', $._value_id_and_type_attr)), optional(seq(',', $.variadic))),
489
+ _value_id_and_type_attr: $ => seq($._function_arg, optional($.attribute),
490
+ optional($.trailing_location)),
491
+ _function_arg: $ => choice(seq($.value_use, ':', choice($.type, $.function_type)), $.value_use, $.type, $.function_type),
492
+ _type_or_func_type: $ => choice($.type, $.function_type),
493
+ type_list_attr_parens: $ => choice($.type, $.function_type,
494
+ seq('(', $._type_or_func_type, optional($.attribute),
495
+ repeat(seq(',', $._type_or_func_type, optional($.attribute))), ')'), seq('(', ')')),
496
+ variadic: $ => token('...'),
497
+
498
+ // =========================================================================
499
+ // Shared helpers
500
+ // =========================================================================
501
+ _value_use_list_parens: $ => seq('(', optional($._value_use_list), ')'),
502
+
503
+ // Comment (standard BCPL)
504
+ comment: $ => token(seq('//', /.*/)),
505
+ }
506
+ });
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@felixtensor/tree-sitter-mlir",
3
+ "version": "0.1.0",
4
+ "description": "MLIR grammar for tree-sitter",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/felixtensor/tree-sitter-mlir.git"
9
+ },
10
+ "license": "Apache-2.0 WITH LLVM-exception",
11
+ "author": {
12
+ "name": "Buyun Xu",
13
+ "email": "xubuyun@outlook.com",
14
+ "url": "https://github.com/felixtensor"
15
+ },
16
+ "main": "bindings/node",
17
+ "types": "bindings/node",
18
+ "keywords": [
19
+ "incremental",
20
+ "parsing",
21
+ "tree-sitter",
22
+ "mlir"
23
+ ],
24
+ "files": [
25
+ "grammar.js",
26
+ "tree-sitter.json",
27
+ "binding.gyp",
28
+ "prebuilds/**",
29
+ "bindings/node/*",
30
+ "queries/*",
31
+ "src/**",
32
+ "*.wasm"
33
+ ],
34
+ "dependencies": {
35
+ "node-addon-api": "^8.8.0",
36
+ "node-gyp-build": "^4.8.4"
37
+ },
38
+ "devDependencies": {
39
+ "prebuildify": "^6.0.1",
40
+ "tree-sitter": "^0.25.0",
41
+ "tree-sitter-cli": "^0.26.9"
42
+ },
43
+ "peerDependencies": {
44
+ "tree-sitter": "^0.25.0"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "tree-sitter": {
48
+ "optional": true
49
+ }
50
+ },
51
+ "scripts": {
52
+ "install": "node-gyp-build",
53
+ "prestart": "tree-sitter build --wasm",
54
+ "start": "tree-sitter playground",
55
+ "compile": "tree-sitter generate",
56
+ "update-tests": "tree-sitter test --update",
57
+ "test": "tree-sitter test",
58
+ "test:bindings": "node --test bindings/node/*_test.js",
59
+ "test:examples": "tree-sitter parse --quiet --stat examples/**/*.mlir",
60
+ "test:all": "npm run test && npm run test:examples",
61
+ "bench": "node bench.mjs",
62
+ "prebuildify": "prebuildify --napi --strip"
63
+ },
64
+ "publishConfig": {
65
+ "access": "public"
66
+ }
67
+ }