tree-sitter-streamdevice-proto
Version:
tree-sitter grammar for StreamDevice's .proto files
218 lines (194 loc) • 6.25 kB
JavaScript
/**
* @file tree-sitter grammar for StreamDevice's .proto files
* @author Rémi NICOLE
* @license MIT
*/
/// <reference types="tree-sitter-cli/dsl" />
// @ts-check
const IDENTIFIER = /[a-zA-Z][\w-]*/;
module.exports = grammar({
name: "streamdevice_proto",
extras: ($) => [/\s/, $.comment],
rules: {
source_file: ($) =>
repeat(
seq(
choice($.comment, $.function, seq($.assignment, ";"), $.handler, ";")
)
),
comment: ($) => seq("#", /.*/),
assignment: ($) => seq($.variable_name, "=", $._value),
variable_name: ($) => $._identifier,
variable: ($) =>
seq("$", alias(token.immediate(IDENTIFIER), $.variable_name)),
_value: ($) => choice($.string, $.keyword),
keyword: ($) => choice(/error/i, /ignore/i),
function: ($) =>
seq(
$.function_name,
"{",
repeat(seq(choice($.assignment, $.command, $.handler), ";")),
optional(choice($.assignment, $.command, $.handler)),
"}"
),
function_name: ($) => $._identifier,
command: ($) =>
seq($.command_name, optional(seq("(", $._value, ")")), $._value),
command_name: ($) => $._identifier,
handler: ($) =>
seq(
"@",
$.handler_name,
"{",
repeat(seq(choice($.function_name, $.command), ";")),
optional(choice($.function_name, $.command)),
"}"
),
handler_name: ($) => token.immediate(IDENTIFIER),
string: ($) =>
seq(
repeat(
seq(choice($.variable, $.number, $.ascii_name, $.quoted_literal), optional(","))
),
choice($.variable, $.number, $.ascii_name, $.quoted_literal)
),
quoted_literal: ($) =>
choice($._double_quoted_string, $._single_quoted_string),
_double_quoted_string: ($) =>
seq(
'"',
repeat(
choice(
$.variable_expansion,
$.escape_sequence,
$.format_converter,
$._quoted_string_text_fragment
)
),
'"'
),
_single_quoted_string: ($) =>
seq(
"'",
repeat(
choice(
$.variable_expansion,
$.escape_sequence,
$.format_converter,
$._quoted_string_text_fragment2
)
),
"'"
),
_quoted_string_text_fragment: ($) => token.immediate(/[^"\\%]+/),
_quoted_string_text_fragment2: ($) => token.immediate(/[^'\\%]+/),
variable_expansion: ($) =>
choice(
seq(
token.immediate("\\$"),
alias(choice(token.immediate(IDENTIFIER), /[1-9]/), $.variable_name),
),
seq(
token.immediate("\\${"),
alias(choice(token.immediate(IDENTIFIER), /[1-9]/), $.variable_name),
"}",
)
),
escape_sequence: ($) =>
choice(
token.immediate(/\\["'%\\abtnre?_]/),
token.immediate(/\\x[a-fA-F0-9]{1,2}/),
token.immediate(/\\0[0-7]{1,3}/),
token.immediate(/\\[1-9][0-9]{0,2}/),
token.immediate("%%")
),
format_converter: ($) =>
seq(
token.immediate("%"),
optional(
seq(token.immediate("("), $.format_inout, token.immediate(")"))
),
optional($.format_flag),
field(
"width",
optional(alias(token.immediate(/[0-9]+/), $.number))
),
optional(
seq(
token.immediate("."),
field(
"precision",
alias(token.immediate(/[0-9]+/), $.number)
)
)
),
choice(
/[feEgGdDiuoxXscbrRm]/,
seq(token.immediate("["), optional($.charset), token.immediate("]")),
seq(token.immediate("{"), $.format_enum, token.immediate("}")),
seq(token.immediate("B"), $._char, $._char),
seq(
token.immediate("<"),
optional($.checksum_flag),
$.checksum,
token.immediate(">")
),
seq(token.immediate("/"), $.regex_pattern, token.immediate("/")),
seq(
token.immediate("#/"),
$.regex_pattern,
token.immediate("/"),
$.regex_pattern,
token.immediate("/")
),
seq(
token.immediate("T"),
token.immediate("("),
$.timeformat,
token.immediate(")")
)
)
),
format_inout: ($) =>
choice(
$.field_name,
$.record_name,
seq($.record_name, ".", $.field_name)
),
// Necessary to put the "#" apart to disambiguate with the comments
format_flag: ($) =>
choice(token.immediate("#"), token.immediate(/[* +0?=!-]/)),
charset: ($) => seq(optional("^"), repeat1(choice(/[^\]]/, "\\]"))),
format_enum: ($) =>
seq(repeat(seq($.enum_specifier, "|")), $.enum_specifier),
enum_specifier: ($) =>
seq($.enum_constant, optional(seq("=", choice($.number, "?")))),
enum_constant: ($) => repeat1(choice($.variable_expansion, /\w+/)),
_char: ($) => choice(token.immediate(/./), $.escape_sequence),
checksum_flag: ($) => /[0+-~]/,
checksum: ($) => repeat1(choice($.variable_expansion, $._identifier)),
// Taken from:
// https://github.com/tree-sitter/tree-sitter-javascript/blob/master/grammar.js
regex_pattern: ($) =>
token.immediate(
repeat1(
choice(
seq("[", repeat(choice(seq("\\", /./), /[^\]\n\\]/)), "]"),
seq("\\", /./),
/[^/\\\[\n]/
)
)
),
timeformat: ($) =>
repeat1(choice(alias(/[^)%]+/, $.thing), $.time_conversion_spec)),
time_conversion_spec: ($) => token.immediate(/%[EO_0^#.-]?\d*[a-zA-Z+%]+/),
record_name: ($) => repeat1(choice(/[\w:]+/, $.escape_sequence, $.variable_expansion)),
field_name: ($) =>
repeat1(prec(-1, choice($._identifier, $.escape_sequence, $.variable_expansion))),
// number: ($) => choice($.ascii_name, $.number_literal),
number: ($) =>
seq(optional("-"), choice(/0x[A-F0-9]+/i, /0[0-7]+/, /[0-9]+/)),
ascii_name: ($) => choice(/[A-Z][A-Z0-9]*/i, "?"),
_identifier: ($) => IDENTIFIER,
},
});