module.exports = grammar({
name: 'tablegen',
externals: $ => [
$.multiline_comment,
],
extras: $ => [
$.comment,
$.multiline_comment,
$.preprocessor_directive,
/\s/,
],
supertypes: $ => [
$.simple_value,
$.statement,
$.type,
],
word: $ => $.identifier,
rules: {
tablegen_file: $ => repeat(choice(
$.statement,
$.preprocessor_directive,
)),
include_directive: $ => seq('include', $.string),
preprocessor_directive: _ => token(choice(
seq(
choice('#define', '#ifdef', '#ifndef'),
/\s+/,
field('macro_name', /[a-zA-Z_][a-zA-Z_0-9]*/),
),
'#else',
'#endif',
)),
statement: $ => choice(
$.assert,
$.class,
$.def,
$.defm,
$.defset,
$.defvar,
$.foreach,
$.if,
$.let,
$.multiclass,
$.include_directive,
),
block: $ => choice(
$.statement,
seq('{', repeat($.statement), '}'),
),
class: $ => seq(
'class',
field('name', $.identifier),
optional($.template_args),
field('body', $.record_body),
),
template_args: $ => seq('<', optionalCommaSep($.template_arg), '>'),
template_arg: $ => seq(
$.type,
$.identifier,
optional(seq('=', $.value)),
),
record_body: $ => seq(
optional($.parent_class_list),
$.body,
),
parent_class_list: $ => seq(
':',
commaSep1(seq(
$.identifier,
optional(seq('<', optionalCommaSep($.value), '>')),
)),
),
body: $ => choice(
';',
seq('{', repeat($.body_item), '}'),
),
body_item: $ => choice(
$.instruction,
$.let_instruction,
$.def_var,
$.assert,
),
instruction: $ => seq(
optional('field'), choice($.type, 'code'),
$.identifier,
optional(seq('=', $.value)),
';',
),
let_instruction: $ => seq(
'let',
$.identifier,
optional(seq('{', $.range_list, '}')),
'=',
$.value,
';',
),
def_var: $ => seq(
'defvar',
field('name', $.identifier),
'=',
$.value,
';',
),
def: $ => seq(
'def',
field('name', optional($.value)),
$.record_body,
),
let: $ => seq(
'let',
$.let_list,
'in',
choice($.statement, seq('{', repeat($.statement), '}')),
),
let_list: $ => optionalCommaSep1($.let_item),
let_item: $ => seq(
$.identifier,
optional(seq('<', $.range_list, '>')),
'=',
$.value,
),
multiclass: $ => seq(
'multiclass',
field('name', $.identifier),
optional($.template_args),
optional($.parent_class_list),
$.multiclass_body,
),
multiclass_body: $ => choice(
';',
seq('{', repeat1($.multiclass_statement), '}'),
),
multiclass_statement: $ => choice(
$.assert,
$.def,
$.defm,
$.defvar,
$.foreach,
$.if,
$.let,
),
defm: $ => seq(
'defm',
field('name', optional($.value)),
optional($.parent_class_list),
';',
),
defset: $ => seq(
'defset',
$.type,
field('name', $.identifier),
'=',
'{',
repeat($.statement),
'}',
),
defvar: $ => seq('defvar', $.identifier, '=', $.value, ';'),
foreach: $ => seq('foreach', $.foreach_iterator, 'in', $.block),
foreach_iterator: $ => seq(
$.identifier,
'=',
choice(
seq('{', $.range_list, '}'),
$.range_piece,
$.value,
),
),
if: $ => prec.left(seq(
'if',
$.value,
'then',
$.block,
optional(seq('else', $.block)),
)),
assert: $ => seq('assert', $.value, ',', $.value, ';'),
type: $ => choice(
$.primitive_type,
$.bits_type,
$.list_type,
alias($.identifier, $.class_identifier),
),
primitive_type: _ => choice('bit', 'int', 'string', 'dag'),
bits_type: $ => seq('bits', '<', $.integer, '>'),
list_type: $ => seq('list', '<', $.type, '>'),
value: $ => prec.left(choice(
seq($.simple_value, repeat($.value_suffix)),
$.paste_value,
)),
paste_value: $ => prec.right(seq($.value, '#', optional($.value))),
value_suffix: $ => choice(
seq('{', $.range_list, '}'),
seq('[', $.range_list, ']'),
seq('.', $.identifier),
),
value_list: $ => optionalCommaSep1($.value),
range_list: $ => commaSep1($.range_piece),
range_piece: $ => prec(1, choice(
seq($.value, '...', $.value),
seq($.value, '-', $.value),
$.value,
)),
simple_value: $ => prec.right(choice(
$.integer,
$.string,
$.concatenated_string,
$.code,
$.boolean,
alias('?', $.uninitialized_value),
$.sequence,
$.list_initializer,
$.dag_initializer,
$.identifier,
$.anonymous_record,
$.operator,
)),
sequence: $ => seq('{', $.value_list, '}'),
list_initializer: $ => seq(
'[',
optional($.value_list),
']',
optional(seq('<', $.type, '>')),
),
dag_initializer: $ => seq(
'(',
$.dag_arg,
optional($.dag_arg_list),
')',
),
dag_arg_list: $ => optionalOptionalCommaSep1($.dag_arg),
dag_arg: $ => choice(
seq($.value, optional(seq(':', $.var))),
$.var,
),
anonymous_record: $ => seq($.identifier, '<', commaSep($.value), '>'),
concatenated_string: $ => prec.right(
seq($.string, repeat1($.string)),
),
operator: $ => choice(
seq(
$.bang_operator,
optional(seq('<', $.type, '>')),
'(',
$.value_list,
')',
),
seq($.cond_operator, '(', optionalCommaSep($.cond_clause), ')'),
),
cond_clause: $ => seq($.value, ':', $.value),
bang_operator: _ => seq(
'!',
choice(
'add',
'and',
'cast',
'con',
'dag',
'div',
'empty',
'eq',
'exists',
'filter',
'find',
'foldl',
'foreach',
'ge',
'getop',
'getdagop',
'gt',
'head',
'if',
'interleave',
'isa',
'le',
'listconcat',
'listremove',
'listsplat',
'logtwo',
'lt',
'mul',
'ne',
'not',
'or',
'setop',
'setdagop',
'shl',
'size',
'sra',
'srl',
'strconcat',
'sub',
'subst',
'substr',
'tail',
'tolower',
'toupper',
'xor',
),
),
cond_operator: _ => seq('!', 'cond'),
integer: _ => {
const decimal = /[+-]?\d+/;
const hex = /0x[\da-fA-F]+/;
const bin = /0b[01]+/;
return token(choice(decimal, hex, bin));
},
string: $ => seq(
'"',
repeat(choice(
$.string_content,
$._escape_sequence,
)),
'"',
),
string_content: _ => token.immediate(prec(1, /[^"\\]+/)),
_escape_sequence: $ => choice(
prec(2, token.immediate(seq('\\', /[^abfnrtvxu'\"\\\?]/))),
prec(1, $.escape_sequence),
),
escape_sequence: _ => token.immediate(seq(
'\\',
choice(
/[^xu0-7]/,
/[0-7]{1,3}/,
/x[0-9a-fA-F]{2}/,
/u[0-9a-fA-F]{4}/,
/u{[0-9a-fA-F]+}/,
/U[0-9a-fA-F]{8}/,
))),
code: _ => /\[\{([^}]|\}+[^}\]])*\}\]/,
code_content: _ => token.immediate(prec(1, /[^\\}]+/)),
_code_escape_sequence: $ => choice(
prec(2, token.immediate(seq('\\', /[^tn'\"\\]/))),
prec(1, $.code_escape_sequence),
),
code_escape_sequence: _ => token.immediate(seq(
'\\',
/[tn'\"\\]/,
)),
boolean: _ => choice('true', 'false'),
identifier: _ => /[0-9]*[a-zA-Z_][a-zA-Z0-9_]*/,
var: _ => /\$[a-zA-Z_][a-zA-Z0-9_]*/,
comment: _ => /\/\/[^\n\r]*/,
},
});
function optionalCommaSep(rule) {
return seq(commaSep(rule), optional(','));
}
function optionalCommaSep1(rule) {
return seq(commaSep1(rule), optional(','));
}
function commaSep(rule) {
return optional(commaSep1(rule));
}
function commaSep1(rule) {
return seq(rule, repeat(seq(',', rule)));
}
function optionalOptionalCommaSep1(rule) {
return seq(rule, repeat(seq(optional(','), rule)), optional(','));
}