xref: /llvm-project/mlir/utils/tree-sitter-mlir/grammar.js (revision 3f9cabae0029bcbe88835aaa4c417ce41e584fb1)
1'use strict';
2
3const builtin_dialect = require('./dialect/builtin');
4const func_dialect = require('./dialect/func');
5const llvm_dialect = require('./dialect/llvm');
6const arith_dialect = require('./dialect/arith');
7const math_dialect = require('./dialect/math');
8const cf_dialect = require('./dialect/cf');
9const scf_dialect = require('./dialect/scf');
10const memref_dialect = require('./dialect/memref');
11const vector_dialect = require('./dialect/vector');
12const tensor_dialect = require('./dialect/tensor');
13const bufferization_dialect = require('./dialect/bufferization');
14const affine_dialect = require('./dialect/affine');
15const linalg_dialect = require('./dialect/linalg');
16
17const common = {
18  // Top level production:
19  //   (operation | attribute-alias-def | type-alias-def)
20  toplevel : $ => seq($._toplevel, repeat($._toplevel)),
21  _toplevel : $ => choice($.operation, $.attribute_alias_def, $.type_alias_def),
22
23  // Common syntax (lang-ref)
24  //  digit     ::= [0-9]
25  //  hex_digit ::= [0-9a-fA-F]
26  //  letter    ::= [a-zA-Z]
27  //  id-punct  ::= [$._-]
28  //
29  //  integer-literal ::= decimal-literal | hexadecimal-literal
30  //  decimal-literal ::= digit+
31  //  hexadecimal-literal ::= `0x` hex_digit+
32  //  float-literal ::= [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?
33  //  string-literal  ::= `"` [^"\n\f\v\r]* `"`   TODO: define escaping rules
34  //
35  _digit : $ => /[0-9]/,
36  integer_literal : $ => choice($._decimal_literal, $._hexadecimal_literal),
37  _decimal_literal : $ => token(seq(optional(/[-+]/), repeat1(/[0-9]/))),
38  _hexadecimal_literal : $ => token(seq('0x', repeat1(/[0-9a-fA-F]/))),
39  float_literal : $ =>
40      token(seq(optional(/[-+]/), repeat1(/[0-9]/), '.', repeat(/[0-9]/),
41                optional(seq(/[eE]/, optional(/[-+]/), repeat1(/[0-9]/))))),
42  string_literal : $ => token(seq('"', repeat(/[^\\"\n\f\v\r]+/), '"')),
43  bool_literal : $ => token(choice('true', 'false')),
44  unit_literal : $ => token('unit'),
45  complex_literal : $ =>
46      seq('(', choice($.integer_literal, $.float_literal), ',',
47          choice($.integer_literal, $.float_literal), ')'),
48  tensor_literal : $ =>
49      seq(token(choice('dense', 'sparse')), '<',
50          optional(choice(
51              seq($.nested_idx_list, repeat(seq(',', $.nested_idx_list))),
52              $._primitive_idx_literal)),
53          '>'),
54  array_literal : $ => seq(token('array'), '<', $.type, ':', $._idx_list, '>'),
55  _literal : $ => choice($.integer_literal, $.float_literal, $.string_literal,
56                         $.bool_literal, $.tensor_literal, $.array_literal,
57                         $.complex_literal, $.unit_literal),
58
59  nested_idx_list : $ =>
60      seq('[', optional(choice($.nested_idx_list, $._idx_list)),
61          repeat(seq(',', $.nested_idx_list)), ']'),
62  _idx_list : $ => prec.right(seq($._primitive_idx_literal,
63                                  repeat(seq(',', $._primitive_idx_literal)))),
64  _primitive_idx_literal : $ => choice($.integer_literal, $.float_literal,
65                                       $.bool_literal, $.complex_literal),
66
67  // Identifiers
68  //   bare-id ::= (letter|[_]) (letter|digit|[_$.])*
69  //   bare-id-list ::= bare-id (`,` bare-id)*
70  //   value-id ::= `%` suffix-id
71  //   suffix-id ::= (digit+ | ((letter|id-punct) (letter|id-punct|digit)*))
72  //   alias-name :: = bare-id
73  //
74  //   symbol-ref-id ::= `@` (suffix-id | string-literal) (`::`
75  //                     symbol-ref-id)?
76  //   value-id-list ::= value-id (`,` value-id)*
77  //
78  //   // Uses of value, e.g. in an operand list to an operation.
79  //   value-use ::= value-id
80  //   value-use-list ::= value-use (`,` value-use)*
81  bare_id : $ => token(seq(/[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$.]/))),
82  _alias_or_dialect_id : $ => token(seq(/[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$]/))),
83  bare_id_list : $ => seq($.bare_id, repeat(seq(',', $.bare_id))),
84  value_use : $ => seq('%', $._suffix_id),
85  _suffix_id : $ => token(seq(
86      choice(repeat1(/[0-9]/), seq(/[a-zA-Z_$.-]/, repeat(/[a-zA-Z0-9_$.-]/))),
87      optional(seq(choice(':', '#'), repeat1(/[0-9]/))))),
88  symbol_ref_id : $ => seq('@', choice($._suffix_id, $.string_literal),
89                           optional(seq('::', $.symbol_ref_id))),
90  _value_use_list : $ => seq($.value_use, repeat(seq(',', $.value_use))),
91
92  // Operations
93  //   operation            ::= op-result-list? (generic-operation |
94  //                            custom-operation)
95  //                            trailing-location?
96  //   generic-operation    ::= string-literal `(` value-use-list? `)`
97  //                            successor-list? region-list?
98  //                            dictionary-attribute? `:` function-type
99  //   custom-operation     ::= bare-id custom-operation-format
100  //   op-result-list       ::= op-result (`,` op-result)* `=`
101  //   op-result            ::= value-id (`:` integer-literal)
102  //   successor-list       ::= `[` successor (`,` successor)* `]`
103  //   successor            ::= caret-id (`:` bb-arg-list)?
104  //   region-list          ::= `(` region (`,` region)* `)`
105  //   dictionary-attribute ::= `{` (attribute-entry (`,` attribute-entry)*)?
106  //                            `}`
107  //   trailing-location    ::= (`loc` `(` location `)`)?
108  operation : $ =>
109      seq(field('lhs', optional($._op_result_list)),
110          field('rhs', choice($.generic_operation, $.custom_operation)),
111          field('location', optional($.trailing_location))),
112  generic_operation : $ => seq(
113      $.string_literal, $._value_use_list_parens, optional($._successor_list),
114      optional($._region_list), optional($.attribute), ':', $.function_type),
115  // custom-operation rule is defined later in the grammar, post the generic.
116  _op_result_list : $ => seq($.op_result, repeat(seq(',', $.op_result)), '='),
117  op_result : $ => seq($.value_use, optional(seq(':', $.integer_literal))),
118  _successor_list : $ =>
119      seq('[', $.successor, repeat(seq(',', $.successor)), ']'),
120  successor : $ => seq($.caret_id, optional($._value_arg_list)),
121  _region_list : $ => seq('(', $.region, repeat(seq(',', $.region)), ')'),
122  dictionary_attribute : $ => seq('{', optional($.attribute_entry),
123                                  repeat(seq(',', $.attribute_entry)), '}'),
124  trailing_location : $ => seq(token('loc'), '(', $.location, ')'),
125  // TODO: Complete location forms.
126  location : $ => $.string_literal,
127
128  // Blocks
129  //   block           ::= block-label operation+
130  //   block-label     ::= block-id block-arg-list? `:`
131  //   block-id        ::= caret-id
132  //   caret-id        ::= `^` suffix-id
133  //   value-id-and-type ::= value-id `:` type
134  //
135  //   // Non-empty list of names and types.
136  //   value-id-and-type-list ::= value-id-and-type (`,` value-id-and-type)*
137  //
138  //   block-arg-list ::= `(` value-id-and-type-list? `)`
139  block : $ => seq($.block_label, repeat1($.operation)),
140  block_label : $ => seq($._block_id, optional($.block_arg_list), ':'),
141  _block_id : $ => $.caret_id,
142  caret_id : $ => seq('^', $._suffix_id),
143  _value_use_and_type : $ => seq($.value_use, optional(seq(':', $.type))),
144  _value_use_and_type_list : $ =>
145      seq($._value_use_and_type, repeat(seq(',', $._value_use_and_type))),
146  block_arg_list : $ => seq('(', optional($._value_use_and_type_list), ')'),
147  _value_arg_list : $ => seq('(', optional($._value_use_type_list), ')'),
148  _value_use_type_list : $ => seq($._value_use_list, $._type_annotation),
149
150  // Regions
151  //   region      ::= `{` entry-block? block* `}`
152  //   entry-block ::= operation+
153  region : $ => seq('{', optional($.entry_block), repeat($.block), '}'),
154  entry_block : $ => repeat1($.operation),
155
156  // Types
157  //   type ::= type-alias | dialect-type | builtin-type
158  //
159  //   type-list-no-parens ::=  type (`,` type)*
160  //   type-list-parens ::= `(` type-list-no-parens? `)`
161  //
162  //   // This is a common way to refer to a value with a specified type.
163  //   ssa-use-and-type ::= ssa-use `:` type
164  //   ssa-use ::= value-use
165  //
166  //   // Non-empty list of names and types.
167  //   ssa-use-and-type-list ::= ssa-use-and-type (`,` ssa-use-and-type)*
168  //
169  //   function-type ::= (type | type-list-parens) `->` (type |
170  //                      type-list-parens)
171  type : $ => choice($.type_alias, $.dialect_type, $.builtin_type),
172  _type_list_no_parens : $ => prec.left(seq($.type, repeat(seq(',', $.type)))),
173  _type_list_parens : $ => seq('(', optional($._type_list_no_parens), ')'),
174  function_type : $ =>
175      seq(choice($.type, $._type_list_parens), $._function_return),
176  _function_return : $ => seq(token('->'), choice($.type, $._type_list_parens)),
177  _type_annotation : $ =>
178      seq(':', choice(seq($.type, choice('from', 'into', 'to'), $.type),
179                      $._type_list_no_parens)),
180  _function_type_annotation : $ => seq(':', $.function_type),
181  _literal_and_type : $ => seq($._literal, optional($._type_annotation)),
182
183  // Type aliases
184  //   type-alias-def ::= '!' alias-name '=' type
185  //   type-alias ::= '!' alias-name
186  type_alias_def : $ => seq('!', $._alias_or_dialect_id, '=', $.type),
187  type_alias : $ => seq('!', $._alias_or_dialect_id),
188
189  // Dialect Types
190  //   dialect-namespace ::= bare-id
191  //
192  //   opaque-dialect-item ::= dialect-namespace '<' string-literal '>'
193  //
194  //   pretty-dialect-item ::= dialect-namespace '.'
195  //   pretty-dialect-item-lead-ident pretty-dialect-item-body?
196  //
197  //   pretty-dialect-item-lead-ident ::= '[A-Za-z][A-Za-z0-9._]*'
198  //   pretty-dialect-item-body ::= '<' pretty-dialect-item-contents+ '>'
199  //   pretty-dialect-item-contents ::= pretty-dialect-item-body
200  //                                 | '(' pretty-dialect-item-contents+ ')'
201  //                                 | '[' pretty-dialect-item-contents+ ']'
202  //                                 | '{' pretty-dialect-item-contents+ '}'
203  //                                 | '[^[<({>\])}\0]+'
204  //
205  //   dialect-type ::= '!' (opaque-dialect-item | pretty-dialect-item)
206  dialect_type : $ =>
207      seq('!', choice($.opaque_dialect_item, $.pretty_dialect_item)),
208  dialect_namespace : $ => $._alias_or_dialect_id,
209  dialect_ident : $ => $._alias_or_dialect_id,
210  opaque_dialect_item : $ =>
211      seq($.dialect_namespace, '<', $.string_literal, '>'),
212  pretty_dialect_item : $ => seq($.dialect_namespace, '.', $.dialect_ident,
213                                 optional($.pretty_dialect_item_body)),
214  pretty_dialect_item_body : $ =>
215      seq('<', repeat($._pretty_dialect_item_contents), '>'),
216  _pretty_dialect_item_contents : $ =>
217      prec.left(choice($.pretty_dialect_item_body, repeat1(/[^<>]/))),
218
219  // Builtin types
220  builtin_type : $ => choice(
221      // TODO: Add opaque_type
222      $.integer_type, $.float_type, $.complex_type, $.index_type, $.memref_type,
223      $.none_type, $.tensor_type, $.vector_type, $.tuple_type),
224
225  // signed-integer-type ::= `si`[1-9][0-9]*
226  // unsigned-integer-type ::= `ui`[1-9][0-9]*
227  // signless-integer-type ::= `i`[1-9][0-9]*
228  // integer-type ::= signed-integer-type | unsigned-integer-type |
229  // signless-integer-type
230  integer_type : $ =>
231      token(seq(choice('si', 'ui', 'i'), /[1-9]/, repeat(/[0-9]/))),
232  float_type : $ => token(
233      choice('f16', 'f32', 'f64', 'f80', 'f128', 'bf16', 'f8E3M4', 'f8E4M3FN',
234             'f8E4M3', 'f8E5M2', 'f4E2M1FN', 'f6E2M3FN', 'f6E3M2FN',
235             'f8E8M0FNU')),
236  index_type : $ => token('index'),
237  none_type : $ => token('none'),
238  complex_type : $ => seq(token('complex'), '<', $._prim_type, '>'),
239  _prim_type : $ =>
240      choice($.integer_type, $.float_type, $.index_type, $.complex_type,
241             $.none_type, $.memref_type, $.vector_type, $.tensor_type),
242
243  // memref-type ::= `memref` `<` dimension-list-ranked type
244  //                 (`,` layout-specification)? (`,` memory-space)? `>`
245  // layout-specification ::= attribute-value
246  // memory-space ::= attribute-value
247  memref_type : $ =>
248      seq(token('memref'), '<', field('dimension_list', $.dim_list),
249          optional(seq(',', $.attribute_value)),
250          optional(seq(',', $.attribute_value)), '>'),
251  dim_list : $ => seq($._dim_primitive, repeat(seq('x', $._dim_primitive))),
252  _dim_primitive : $ => choice($._prim_type, repeat1($._digit), '?', '*'),
253
254  // tensor-type ::= `tensor` `<` dimension-list type (`,` encoding)? `>`
255  // dimension-list ::= (dimension `x`)*
256  // dimension ::= `?` | decimal-literal
257  // encoding ::= attribute-value
258  // tensor-type ::= `tensor` `<` `*` `x` type `>`
259  tensor_type : $ => seq(token('tensor'), '<', $.dim_list,
260                         optional(seq(',', $.tensor_encoding)), '>'),
261  tensor_encoding : $ => $.attribute_value,
262
263  // vector-type ::= `vector` `<` vector-dim-list vector-element-type `>`
264  // vector-element-type ::= float-type | integer-type | index-type
265  // vector-dim-list := (static-dim-list `x`)? (`[` static-dim-list `]` `x`)?
266  // static-dim-list ::= decimal-literal (`x` decimal-literal)*
267  vector_type : $ =>
268      seq(token('vector'), '<', optional($.vector_dim_list), $._prim_type, '>'),
269  vector_dim_list : $ =>
270      choice(seq($._static_dim_list, 'x',
271                 optional(seq('[', $._static_dim_list, ']', 'x'))),
272             seq('[', $._static_dim_list, ']', 'x')),
273  _static_dim_list : $ =>
274      seq(repeat1($._digit), repeat(seq('x', repeat1($._digit)))),
275
276  // tuple-type ::= `tuple` `<` (type ( `,` type)*)? `>`
277  tuple_type : $ =>
278      seq(token('tuple'), '<', $.tuple_dim, repeat(seq(',', $.tuple_dim)), '>'),
279  tuple_dim : $ => $._prim_type,
280
281  // Attributes
282  //   attribute-entry ::= (bare-id | string-literal) `=` attribute-value
283  //   attribute-value ::= attribute-alias | dialect-attribute |
284  //   builtin-attribute
285  attribute_entry : $ => seq(choice($.bare_id, $.string_literal),
286                             optional(seq('=', $.attribute_value))),
287  attribute_value : $ =>
288      choice(seq('[', optional($._attribute_value_nobracket),
289                 repeat(seq(',', $._attribute_value_nobracket)), ']'),
290             $._attribute_value_nobracket),
291  _attribute_value_nobracket : $ =>
292      choice($.attribute_alias, $.dialect_attribute, $.builtin_attribute,
293             $.dictionary_attribute, $._literal_and_type, $.type),
294  attribute : $ => choice($.attribute_alias, $.dialect_attribute,
295                          $.builtin_attribute, $.dictionary_attribute),
296
297  // Attribute Value Aliases
298  //   attribute-alias-def ::= '#' alias-name '=' attribute-value
299  //   attribute-alias ::= '#' alias-name
300  attribute_alias_def : $ =>
301      seq('#', $._alias_or_dialect_id, '=', $.attribute_value),
302  attribute_alias : $ => seq('#', $._alias_or_dialect_id),
303
304  // Dialect Attribute Values
305  dialect_attribute : $ =>
306      seq('#', choice($.opaque_dialect_item, $.pretty_dialect_item)),
307
308  // Builtin Attribute Values
309  builtin_attribute : $ => choice(
310      // TODO
311      $.strided_layout, $.affine_map, $.affine_set),
312  strided_layout : $ => seq(token('strided'), '<', '[', $._dim_list_comma, ']',
313                            optional(seq(',', token('offset'), ':',
314                                         choice($.integer_literal, '?', '*'))),
315                            '>'),
316  _dim_list_comma : $ =>
317      seq($._dim_primitive, repeat(seq(',', $._dim_primitive))),
318
319  affine_map : $ =>
320      seq(token('affine_map'), '<', $._multi_dim_affine_expr_parens,
321          optional($._multi_dim_affine_expr_sq), token('->'),
322          $._multi_dim_affine_expr_parens, '>'),
323  affine_set : $ =>
324      seq(token('affine_set'), '<', $._multi_dim_affine_expr_parens,
325          optional($._multi_dim_affine_expr_sq), ':',
326          $._multi_dim_affine_expr_parens, '>'),
327  _multi_dim_affine_expr_parens : $ =>
328      seq('(', optional($._multi_dim_affine_expr), ')'),
329  _multi_dim_affine_expr_sq : $ =>
330      seq('[', optional($._multi_dim_affine_expr), ']'),
331
332  // affine-expr ::= `(` affine-expr `)`
333  //               | affine-expr `+` affine-expr
334  //               | affine-expr `-` affine-expr
335  //               | `-`? integer-literal `*` affine-expr
336  //               | affine-expr `ceildiv` integer-literal
337  //               | affine-expr `floordiv` integer-literal
338  //               | affine-expr `mod` integer-literal
339  //               | `-`affine-expr
340  //               | bare-id
341  //               | `-`? integer-literal
342  // multi-dim-affine-expr ::= `(` `)`
343  //                         | `(` affine-expr (`,` affine-expr)* `)`
344
345  // semi-affine-expr ::= `(` semi-affine-expr `)`
346  //                    | semi-affine-expr `+` semi-affine-expr
347  //                    | semi-affine-expr `-` semi-affine-expr
348  //                    | symbol-or-const `*` semi-affine-expr
349  //                    | semi-affine-expr `ceildiv` symbol-or-const
350  //                    | semi-affine-expr `floordiv` symbol-or-const
351  //                    | semi-affine-expr `mod` symbol-or-const
352  //                    | bare-id
353  //                    | `-`? integer-literal
354  // symbol-or-const ::= `-`? integer-literal | symbol-id
355  // multi-dim-semi-affine-expr ::= `(` semi-affine-expr (`,` semi-affine-expr)*
356  // `)`
357
358  // affine-constraint ::= affine-expr `>=` `affine-expr`
359  //                     | affine-expr `<=` `affine-expr`
360  //                     | affine-expr `==` `affine-expr`
361  // affine-constraint-conjunction ::= affine-constraint (`,`
362  // affine-constraint)*
363
364  _multi_dim_affine_expr : $ =>
365      seq($._affine_expr, repeat(seq(',', $._affine_expr))),
366  _affine_expr : $ => prec.right(choice(
367      seq('(', $._affine_expr, ')'), seq('-', $._affine_expr),
368      seq($._affine_expr, $._affine_token, $._affine_expr), $._affine_prim)),
369  _affine_prim : $ =>
370      choice($.integer_literal, $.value_use, $.bare_id,
371             seq('symbol', '(', $.value_use, ')'),
372             seq(choice('max', 'min'), '(', $._value_use_list, ')')),
373  _affine_token : $ => token(
374      choice('+', '-', '*', 'ceildiv', 'floordiv', 'mod', '==', '>=', '<=')),
375
376  func_return : $ => seq(token('->'), $.type_list_attr_parens),
377  func_arg_list : $ => seq(
378      '(', optional(choice($.variadic, $._value_id_and_type_attr_list)), ')'),
379  _value_id_and_type_attr_list : $ => seq(
380      $._value_id_and_type_attr, repeat(seq(',', $._value_id_and_type_attr)),
381      optional(seq(',', $.variadic))),
382  _value_id_and_type_attr : $ => seq($._function_arg, optional($.attribute)),
383  _function_arg : $ =>
384      choice(seq($.value_use, ':', $.type), $.value_use, $.type),
385  type_list_attr_parens : $ =>
386      choice($.type,
387             seq('(', $.type, optional($.attribute),
388                 repeat(seq(',', $.type, optional($.attribute))), ')'),
389             seq('(', ')')),
390  variadic : $ => token('...'),
391
392  // (func.func|llvm.func) takes arguments, an optional return type, and and
393  // optional body
394  _op_func : $ =>
395      seq(field('visibility', optional('private')),
396          field('name', $.symbol_ref_id), field('arguments', $.func_arg_list),
397          field('return', optional($.func_return)),
398          field('attributes', optional(seq(token('attributes'), $.attribute))),
399          field('body', optional($.region))),
400
401  // dim-use-list ::= `(` ssa-use-list? `)`
402  // symbol-use-list ::= `[` ssa-use-list? `]`
403  // dim-and-symbol-use-list ::= dim-use-list symbol-use-list?
404  _value_use_list_parens : $ => seq('(', optional($._value_use_list), ')'),
405  _dim_and_symbol_use_list : $ =>
406      seq($._value_use_list_parens, optional($._dense_idx_list)),
407
408  // assignment-list ::= assignment | assignment `,` assignment-list
409  // assignment ::= ssa-value `=` ssa-value
410  _value_assignment_list : $ => seq('(', optional($._value_assignment),
411                                    repeat(seq(',', $._value_assignment)), ')'),
412  _value_assignment : $ => seq($.value_use, '=', $.value_use),
413
414  _dense_idx_list : $ => seq(
415      '[',
416      optional(seq(choice($.integer_literal, $.value_use),
417                   repeat(seq(',', choice($.integer_literal, $.value_use))))),
418      ']'),
419
420  // lower-bound ::= `max`? affine-map-attribute dim-and-symbol-use-list |
421  // shorthand-bound
422  // upper-bound ::= `min`? affine-map-attribute dim-and-symbol-use-list |
423  // shorthand-bound
424  // shorthand-bound ::= ssa-id | `-`? integer-literal
425  _bound : $ =>
426      choice(seq($.attribute, $._dim_and_symbol_use_list), $._shorthand_bound),
427  _shorthand_bound : $ => choice($.value_use, $.integer_literal),
428
429  // Dialect-specific attributes
430  restrict_attr : $ => token('restrict'),
431  writable_attr : $ => token('writable'),
432  gather_dims_attr : $ =>
433      seq(token('gather_dims'), '(', $._dense_idx_list, ')'),
434  scatter_dims_attr : $ =>
435      seq(token('scatter_dims'), '(', $._dense_idx_list, ')'),
436  unique_attr : $ => token('unique'),
437  nofold_attr : $ => token('nofold'),
438  outer_dims_perm_attr : $ =>
439      seq(token('outer_dims_perm'), '=', $._dense_idx_list),
440  inner_dims_pos_attr : $ =>
441      seq(token('inner_dims_pos'), '=', $._dense_idx_list),
442  inner_tiles_attr : $ => seq(token('inner_tiles'), '=', $._dense_idx_list),
443  isWrite_attr : $ => token(choice('read', 'write')),
444  localityHint_attr : $ => seq(token('locality'), '<', $.integer_literal, '>'),
445  isDataCache_attr : $ => token(choice('data', 'instr')),
446  fastmath_attr : $ =>
447      seq(token('fastmath'), '<',
448          seq($._fastmath_flag, repeat(seq(',', $._fastmath_flag))), '>'),
449  _fastmath_flag : $ => token(choice('none', 'reassoc', 'nnan', 'ninf', 'nsz',
450                                     'arcp', 'contract', 'afn', 'fast')),
451
452  // Comment (standard BCPL)
453  comment : $ => token(seq('//', /.*/)),
454
455  // TODO: complete
456  custom_operation : $ =>
457      choice($.builtin_dialect, $.func_dialect, $.llvm_dialect, $.arith_dialect,
458             $.math_dialect, $.cf_dialect, $.scf_dialect, $.memref_dialect,
459             $.vector_dialect, $.tensor_dialect, $.bufferization_dialect,
460             $.affine_dialect, $.linalg_dialect)
461}
462
463               module.exports = grammar({
464  name : 'mlir',
465  extras : $ => [/\s/, $.comment],
466  conflicts : $ => [[ $._static_dim_list, $._static_dim_list ],
467                    [ $.dictionary_attribute, $.region ]],
468  rules : Object.assign(common, builtin_dialect, func_dialect, llvm_dialect,
469                        arith_dialect, math_dialect, cf_dialect, scf_dialect,
470                        memref_dialect, vector_dialect, tensor_dialect,
471                        bufferization_dialect, affine_dialect, linalg_dialect)
472});
473