tree-sitter-tiger/grammar.js

191 lines
3.8 KiB
JavaScript
Raw Normal View History

2022-06-01 19:34:31 +02:00
function sepBy1(sep, rule) {
return seq(rule, repeat(seq(sep, rule)))
}
function sepBy(sep, rule) {
return optional(sepBy1(sep, rule))
}
const PREC = {
2022-06-01 20:11:52 +02:00
assign: 6,
multiplicative: 5,
additive: 4,
comparative: 3,
and: 2,
or: 1,
};
module.exports = grammar({
name: "tiger",
// Ensure we don't extract keywords from tokens
word: ($) => $.identifier,
2022-06-01 20:07:00 +02:00
conflicts: ($) => [
[$._lvalue, $.array_expression],
],
rules: {
2022-06-01 19:33:42 +02:00
source_file: ($) => choice(
$._expr,
),
_expr: ($) => choice(
$.nil_literal,
2022-06-01 19:33:42 +02:00
$.integer_literal,
$.string_literal,
2022-06-01 19:34:31 +02:00
2022-06-01 19:48:54 +02:00
$.array_expression,
2022-06-01 19:54:09 +02:00
$.record_expression,
2022-06-01 19:48:54 +02:00
2022-06-01 20:07:00 +02:00
$._lvalue,
2022-06-01 19:58:40 +02:00
$.function_call,
2022-06-01 19:34:31 +02:00
$.unary_expression,
$.binary_expression,
$.sequence_expression,
2022-06-01 20:11:52 +02:00
$.assignment_expression,
2022-06-01 20:18:10 +02:00
$.if_expression,
2022-06-01 19:33:42 +02:00
),
nil_literal: (_) => "nil",
2022-06-01 19:33:42 +02:00
integer_literal: (_) => /[0-9]+/,
string_literal: ($) => seq(
'"',
repeat(choice($.escape_sequence, /[^"\\]+/)),
'"',
),
// NOTE: includes reserved identifiers
identifier: (_) => /[_a-zA-Z0-9]+/,
2022-06-01 19:33:42 +02:00
escape_sequence: (_) => token.immediate(
seq(
"\\",
choice(
// Special escapes
choice("a", "b", "f", "n", "r", "t", "v"),
// Octal
/[0-3][0-7]{2}/,
// Hexadecimal
seq("x", /[0-9a-fA-F]{2}/),
// Escaped characters
choice("\\", '"'),
)
)
),
2022-06-01 19:34:31 +02:00
2022-06-01 20:07:00 +02:00
_lvalue: ($) => choice(
$.identifier,
$.record_value,
$.array_value,
),
record_value: ($) => seq(
field("record", $._lvalue),
".",
field("field", $.identifier),
),
array_value: ($) => seq(
field("array", $._lvalue),
"[",
field("index", $._expr),
"]",
),
2022-06-01 19:58:40 +02:00
function_call: ($) => seq(
field("function", $.identifier),
"(",
field("arguments", sepBy(",", $._expr)),
")",
),
2022-06-01 19:34:31 +02:00
unary_expression: ($) => seq(
field("operator", alias("-", $.operator)),
field("expression", $._expr),
),
binary_expression: ($) => {
const table = [
[PREC.multiplicative, prec.left, choice("*", "/")],
[PREC.additive, prec.left, choice("+", "-")],
2022-06-01 19:34:31 +02:00
// FIXME: comparisons should be non-associative
// See https://github.com/tree-sitter/tree-sitter/issues/761
[PREC.comparative, prec.left, choice(">=", "<=", "=", "<>", "<", ">")],
[PREC.and, prec.left, "&"],
[PREC.or, prec.left, "|"],
2022-06-01 19:34:31 +02:00
];
return choice(
...table.map(
([priority, assoc, operator]) => assoc(
priority,
seq(
field("left", $._expr),
field("operator", alias(operator, $.operator)),
field("right", $._expr),
)
)
)
);
},
sequence_expression: ($) => seq("(", sepBy(";", $._expr), ")"),
2022-06-01 19:48:54 +02:00
array_expression: ($) => seq(
field("type", $.identifier),
"[",
field("size", $._expr),
"]",
"of",
field("init", $._expr),
),
2022-06-01 19:54:09 +02:00
record_expression: ($) => seq(
field("type", $.identifier),
"{",
sepBy(
",",
seq(
field("field", $.identifier),
"=",
field("init", $._expr),
),
),
"}",
),
2022-06-01 20:11:52 +02:00
assignment_expression: ($) => prec.right(
PREC.assign,
seq(
field("left", $._lvalue),
":=",
field("right", $._expr),
),
),
2022-06-01 20:18:10 +02:00
if_expression: ($) => prec.right(
seq(
"if",
field("condition", $._expr),
"then",
field("consequence", $._expr),
optional(
seq(
"else",
field("alternative", $._expr),
),
),
),
),
}
});
// vim: sw=2