1module.exports = grammar({ 2 name : 'mlir', 3 extras : $ => [/\s/, 4 $.comment, 5], 6 conflicts : $ => [], 7 rules : { 8 // Top level production: 9 // (operation | attribute-alias-def | type-alias-def) 10 toplevel : $ => seq(choice( 11 $.operation, 12 $.attribute_alias_def, 13 $.type_alias_def, 14 )), 15 16 // Common syntax (lang-ref) 17 // digit ::= [0-9] 18 // hex_digit ::= [0-9a-fA-F] 19 // letter ::= [a-zA-Z] 20 // id-punct ::= [$._-] 21 // 22 // integer-literal ::= decimal-literal | hexadecimal-literal 23 // decimal-literal ::= digit+ 24 // hexadecimal-literal ::= `0x` hex_digit+ 25 // float-literal ::= [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)? 26 // string-literal ::= `"` [^"\n\f\v\r]* `"` TODO: define escaping rules 27 // 28 _digit : $ => /[0-9]/, 29 _hex_digit : $ => /[0-9a-fA-F]/, 30 integer_literal : $ => choice($._decimal_literal, $._hexadecimal_literal), 31 _decimal_literal : $ => repeat1($._digit), 32 _hexadecimal_literal : $ => seq('0x', repeat1($._hex_digit)), 33 float_literal : $ => token( 34 seq(optional(/[-+]/), repeat1(/[0_9]/), 35 optional(seq('.', repeat(/[0-9]/), 36 optional(seq(/[eE]/, optional(/[-+]/), 37 repeat1(/[0-9]/))))))), 38 string_literal : $ => seq( 39 '"', 40 repeat(token.immediate(prec(1, /[^\\"\n\f\v\r]+/))), 41 '"', 42 ), 43 44 // Identifiers 45 // bare-id ::= (letter|[_]) (letter|digit|[_$.])* 46 // bare-id-list ::= bare-id (`,` bare-id)* 47 // value-id ::= `%` suffix-id 48 // suffix-id ::= (digit+ | ((letter|id-punct) (letter|id-punct|digit)*)) 49 // alias-name :: = bare-id 50 // 51 // symbol-ref-id ::= `@` (suffix-id | string-literal) (`::` 52 // symbol-ref-id)? 53 // value-id-list ::= value-id (`,` value-id)* 54 // 55 // // Uses of value, e.g. in an operand list to an operation. 56 // value-use ::= value-id 57 // value-use-list ::= value-use (`,` value-use)* 58 bare_id : $ => seq(token(/[a-zA-Z_]/), 59 token.immediate(repeat(/[a-zA-Z0-9_$]/))), 60 bare_id_list : $ => seq($.bare_id, repeat(seq(',', $.bare_id))), 61 value_id : $ => seq('%', $._suffix_id), 62 alias_name : $ => $.bare_id, 63 _suffix_id : $ => choice(repeat1(/[0-9]/), 64 seq(/[a-zA-Z_$.]/, repeat(/[a-zA-Z0-9_$.]/))), 65 symbol_ref_id : $ => seq('@', choice($._suffix_id, $.string_literal), 66 optional(seq('::', $.symbol_ref_id))), 67 value_use : $ => $.value_id, 68 value_use_list : $ => seq($.value_use, repeat(seq(',', $.value_use))), 69 70 // Operations 71 // operation ::= op-result-list? (generic-operation | 72 // custom-operation) 73 // trailing-location? 74 // generic-operation ::= string-literal `(` value-use-list? `)` 75 // successor-list? 76 // region-list? dictionary-attribute? `:` 77 // function-type 78 // custom-operation ::= bare-id custom-operation-format 79 // op-result-list ::= op-result (`,` op-result)* `=` 80 // op-result ::= value-id (`:` integer-literal) 81 // successor-list ::= `[` successor (`,` successor)* `]` 82 // successor ::= caret-id (`:` bb-arg-list)? 83 // region-list ::= `(` region (`,` region)* `)` 84 // dictionary-attribute ::= `{` (attribute-entry (`,` attribute-entry)*)? 85 // `}` 86 // trailing-location ::= (`loc` `(` location `)`)? 87 operation : $ => seq(optional($.op_result_list), 88 choice($.generic_operation, $.custom_operation), 89 optional($.trailing_location)), 90 generic_operation : $ => 91 seq($.string_literal, '(', optional($.value_use_list), 92 ')', optional($.successor_list), 93 optional($.region_list), 94 optional($.dictionary_attribute), ':', 95 $.function_type), 96 // custom-operation rule is defined later in the grammar, post the generic. 97 op_result_list : $ => seq($.op_result, repeat(seq(',', $.op_result)), '='), 98 op_result : $ => seq($.value_id, optional(seq(':', $.integer_literal))), 99 successor_list : $ => seq('[', $.successor, repeat(seq(',', $.successor)), 100 ']'), 101 successor : $ => seq($.caret_id, optional(seq(':', $.block_arg_list))), 102 region_list : $ => seq('(', $.region, repeat(seq(',', $.region)), ')'), 103 dictionary_attribute : $ => seq( 104 '{', 105 optional(seq($.attribute_entry, 106 repeat(seq(',', $.attribute_entry)))), 107 '}'), 108 trailing_location : $ => seq('loc(', $.location, ')'), 109 // TODO: Complete location forms. 110 location : $ => $.string_literal, 111 112 // Blocks 113 // block ::= block-label operation+ 114 // block-label ::= block-id block-arg-list? `:` 115 // block-id ::= caret-id 116 // caret-id ::= `^` suffix-id 117 // value-id-and-type ::= value-id `:` type 118 // 119 // // Non-empty list of names and types. 120 // value-id-and-type-list ::= value-id-and-type (`,` value-id-and-type)* 121 // 122 // block-arg-list ::= `(` value-id-and-type-list? `)` 123 block : $ => seq($.block_label, repeat1($.operation)), 124 block_label : $ => seq($._block_id, optional($.block_arg_list), ':'), 125 _block_id : $ => $.caret_id, 126 caret_id : $ => seq('^', $._suffix_id), 127 value_id_and_type : $ => seq($.value_id, ':', $.type), 128 value_id_and_type_list : $ => seq($.value_id_and_type, 129 repeat(seq(',', $.value_id_and_type))), 130 block_arg_list : $ => seq('(', optional($.value_id_and_type_list), ')'), 131 132 // Regions 133 // region ::= `{` entry-block? block* `}` 134 // entry-block ::= operation+ 135 region : $ => seq('{', optional($.entry_block), repeat($.block), '}'), 136 entry_block : $ => repeat1($.operation), 137 138 // Types 139 // type ::= type-alias | dialect-type | builtin-type 140 // 141 // type-list-no-parens ::= type (`,` type)* 142 // type-list-parens ::= `(` type-list-no-parens? `)` 143 // 144 // // This is a common way to refer to a value with a specified type. 145 // ssa-use-and-type ::= ssa-use `:` type 146 // ssa-use ::= value-use 147 // 148 // // Non-empty list of names and types. 149 // ssa-use-and-type-list ::= ssa-use-and-type (`,` ssa-use-and-type)* 150 // 151 // function-type ::= (type | type-list-parens) `->` (type | 152 // type-list-parens) 153 type : $ => choice($.type_alias, $.dialect_type, $.builtin_type), 154 type_list_no_parens : $ => seq($.type, repeat(seq(',', $.type))), 155 type_list_parens : $ => seq('(', optional($.type_list_no_parens), ')'), 156 ssa_use_and_type : $ => seq($.ssa_use, ':', $.type), 157 ssa_use : $ => $.value_use, 158 ssa_use_and_type_list : $ => seq($.ssa_use_and_type, 159 repeat(seq(',', $.ssa_use_and_type))), 160 function_type : $ => seq(choice($.type, $.type_list_parens), '->', 161 choice($.type, $.type_list_parens)), 162 163 // Type aliases 164 // type-alias-def ::= '!' alias-name '=' type 165 // type-alias ::= '!' alias-name 166 type_alias_def : $ => seq('!', $.alias_name, '=', $.type), 167 type_alias : $ => seq('!', $.alias_name), 168 169 // Dialect Types 170 // dialect-namespace ::= bare-id 171 // 172 // opaque-dialect-item ::= dialect-namespace '<' string-literal '>' 173 // 174 // pretty-dialect-item ::= dialect-namespace '.' 175 // pretty-dialect-item-lead-ident 176 // pretty-dialect-item-body? 177 // 178 // pretty-dialect-item-lead-ident ::= '[A-Za-z][A-Za-z0-9._]*' 179 // pretty-dialect-item-body ::= '<' pretty-dialect-item-contents+ '>' 180 // pretty-dialect-item-contents ::= pretty-dialect-item-body 181 // | '(' pretty-dialect-item-contents+ ')' 182 // | '[' pretty-dialect-item-contents+ ']' 183 // | '{' pretty-dialect-item-contents+ '}' 184 // | '[^[<({>\])}\0]+' 185 // 186 // dialect-type ::= '!' (opaque-dialect-item | pretty-dialect-item) 187 dialect_type : $ => seq( 188 '!', choice($.opaque_dialect_item, $.pretty_dialect_item)), 189 dialect_namespace : $ => $.bare_id, 190 opaque_dialect_item : $ => seq($.dialect_namespace, '<', $.string_literal, 191 '>'), 192 pretty_dialect_item : $ => seq($.dialect_namespace, '.', 193 $.pretty_dialect_item_lead_ident, 194 optional($.pretty_dialect_item_body)), 195 pretty_dialect_item_lead_ident : $ => $.bare_id, 196 pretty_dialect_item_body : $ => seq('<', 197 repeat1($.pretty_dialect_item_contents), 198 '>'), 199 // TODO: not sure why prec.left (setting left-associated parsing) needed 200 // here, 201 // left-associated way avoids an ambiguity flagged by generator. It may not 202 // be needed and be only papering over an issue. 203 pretty_dialect_item_contents : $ => prec.left(choice( 204 $.pretty_dialect_item_body, 205 seq('(', 206 repeat1( 207 $.pretty_dialect_item_contents), 208 ')'), 209 seq('[', 210 repeat1( 211 $.pretty_dialect_item_contents), 212 ']'), 213 seq('{', 214 repeat1( 215 $.pretty_dialect_item_contents), 216 '}'), 217 repeat1(/[^\[<({>\])}\\0]/))), 218 dialect_type : $ => seq( 219 '!', choice($.opaque_dialect_item, $.pretty_dialect_item)), 220 221 // Builtin types 222 builtin_type : $ => choice( 223 // TODO: Add builtin types 224 seq('i', repeat1(/[0-9]/))), 225 226 // Attributes 227 // attribute-entry ::= (bare-id | string-literal) `=` attribute-value 228 // attribute-value ::= attribute-alias | dialect-attribute | 229 // builtin-attribute 230 attribute_entry : $ => seq(choice($.bare_id, $.string_literal), '=', 231 $.attribute_value), 232 attribute_value : $ => choice($.attribute_alias, $.dialect_attribute, 233 $.builtin_attribute), 234 235 // Attribute Value Aliases 236 // attribute-alias-def ::= '#' alias-name '=' attribute-value 237 // attribute-alias ::= '#' alias-name 238 attribute_alias_def : $ => seq('#', $.alias_name, '=', $.attribute_value), 239 attribute_alias : $ => seq('#', $.alias_name), 240 241 // Dialect Attribute Values 242 dialect_attribute : $ => seq('#', choice($.opaque_dialect_item, 243 $.pretty_dialect_item)), 244 245 // Builtin Attribute Values 246 builtin_attribute : $ => choice( 247 // TODO 248 $.function_type, 249 $.string_literal, 250 ), 251 252 // Comment (standard BCPL) 253 comment : $ => token(seq('//', /.*/)), 254 255 custom_operation : $ => choice( 256 // TODO: Just basic/incomplete instance. 257 seq('func', field('name', $.symbol_ref_id), 258 $.block_arg_list, '->', $.type, $.region), 259 ), 260 } 261}); 262