Add Tree-sitter grammar for Decodal
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
const PREC = {
|
||||
DEFAULT: 1,
|
||||
PATCH: 2,
|
||||
AND: 3,
|
||||
CALL: 7,
|
||||
PATH: 8,
|
||||
};
|
||||
|
||||
function commaSep(rule) {
|
||||
return optional(seq(rule, repeat(seq(',', rule)), optional(',')));
|
||||
}
|
||||
|
||||
function semiSep(rule) {
|
||||
return optional(seq(rule, repeat(seq(';', rule)), optional(';')));
|
||||
}
|
||||
|
||||
module.exports = grammar({
|
||||
name: 'decodal',
|
||||
|
||||
extras: $ => [
|
||||
/[\s\uFEFF\u2060\u200B]/,
|
||||
$.comment,
|
||||
],
|
||||
|
||||
word: $ => $.identifier,
|
||||
|
||||
conflicts: $ => [
|
||||
[$._expression, $.parameter],
|
||||
],
|
||||
|
||||
rules: {
|
||||
source_file: $ => repeat($._statement),
|
||||
|
||||
_statement: $ => choice(
|
||||
seq($.field_definition, optional(';')),
|
||||
seq($._expression, optional(';')),
|
||||
),
|
||||
|
||||
comment: _ => token(seq('#', /.*/)),
|
||||
|
||||
_expression: $ => choice(
|
||||
$.literal,
|
||||
$.identifier,
|
||||
$.regex_literal,
|
||||
$.comparison_constraint,
|
||||
$.object,
|
||||
$.array,
|
||||
$.let_expression,
|
||||
$.function_expression,
|
||||
$.match_expression,
|
||||
$.import_expression,
|
||||
$.parenthesized_expression,
|
||||
$.call_expression,
|
||||
$.path_expression,
|
||||
$.binary_expression,
|
||||
$.default_expression,
|
||||
),
|
||||
|
||||
literal: $ => choice(
|
||||
$.string,
|
||||
$.integer,
|
||||
$.float,
|
||||
$.boolean,
|
||||
),
|
||||
|
||||
boolean: _ => choice('true', 'false'),
|
||||
|
||||
string: _ => token(seq(
|
||||
'"',
|
||||
repeat(choice(/[^"\\\n]/, /\\./)),
|
||||
'"',
|
||||
)),
|
||||
|
||||
integer: _ => token(/[0-9]+/),
|
||||
float: _ => token(/[0-9]+\.[0-9]+/),
|
||||
|
||||
identifier: _ => /[A-Za-z][A-Za-z0-9_]*/,
|
||||
|
||||
regex_literal: _ => token(seq(
|
||||
'/',
|
||||
repeat1(choice(/[^\/\\\n]/, /\\./)),
|
||||
'/',
|
||||
)),
|
||||
|
||||
object: $ => seq(
|
||||
'{',
|
||||
semiSep($.field_definition),
|
||||
'}',
|
||||
),
|
||||
|
||||
field_definition: $ => seq(
|
||||
field('path', $.field_path),
|
||||
'=',
|
||||
field('value', $._expression),
|
||||
),
|
||||
|
||||
field_path: $ => prec(10, seq(
|
||||
$.identifier,
|
||||
repeat(seq('.', $.identifier)),
|
||||
)),
|
||||
|
||||
array: $ => seq(
|
||||
'[',
|
||||
commaSep($._expression),
|
||||
']',
|
||||
),
|
||||
|
||||
let_expression: $ => seq(
|
||||
'let',
|
||||
repeat(seq($.field_definition, ';')),
|
||||
'in',
|
||||
field('body', $._expression),
|
||||
),
|
||||
|
||||
function_expression: $ => prec.right(seq(
|
||||
'(',
|
||||
commaSep($.parameter),
|
||||
')',
|
||||
'=>',
|
||||
field('body', $._expression),
|
||||
)),
|
||||
|
||||
parameter: $ => seq(
|
||||
field('name', $.identifier),
|
||||
optional(seq(':', field('constraint', $._expression))),
|
||||
),
|
||||
|
||||
match_expression: $ => seq(
|
||||
'match',
|
||||
field('scrutinee', $._expression),
|
||||
'{',
|
||||
semiSep($.match_arm),
|
||||
'}',
|
||||
),
|
||||
|
||||
match_arm: $ => seq(
|
||||
field('pattern', choice('_', $._expression)),
|
||||
':',
|
||||
field('body', $._expression),
|
||||
),
|
||||
|
||||
import_expression: $ => seq(
|
||||
'import',
|
||||
field('specifier', $.string),
|
||||
),
|
||||
|
||||
parenthesized_expression: $ => seq('(', $._expression, ')'),
|
||||
|
||||
call_expression: $ => prec.left(PREC.CALL, seq(
|
||||
field('function', $._expression),
|
||||
'(',
|
||||
commaSep($._expression),
|
||||
')',
|
||||
)),
|
||||
|
||||
path_expression: $ => prec.left(PREC.PATH, seq(
|
||||
field('object', $._expression),
|
||||
'.',
|
||||
field('field', $.identifier),
|
||||
)),
|
||||
|
||||
comparison_constraint: $ => prec(6, seq(
|
||||
field('operator', choice('>', '>=', '<', '<=')),
|
||||
field('value', choice($.integer, $.float)),
|
||||
)),
|
||||
|
||||
binary_expression: $ => choice(
|
||||
prec.left(PREC.AND, seq(
|
||||
field('left', $._expression),
|
||||
field('operator', '&'),
|
||||
field('right', $._expression),
|
||||
)),
|
||||
prec.left(PREC.PATCH, seq(
|
||||
field('left', $._expression),
|
||||
field('operator', token(prec(2, '//'))),
|
||||
field('right', $._expression),
|
||||
)),
|
||||
),
|
||||
|
||||
default_expression: $ => prec.right(PREC.DEFAULT, seq(
|
||||
field('base', $._expression),
|
||||
'default',
|
||||
field('fallback', $._expression),
|
||||
)),
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user