1461 lines
36 KiB
JavaScript
1461 lines
36 KiB
JavaScript
const kPrec = {
|
|
kIdentifier: -1, // 标识符
|
|
|
|
kIf: 0,
|
|
kElif: 1,
|
|
|
|
kExprOperator: 1, // @ &
|
|
kAssignment: 2, // := += -= /= *= ...
|
|
kTernary: 3, // ?:
|
|
|
|
kLogicalOr: 4, // or .||
|
|
kLogicalAnd: 5, // and .&&
|
|
|
|
kBitwiseOr: 6, // .|
|
|
kBitwiseXor: 7, // .^
|
|
kBitwiseAnd: 8, // .&
|
|
|
|
kComparsion: 9, // = .= <> .<> > .> <= .<= >= .>= like in is
|
|
|
|
kSet: 10, // union/2 intersect outersect minus
|
|
kMatrixConcat: 10, // :| |
|
|
kRange: 10, // -> 数列初始化
|
|
|
|
kAddSub: 11, // + -
|
|
kShift: 12, // shl rol shr ror
|
|
kTimes: 13, // * / \ % mod div
|
|
kMatrixTimes: 13, // :* :/ :\
|
|
|
|
kLogarithm: 14, // ~
|
|
kDerivative: 14, // ! 求导
|
|
|
|
kConcat: 14, // $
|
|
|
|
kSigned: 15, // ±
|
|
kBitwiseNot: 16, // .!
|
|
kLogicalNot: 16, // not .!!
|
|
kMatrixInverse: 16, // ! 矩阵求逆
|
|
kMatrixTranspose: 16, // ` 矩阵转置
|
|
kFunctionPointer: 16, // ## 函数指针
|
|
kPrefix: 17, // ++ --
|
|
kMatrixPower: 17, // :^
|
|
kPower: 17, // ^
|
|
|
|
kPostfix: 18, // ++ --
|
|
kCall: 18, // func()
|
|
kAttribute: 18, // obj.attr
|
|
kSubscript: 18, // a[] a[:] a[1:] a[:1,2]
|
|
kParenthesized: 19, // (expr)
|
|
|
|
kArray: 20,
|
|
};
|
|
const kSemicolon = ";";
|
|
|
|
module.exports = grammar({
|
|
name: "tsf",
|
|
|
|
word: ($) => $.identifier,
|
|
|
|
conflicts: ($) => [
|
|
[$._left_hand_side, $.primary_expression],
|
|
[$.tssql_select_expression, $._table_or_subquery],
|
|
[$.tslx_close_tag, $.tslx_expression_tag],
|
|
],
|
|
|
|
inline: ($) => [$._statement],
|
|
|
|
extras: ($) => [/\s/, $.line_comment, $.block_comment, $.nested_comment],
|
|
|
|
rules: {
|
|
root: ($) => choice($.unit, repeat($._statement)),
|
|
|
|
_statement: ($) => choice($._simple_statement, $._compound_statement),
|
|
|
|
_simple_statement: ($) =>
|
|
choice(
|
|
$.var_statement,
|
|
$.static_statement,
|
|
$.global_statement,
|
|
$.const_statement,
|
|
|
|
$.assignment_statement,
|
|
$.expression_statement,
|
|
|
|
$.uses_statement,
|
|
$.break_statement,
|
|
$.continue_statement,
|
|
$.return_statement,
|
|
$.inherited_statement,
|
|
),
|
|
|
|
_compound_statement: ($) =>
|
|
choice(
|
|
$.if_statement,
|
|
$.for_statement,
|
|
$.while_statement,
|
|
$.repeat_statement,
|
|
$.case_statement,
|
|
$.try_statement,
|
|
|
|
$.anonymous_function_statement,
|
|
$.function_declaration_statement,
|
|
$.function_definition_statement,
|
|
$.class_definition_statement,
|
|
$.external_method_statement,
|
|
|
|
$.matrix_iteration_statement,
|
|
$._tslx_template_statement,
|
|
),
|
|
|
|
var_statement: ($) => seq($.var_declaration, kSemicolon),
|
|
|
|
static_statement: ($) => seq($.static_declaration, kSemicolon),
|
|
|
|
global_statement: ($) => seq($.global_declaration, kSemicolon),
|
|
|
|
const_statement: ($) =>
|
|
seq(
|
|
kw("const"),
|
|
field("name", $.identifier),
|
|
optional($._type_annotation),
|
|
"=",
|
|
field("value", $.expression),
|
|
kSemicolon,
|
|
),
|
|
|
|
var_declaration: ($) =>
|
|
seq(kw("var"), $._variable_declaration, optional($._type_annotation)),
|
|
|
|
static_declaration: ($) =>
|
|
seq(kw("static"), $._variable_declaration, optional($._type_annotation)),
|
|
|
|
global_declaration: ($) =>
|
|
seq(kw("global"), $._variable_declaration, optional($._type_annotation)),
|
|
|
|
_variable_declaration: ($) => sep1(field("name", $.identifier), ","),
|
|
|
|
_type_annotation: ($) => seq(":", $.type_specification),
|
|
|
|
type_specification: ($) =>
|
|
field(
|
|
"type",
|
|
token(
|
|
choice(
|
|
// array of xxx
|
|
seq("array", /\s+/, "of", /\s+/, /[_a-zA-Z][_a-zA-Z0-9_.]*/),
|
|
/[_a-zA-Z][_a-zA-Z0-9_.]*/,
|
|
),
|
|
),
|
|
),
|
|
|
|
assignment_statement: ($) =>
|
|
choice(
|
|
seq(
|
|
choice($.assignment_expression, $.augmented_assignment_expression),
|
|
kSemicolon,
|
|
),
|
|
seq(
|
|
field("left", $._left_hand_side),
|
|
field("operator", ":="),
|
|
field("right", $.anonymous_function_statement),
|
|
),
|
|
),
|
|
|
|
break_statement: (_) => seq(kw("break"), kSemicolon),
|
|
|
|
continue_statement: (_) => seq(kw("continue"), kSemicolon),
|
|
|
|
return_statement: ($) =>
|
|
seq(kw("return"), optional($.expression), kSemicolon),
|
|
|
|
inherited_statement: ($) => seq($.inherited_expression, kSemicolon),
|
|
|
|
_built_in_expression: ($) =>
|
|
choice($.echo_expression, $.raise_expression, $.new_expression),
|
|
|
|
echo_expression: ($) =>
|
|
prec.left(1, seq(kw("echo"), sep1($.expression, ","))),
|
|
|
|
raise_expression: ($) => seq(kw("raise"), $.expression),
|
|
|
|
inherited_expression: ($) => seq(kw("inherited"), optional($.expression)),
|
|
|
|
new_expression: ($) => seq(kw("new"), $.expression),
|
|
|
|
expression_statement: ($) =>
|
|
seq(choice($.expression, $.tssql_dml_expression), kSemicolon),
|
|
|
|
expression: ($) =>
|
|
choice(
|
|
$.operator_expression,
|
|
$.tssql_select_expression,
|
|
$.primary_expression,
|
|
$._built_in_expression,
|
|
),
|
|
|
|
operator_expression: ($) =>
|
|
choice(
|
|
$.expr_expression,
|
|
|
|
$.ternary_expression,
|
|
|
|
$.logical_or_expression,
|
|
$.logical_and_expression,
|
|
$.logical_not_expression,
|
|
|
|
$.comparison_expression,
|
|
|
|
$.bitwise_or_expression,
|
|
$.bitwise_and_expression,
|
|
$.bitwise_xor_expression,
|
|
$.bitwise_not_expression,
|
|
$.shift_expression,
|
|
|
|
$.addition_expression,
|
|
$.multiplication_expression,
|
|
$.power_expression,
|
|
$.logarithm_expression,
|
|
|
|
$.matrix_multiplication_expression,
|
|
$.matrix_power_expression,
|
|
$.matrix_concatenation_expression,
|
|
$.matrix_transpose_expression,
|
|
$.range_expression,
|
|
|
|
$.set_operation_expression,
|
|
|
|
$.concatenation_expression,
|
|
|
|
$.unary_plus_expression,
|
|
$.unary_minus_expression,
|
|
$.prefix_increment_expression,
|
|
$.prefix_decrement_expression,
|
|
$.postfix_increment_expression,
|
|
$.postfix_decrement_expression,
|
|
$.derivative_expression,
|
|
$.function_pointer_expression,
|
|
),
|
|
|
|
expr_expression: ($) =>
|
|
prec.right(
|
|
kPrec.kExprOperator,
|
|
seq(
|
|
field("operator", choice("@", "&")),
|
|
field("argument", $.expression),
|
|
),
|
|
),
|
|
|
|
assignment_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kAssignment,
|
|
seq(
|
|
field("left", $._left_hand_side),
|
|
field("operator", ":="),
|
|
field("right", $._right_hand_side),
|
|
),
|
|
),
|
|
|
|
augmented_assignment_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kAssignment,
|
|
seq(
|
|
field("left", $._left_hand_side),
|
|
field(
|
|
"operator",
|
|
choice(
|
|
"+=",
|
|
"-=",
|
|
"*=",
|
|
"/=",
|
|
"\\=",
|
|
"^=",
|
|
"~=",
|
|
"%=",
|
|
seq(kw("div"), "="),
|
|
"|=",
|
|
":|=",
|
|
"&=",
|
|
":*=",
|
|
":/=",
|
|
":\\=",
|
|
":^=",
|
|
"::=",
|
|
".|=",
|
|
".&=",
|
|
".||=",
|
|
".&&=",
|
|
".^=",
|
|
seq(kw("union"), "="),
|
|
seq(kw("union2"), "="),
|
|
seq(kw("intersect"), "="),
|
|
seq(kw("outersect"), "="),
|
|
seq(kw("minus"), "="),
|
|
),
|
|
),
|
|
field("right", $._right_hand_side),
|
|
),
|
|
),
|
|
|
|
_with_assignment_expression: ($) =>
|
|
choice(
|
|
$.expression,
|
|
$.assignment_expression,
|
|
$.augmented_assignment_expression,
|
|
),
|
|
|
|
ternary_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kTernary,
|
|
seq(
|
|
field("condition", $.expression),
|
|
"?",
|
|
optional(field("consequence", $._with_assignment_expression)),
|
|
":",
|
|
field("alternative", $._with_assignment_expression),
|
|
),
|
|
),
|
|
|
|
logical_or_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kLogicalOr,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", choice(kw("or"), ".||", "||")),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
logical_and_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kLogicalAnd,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", choice(kw("and"), ".&&", "&&")),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
logical_not_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kLogicalNot,
|
|
seq(
|
|
field("operator", choice(kw("not"), ".!!")),
|
|
field("argument", $.expression),
|
|
),
|
|
),
|
|
|
|
comparison_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kComparsion,
|
|
seq(
|
|
$.expression,
|
|
repeat1(
|
|
seq(
|
|
field(
|
|
"operators",
|
|
choice(
|
|
"=",
|
|
"<>",
|
|
">",
|
|
">=",
|
|
"<",
|
|
"<=",
|
|
".=",
|
|
".<>",
|
|
".>",
|
|
".>=",
|
|
".<",
|
|
".<=",
|
|
$.in,
|
|
kw("is"),
|
|
kw("like"),
|
|
),
|
|
),
|
|
$.expression,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
|
|
bitwise_or_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kBitwiseOr,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", ".|"),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
bitwise_and_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kBitwiseAnd,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", ".&"),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
bitwise_xor_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kBitwiseXor,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", ".^"),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
bitwise_not_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kBitwiseNot,
|
|
seq(field("operator", ".!"), field("argument", $.expression)),
|
|
),
|
|
|
|
shift_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kShift,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", choice(kw("shl"), kw("rol"), kw("shr"), kw("ror"))),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
addition_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kAddSub,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", choice("+", "-")),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
multiplication_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kTimes,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", choice("*", "/", "\\", "%", kw("mod"), kw("div"))),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
power_expression: ($) =>
|
|
prec.right(
|
|
kPrec.kPower,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", "^"),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
logarithm_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kLogarithm,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", "~"),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
matrix_multiplication_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kMatrixTimes,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", choice(":*", ":/", ":\\")),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
matrix_power_expression: ($) =>
|
|
prec.right(
|
|
kPrec.kMatrixPower,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", ":^"),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
matrix_concatenation_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kMatrixConcat,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", choice(":|", "|")),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
range_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kRange,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", "->"),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
matrix_transpose_expression: ($) =>
|
|
prec(
|
|
kPrec.kMatrixTranspose,
|
|
seq(field("operator", "`"), field("argument", $.expression)),
|
|
),
|
|
|
|
set_operation_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kSet,
|
|
seq(
|
|
field("left", $.expression),
|
|
field(
|
|
"operator",
|
|
choice(
|
|
kw("union"),
|
|
kw("union2"),
|
|
kw("intersect"),
|
|
kw("outersect"),
|
|
kw("minus"),
|
|
),
|
|
),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
concatenation_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kConcat,
|
|
seq(
|
|
field("left", $.expression),
|
|
field("operator", "$"),
|
|
field("right", $.expression),
|
|
),
|
|
),
|
|
|
|
unary_plus_expression: ($) =>
|
|
prec(
|
|
kPrec.kSigned,
|
|
seq(field("operator", "+"), field("argument", $.expression)),
|
|
),
|
|
|
|
unary_minus_expression: ($) =>
|
|
prec(
|
|
kPrec.kSigned,
|
|
seq(field("operator", "-"), field("argument", $.expression)),
|
|
),
|
|
|
|
prefix_increment_expression: ($) =>
|
|
prec.right(
|
|
kPrec.kPrefix,
|
|
seq(field("operator", "++"), field("argument", $.expression)),
|
|
),
|
|
|
|
prefix_decrement_expression: ($) =>
|
|
prec.right(
|
|
kPrec.kPrefix,
|
|
seq(field("operator", "--"), field("argument", $.expression)),
|
|
),
|
|
|
|
postfix_increment_expression: ($) =>
|
|
prec.right(
|
|
kPrec.kPostfix,
|
|
seq(field("argument", $.expression), field("operator", "++")),
|
|
),
|
|
|
|
postfix_decrement_expression: ($) =>
|
|
prec.right(
|
|
kPrec.kPostfix,
|
|
seq(field("argument", $.expression), field("operator", "--")),
|
|
),
|
|
|
|
derivative_expression: ($) =>
|
|
prec.left(
|
|
kPrec.kDerivative,
|
|
seq(field("operator", "!"), field("argument", $.expression)),
|
|
),
|
|
|
|
function_pointer_expression: ($) =>
|
|
prec(
|
|
kPrec.kFunctionPointer,
|
|
seq(field("operator", "##"), field("argument", $.expression)),
|
|
),
|
|
|
|
anonymous_function_expression: ($) =>
|
|
seq(
|
|
kw("function"),
|
|
$._parameter_signature,
|
|
field("return_type", optional($._type_annotation)),
|
|
optional(kSemicolon),
|
|
field("body", $.block_statement),
|
|
),
|
|
|
|
unpack_pattern: ($) => prec.dynamic(1, seq("[", $._unpack_vars, "]")),
|
|
|
|
_unpack_vars: ($) =>
|
|
seq(
|
|
field("variable", $.identifier),
|
|
repeat1(seq(",", field("variable", $.identifier))),
|
|
),
|
|
|
|
_left_hand_side: ($) =>
|
|
choice(
|
|
$._assignable_identifier,
|
|
$.var_declaration,
|
|
$.static_declaration,
|
|
$.global_declaration,
|
|
$.attribute,
|
|
$.subscript,
|
|
$.unpack_pattern,
|
|
),
|
|
|
|
_right_hand_side: ($) =>
|
|
choice(
|
|
$.expression,
|
|
$.assignment_expression,
|
|
$.augmented_assignment_expression,
|
|
),
|
|
|
|
tssql_select_expression: ($) =>
|
|
choice(
|
|
$.select_expression,
|
|
$.sselect_expression,
|
|
$.vselect_expression,
|
|
$.mselect_expression,
|
|
),
|
|
|
|
tssql_dml_expression: ($) =>
|
|
choice($.update_expression, $.delete_expression, $.insert_expression),
|
|
|
|
select_expression: ($) => seq(kw("select"), $._select_clause),
|
|
|
|
sselect_expression: ($) => seq(kw("sselect"), $._select_clause),
|
|
|
|
vselect_expression: ($) => seq(kw("vselect"), $._select_clause),
|
|
|
|
mselect_expression: ($) => seq(kw("mselect"), $._select_clause),
|
|
|
|
update_expression: ($) =>
|
|
seq(
|
|
kw("update"),
|
|
field("table", $.identifier),
|
|
kw("set"),
|
|
field("assignments", sep1($.update_assignment, ",")),
|
|
optional(field("where", $.where_clause)),
|
|
kw("end"),
|
|
),
|
|
|
|
delete_expression: ($) =>
|
|
seq(
|
|
kw("delete"),
|
|
kw("from"),
|
|
field("table", $.identifier),
|
|
optional(field("where", $.where_clause)),
|
|
),
|
|
|
|
insert_expression: ($) =>
|
|
seq(
|
|
kw("insert"),
|
|
kw("into"),
|
|
field("table", $.identifier),
|
|
optional($.insert_fields),
|
|
choice($.values_clause, field("source", $.identifier)),
|
|
),
|
|
|
|
insert_fields: ($) =>
|
|
seq(kw("insertfields"), "(", sep1($.sql_field, ","), ")"),
|
|
|
|
values_clause: ($) => seq(kw("values"), "(", sep1($.expression, ","), ")"),
|
|
|
|
update_assignment: ($) =>
|
|
seq(
|
|
field("column", $.primary_expression),
|
|
"=",
|
|
field("value", $.expression),
|
|
),
|
|
|
|
_select_clause: ($) =>
|
|
seq(
|
|
optional(field("distinct", kw("distinct"))),
|
|
optional(field("drange", $.drange_clause)),
|
|
optional(field("columns", $.select_list)),
|
|
field("from", $.from_clause),
|
|
optional(field("where", $.where_clause)),
|
|
optional(field("group_by", $.group_by_clause)),
|
|
optional(field("order_by", $.order_by_clause)),
|
|
optional(field("having", $.having_clause)),
|
|
kw("end"),
|
|
),
|
|
|
|
drange_clause: ($) =>
|
|
seq(kw("drange"), "(", choice($.drange_to, $.drange_of), ")"),
|
|
|
|
drange_to: ($) =>
|
|
seq(field("start", $.expression), kw("to"), field("end", $.expression)),
|
|
|
|
drange_of: ($) =>
|
|
seq(field("part", $.expression), kw("of"), field("total", $.expression)),
|
|
|
|
select_list: ($) =>
|
|
seq($.select_list_item, repeat(seq(",", $.select_list_item))),
|
|
|
|
select_list_item: ($) => choice(prec(10, "*"), $.select_item),
|
|
|
|
select_item: ($) =>
|
|
seq(field("expression", $.expression), optional($.alias_clause)),
|
|
|
|
alias_clause: ($) => seq(kw("as"), choice(field("alias", $.string), $.nil)),
|
|
|
|
from_clause: ($) => seq(kw("from"), $.from_item),
|
|
|
|
from_item: ($) => choice($._table_or_subquery, $.join_clause),
|
|
|
|
_table_or_subquery: ($) =>
|
|
choice($.expression, seq("(", $.select_expression, ")")),
|
|
|
|
table_name: ($) => $.identifier,
|
|
|
|
sql_field: ($) =>
|
|
choice(
|
|
$._sql_field_with_table, // ⚠️ 带表前缀的字段:[1].* 或 [1].["field"]
|
|
$._sql_field_simple, // ⚠️ 简单字段:["field"]
|
|
),
|
|
|
|
_sql_field_with_table: ($) =>
|
|
prec(
|
|
kPrec.kSubscript + 3,
|
|
seq(
|
|
"[",
|
|
field("table_index", $.number),
|
|
"]",
|
|
".",
|
|
choice(
|
|
"*",
|
|
seq("[", field("field_name", choice($.string, $.number)), "]"),
|
|
),
|
|
),
|
|
),
|
|
|
|
// ⚠️ 简单的 SQL 字段或参数引用
|
|
_sql_field_simple: ($) =>
|
|
prec(
|
|
kPrec.kSubscript + 2,
|
|
seq("[", field("ref", choice($.string, $.number)), "]"),
|
|
),
|
|
|
|
where_clause: ($) => seq(kw("where"), field("condition", $.expression)),
|
|
|
|
group_by_clause: ($) =>
|
|
seq(kw("group"), kw("by"), field("expressions", sep1($.expression, ","))),
|
|
|
|
order_by_clause: ($) =>
|
|
seq(
|
|
kw("order"),
|
|
kw("by"),
|
|
field("expressions", sep1($._order_by_item, ",")),
|
|
),
|
|
|
|
_order_by_item: ($) =>
|
|
seq(
|
|
field("expression", $.expression),
|
|
optional(field("direction", choice(kw("asc"), kw("desc")))),
|
|
),
|
|
|
|
having_clause: ($) => seq(kw("having"), field("condition", $.expression)),
|
|
|
|
join_clause: ($) =>
|
|
prec.left(1, seq($._table_or_subquery, repeat1($._join_part))),
|
|
|
|
_join_part: ($) =>
|
|
seq(
|
|
field("join_type", $.join_type),
|
|
field("right", $._table_or_subquery),
|
|
optional(field("condition", choice($.on_condition, $.with_condition))),
|
|
),
|
|
|
|
join_type: (_) =>
|
|
choice(
|
|
kw("join"),
|
|
seq(kw("left"), kw("join")),
|
|
seq(kw("right"), kw("join")),
|
|
seq(kw("full"), kw("join")),
|
|
seq(kw("cross"), kw("join")),
|
|
",", // comma join
|
|
),
|
|
|
|
on_condition: ($) => seq(kw("on"), field("condition", $.expression)),
|
|
|
|
with_condition: ($) =>
|
|
seq(
|
|
kw("with"),
|
|
"(",
|
|
field("left_fields", sep1($.sql_field, ",")),
|
|
kw("on"),
|
|
field("right_fields", sep1($.sql_field, ",")),
|
|
")",
|
|
),
|
|
|
|
primary_expression: ($) =>
|
|
choice(
|
|
$.attribute,
|
|
$.subscript,
|
|
$.parenthesized_expression,
|
|
$.call,
|
|
$.array,
|
|
$._literal,
|
|
$._assignable_identifier,
|
|
$._reserved_keyword,
|
|
|
|
$.sql_field,
|
|
),
|
|
|
|
// identifier: _ => /[a-zA-Z_][a-zA-Z0-9_]*/,
|
|
identifier: (_) => token(prec(kPrec.kIdentifier, /[a-zA-Z_][a-zA-Z0-9_]*/)),
|
|
|
|
_literal: ($) =>
|
|
choice($.number, $.string, $.boolean, $.nil, $.infinity, $.ellipsis),
|
|
|
|
_assignable_identifier: ($) => choice($.identifier, $.type, $.do),
|
|
|
|
_reserved_keyword: ($) => choice($.class, $.in),
|
|
|
|
type: (_) => kw("type"),
|
|
class: (_) => kw("class"),
|
|
in: (_) => kw("in"),
|
|
do: (_) => kw("do"),
|
|
|
|
number: (_) =>
|
|
token(
|
|
choice(
|
|
/0[xX][0-9a-fA-F]+/,
|
|
/0[bB][01]+/,
|
|
/0[oO][0-7]+/,
|
|
|
|
/[+-]?\d+\.\d*(?:[eE][+-]?\d+)?/, // 123.456, 123., +123.
|
|
/[+-]?\.\d+(?:[eE][+-]?\d+)?/, // .456, +.456
|
|
|
|
/[+-]?\d+(?:[eE][+-]?\d+)?/, // 123, +123, 123e10
|
|
),
|
|
),
|
|
|
|
string: (_) =>
|
|
token(
|
|
choice(
|
|
seq(
|
|
'"',
|
|
repeat(
|
|
choice(
|
|
/[^"\\]/,
|
|
seq("\\", /./), // escape sequence
|
|
),
|
|
),
|
|
'"',
|
|
),
|
|
seq(
|
|
"'",
|
|
repeat(
|
|
choice(
|
|
/[^'\\]/,
|
|
seq("\\", /./), // escape sequence
|
|
),
|
|
),
|
|
"'",
|
|
),
|
|
),
|
|
),
|
|
|
|
escape_sequence: (_) => token(seq("\\", /./)),
|
|
|
|
boolean: ($) => choice($.true, $.false),
|
|
|
|
true: (_) => kw("true"),
|
|
|
|
false: (_) => kw("false"),
|
|
|
|
nil: (_) => kw("nil"),
|
|
|
|
infinity: ($) => choice($.minus_inf, $.plus_inf),
|
|
|
|
minus_inf: (_) => kw("-inf"),
|
|
|
|
plus_inf: (_) => kw("+inf"),
|
|
|
|
ellipsis: (_) => "...",
|
|
|
|
call: ($) =>
|
|
prec(
|
|
kPrec.kCall,
|
|
seq(
|
|
field("function", $.primary_expression),
|
|
"(",
|
|
field("arguments", optional($.argument_list)),
|
|
")",
|
|
),
|
|
),
|
|
|
|
attribute: ($) =>
|
|
prec(
|
|
kPrec.kAttribute,
|
|
seq(
|
|
field("object", choice($.primary_expression)),
|
|
".",
|
|
field("attribute", $.identifier),
|
|
),
|
|
),
|
|
|
|
subscript: ($) =>
|
|
prec.dynamic(
|
|
2,
|
|
prec(
|
|
kPrec.kSubscript,
|
|
seq(
|
|
field("value", $.primary_expression),
|
|
"[",
|
|
field("subscript", $._index_spec),
|
|
"]",
|
|
),
|
|
),
|
|
),
|
|
|
|
parenthesized_expression: ($) =>
|
|
seq("(", $._with_assignment_expression, ")"),
|
|
|
|
array: ($) =>
|
|
prec(
|
|
kPrec.kArray,
|
|
seq(kw("array"), "(", optional($._array_elements), ")"),
|
|
),
|
|
|
|
argument_list: ($) => sep1($.argument, ","),
|
|
|
|
argument: ($) =>
|
|
choice(
|
|
$.expression,
|
|
seq(field("name", $.identifier), ":", field("value", $.expression)),
|
|
"*",
|
|
),
|
|
|
|
_index_spec: ($) => choice($._multi_index, $._single_index),
|
|
|
|
_multi_index: ($) => seq($._index_item, repeat1(seq(",", $._index_item))),
|
|
|
|
_single_index: ($) => $._index_item,
|
|
|
|
_index_item: ($) =>
|
|
choice(
|
|
$.expression, // string, array都在里面
|
|
$.slice,
|
|
$.empty_slice,
|
|
),
|
|
|
|
empty_slice: (_) => ":",
|
|
|
|
slice: ($) =>
|
|
choice($.range_slice, $.start_slice, $.end_slice, $.step_slice),
|
|
|
|
range_slice: ($) => seq($.expression, ":", $.expression),
|
|
start_slice: ($) => seq($.expression, ":"),
|
|
end_slice: ($) => seq(":", $.expression),
|
|
step_slice: ($) => seq($.expression, ":", $.expression, ":", $.expression),
|
|
|
|
_array_elements: ($) => seq(sep1($.array_element, ","), optional(",")),
|
|
|
|
array_element: ($) =>
|
|
choice($.key_value_pair, prec(1, $.parenthesized_array), $.expression),
|
|
|
|
key_value_pair: ($) =>
|
|
seq(
|
|
field("key", $.expression),
|
|
":",
|
|
field("value", choice($.expression, $.parenthesized_array)),
|
|
),
|
|
|
|
parenthesized_array: ($) =>
|
|
prec(
|
|
1,
|
|
seq(
|
|
"(",
|
|
choice(
|
|
seq($.key_value_pair, ",", sep1($.key_value_pair, ",")),
|
|
$.key_value_pair,
|
|
seq($.expression, ",", sep1($.expression, ",")),
|
|
$.expression,
|
|
),
|
|
optional(","),
|
|
")",
|
|
),
|
|
),
|
|
|
|
line_comment: (_) => token(seq("//", /.*/)),
|
|
|
|
block_comment: (_) => token(seq("{", /([^$}][^}]*)?/, "}")),
|
|
|
|
nested_comment: (_) => token(/[(][*]([^*]*[*]+[^)*])*[^*]*[*]+[)]/),
|
|
|
|
if_statement: ($) =>
|
|
prec.right(
|
|
kPrec.kIf,
|
|
seq(
|
|
$.if_clause,
|
|
repeat(field("alternative", $.else_if_clause)),
|
|
optional(field("alternative", $.else_clause)),
|
|
),
|
|
),
|
|
|
|
if_clause: ($) =>
|
|
seq(
|
|
kw("if"),
|
|
field("condition", $._with_assignment_expression),
|
|
kw("then"),
|
|
field("consequence", $._statement_suite),
|
|
),
|
|
|
|
else_if_clause: ($) =>
|
|
prec(
|
|
kPrec.kElif,
|
|
seq(
|
|
kw("else"),
|
|
kw("if"),
|
|
field("condition", $._with_assignment_expression),
|
|
kw("then"),
|
|
field("consequence", $._statement_suite),
|
|
),
|
|
),
|
|
|
|
else_clause: ($) =>
|
|
seq(kw("else"), field("consequence", $._statement_suite)),
|
|
|
|
_statement_suite: ($) =>
|
|
choice(seq($.block_statement, optional(kSemicolon)), $.single_suite),
|
|
|
|
single_suite: ($) => $._statement,
|
|
|
|
block_statement: ($) => seq(kw("begin"), repeat($._statement), kw("end")),
|
|
|
|
for_statement: ($) => choice($.for_in_statement, $.for_to_statement),
|
|
|
|
for_in_statement: ($) =>
|
|
seq(
|
|
kw("for"),
|
|
field("key", $.identifier),
|
|
",",
|
|
field("value", $.identifier),
|
|
kw("in"),
|
|
field("collection", $.expression),
|
|
$.do,
|
|
field("body", $._statement_suite),
|
|
),
|
|
|
|
for_to_statement: ($) =>
|
|
seq(
|
|
kw("for"),
|
|
field("counter", $.identifier),
|
|
":=",
|
|
field("start", $.expression),
|
|
field("direction", choice(kw("to"), kw("downto"))),
|
|
field("end", $.expression),
|
|
$.do,
|
|
field("body", $._statement_suite),
|
|
),
|
|
|
|
while_statement: ($) =>
|
|
seq(
|
|
kw("while"),
|
|
field("condition", $.expression),
|
|
$.do,
|
|
field("body", $._statement_suite),
|
|
),
|
|
|
|
repeat_statement: ($) =>
|
|
seq(
|
|
kw("repeat"),
|
|
field("body", repeat($.single_suite)),
|
|
kw("until"),
|
|
field("condition", $.expression),
|
|
kSemicolon,
|
|
),
|
|
|
|
case_statement: ($) =>
|
|
seq(
|
|
kw("case"),
|
|
field("discriminant", $.expression), // 被匹配的表达式
|
|
kw("of"),
|
|
field("branches", repeat($.case_branch)),
|
|
field("default", optional($.case_else)),
|
|
kw("end"),
|
|
optional(kSemicolon),
|
|
),
|
|
|
|
case_branch: ($) =>
|
|
seq(
|
|
field("values", $.case_values),
|
|
":",
|
|
field("consequence", $._statement_suite),
|
|
),
|
|
|
|
case_values: ($) => sep1(field("value", $.expression), ","),
|
|
|
|
case_else: ($) => seq(kw("else"), field("consequence", $._statement_suite)),
|
|
|
|
try_statement: ($) =>
|
|
seq(
|
|
kw("try"),
|
|
optional(field("body", repeat1($._statement))),
|
|
kw("except"),
|
|
optional(field("body", repeat1($._statement))),
|
|
kw("end"),
|
|
optional(kSemicolon),
|
|
),
|
|
|
|
anonymous_function_statement: ($) =>
|
|
seq($.anonymous_function_expression, optional(kSemicolon)),
|
|
|
|
function_declaration_statement: ($) =>
|
|
seq(
|
|
kw("function"),
|
|
field("name", $.identifier),
|
|
$._parameter_signature,
|
|
optional(field("return_type", $._type_annotation)),
|
|
kSemicolon,
|
|
),
|
|
|
|
function_definition_statement: ($) =>
|
|
seq(
|
|
kw("function"),
|
|
field("name", $.identifier),
|
|
$._parameter_signature,
|
|
field("return_type", optional($._type_annotation)),
|
|
optional(kSemicolon),
|
|
field("body", $.block_statement),
|
|
optional(kSemicolon),
|
|
),
|
|
|
|
_parameter_signature: ($) =>
|
|
seq("(", optional(field("parameters", $.parameter_list)), ")"),
|
|
|
|
parameter_list: ($) => sep1($.parameter, kSemicolon),
|
|
|
|
parameter: ($) =>
|
|
seq(
|
|
optional(choice(field("var", kw("var")), field("out", kw("out")))),
|
|
sep1(field("name", $.identifier), ","),
|
|
optional(field("type", $._type_annotation)),
|
|
optional(seq("=", field("default", $.expression))),
|
|
),
|
|
|
|
class_definition_statement: ($) =>
|
|
seq(
|
|
$.type,
|
|
field("name", $.identifier),
|
|
"=",
|
|
$.class,
|
|
optional($._parent_list),
|
|
optional(field("body", $.class_body)),
|
|
kw("end"),
|
|
optional(kSemicolon),
|
|
),
|
|
|
|
_parent_list: ($) =>
|
|
seq(
|
|
"(",
|
|
optional(sep1(field("parent", choice($.identifier, $.attribute)), ",")),
|
|
")",
|
|
),
|
|
|
|
class_body: ($) => repeat1($.class_member),
|
|
|
|
class_member: ($) =>
|
|
choice(
|
|
field("access_modifier", $.access_modifier),
|
|
choice(
|
|
$.variable_declaration,
|
|
$.method_declaration,
|
|
$.property_declaration,
|
|
),
|
|
$.uses_statement,
|
|
),
|
|
|
|
access_modifier: (_) =>
|
|
choice(kw("public"), kw("protected"), kw("private")),
|
|
|
|
variable_declaration: ($) =>
|
|
seq(
|
|
optional($._reference_tag),
|
|
field("variables", $.member_variable),
|
|
kSemicolon,
|
|
),
|
|
|
|
_reference_tag: ($) =>
|
|
seq("[", field("ref_modifier", $.reference_modifier), "]"),
|
|
|
|
reference_modifier: (_) => choice(kw("weakref"), kw("autoref")),
|
|
|
|
member_variable: ($) =>
|
|
choice($.static_declaration, $.nostatic_declaration),
|
|
|
|
nostatic_declaration: ($) =>
|
|
seq($._variable_declaration, optional($._type_annotation)),
|
|
|
|
method_declaration: ($) =>
|
|
choice(
|
|
$.method_declaration_only,
|
|
$.method_with_modifier,
|
|
$.method_with_implementation,
|
|
),
|
|
|
|
method_declaration_only: ($) =>
|
|
seq(
|
|
optional($.class),
|
|
kw("function"),
|
|
field("name", $.method_name),
|
|
$._parameter_signature,
|
|
optional(field("return_type", $._type_annotation)),
|
|
kSemicolon,
|
|
),
|
|
|
|
method_with_modifier: ($) =>
|
|
seq(
|
|
kw("function"),
|
|
field("name", $.method_name),
|
|
$._parameter_signature,
|
|
optional(field("return_type", $._type_annotation)),
|
|
kSemicolon,
|
|
field("modifier", $.method_modifier),
|
|
kSemicolon,
|
|
optional(seq(field("body", $.block_statement), optional(kSemicolon))),
|
|
),
|
|
|
|
method_with_implementation: ($) =>
|
|
seq(
|
|
optional($.class),
|
|
kw("function"),
|
|
field("name", $.method_name),
|
|
$._parameter_signature,
|
|
optional(field("return_type", $._type_annotation)),
|
|
optional(kSemicolon),
|
|
field("body", $.block_statement),
|
|
optional(kSemicolon),
|
|
),
|
|
|
|
method_name: ($) =>
|
|
choice(
|
|
$._assignable_identifier,
|
|
// $.identifier,
|
|
$.operator_overload,
|
|
),
|
|
|
|
operator_overload: ($) =>
|
|
seq(kw("operator"), field("operator", $._overloadable_operator)),
|
|
|
|
_overloadable_operator: (_) => choice("+", "-", "*", "/", "\\", "[]"),
|
|
|
|
method_modifier: (_) =>
|
|
choice(kw("virtual"), kw("override"), kw("overload")),
|
|
|
|
property_declaration: ($) =>
|
|
seq(
|
|
kw("property"),
|
|
field("name", $.identifier),
|
|
optional($._type_annotation),
|
|
optional($._property_index),
|
|
field("accessors", $.property_accessors),
|
|
kSemicolon,
|
|
),
|
|
|
|
_property_index: ($) => seq(kw("index"), choice($.number, $.string)),
|
|
|
|
property_accessors: ($) =>
|
|
choice(
|
|
$.read_only_accessor,
|
|
$.write_only_accessor,
|
|
$.read_write_accessor,
|
|
$.write_read_accessor,
|
|
),
|
|
|
|
read_only_accessor: ($) => seq(kw("read"), $.identifier),
|
|
|
|
write_only_accessor: ($) => seq(kw("write"), $.identifier),
|
|
|
|
read_write_accessor: ($) =>
|
|
seq(kw("read"), $.identifier, kw("write"), $.identifier),
|
|
|
|
write_read_accessor: ($) =>
|
|
seq(kw("write"), $.identifier, kw("read"), $.identifier),
|
|
|
|
// 类外方法实现
|
|
external_method_statement: ($) =>
|
|
choice($.modifier_method, $.operator_method, $.normal_method),
|
|
|
|
matrix_iteration_statement: ($) =>
|
|
seq(
|
|
field("target", $.expression),
|
|
"::",
|
|
field("body", $.block_statement),
|
|
optional(kSemicolon),
|
|
),
|
|
|
|
_tslx_template_statement: ($) =>
|
|
choice(
|
|
$.tslx_open_tag,
|
|
$.tslx_close_tag,
|
|
$.tslx_output_tag,
|
|
$.tslx_expression_tag,
|
|
$._tslx_html_tag,
|
|
),
|
|
|
|
tslx_open_tag: (_) => seq("<?", kw("tslx"), ">"),
|
|
|
|
tslx_close_tag: (_) => seq("<?", kw("tsl")),
|
|
|
|
tslx_expression_tag: ($) =>
|
|
seq("<?", kw("tsl"), repeat($._statement), "?>"),
|
|
|
|
tslx_output_tag: ($) => seq("<?=", sep1($.expression, ","), "?>"),
|
|
|
|
_tslx_html_tag: ($) =>
|
|
choice($.html_self_closing_tag, $.html_paired_tag, $.html_comment),
|
|
|
|
html_self_closing_tag: ($) =>
|
|
seq(
|
|
"<",
|
|
field("tag_name", $.html_tag_name),
|
|
repeat(field("attribute", $.html_attribute)),
|
|
"/>",
|
|
),
|
|
|
|
html_paired_tag: ($) =>
|
|
seq(
|
|
"<",
|
|
field("tag_name", $.html_tag_name),
|
|
repeat(field("attribute", $.html_attribute)),
|
|
">",
|
|
field("content", repeat($._tslx_template_statement)),
|
|
"</",
|
|
field("tag_name", $.html_tag_name),
|
|
">",
|
|
),
|
|
|
|
html_attribute: ($) =>
|
|
seq(
|
|
field("name", /[a-zA-Z:_][a-zA-Z0-9:_.-]*/),
|
|
"=",
|
|
field("value", $.string),
|
|
),
|
|
|
|
html_tag_name: (_) => /[a-zA-Z][a-zA-Z0-9-]*/,
|
|
|
|
html_comment: (_) =>
|
|
token(seq("<!--", repeat(choice(/[^-]/, /-[^-]/, /--[^>]/)), "-->")),
|
|
|
|
modifier_method: ($) =>
|
|
seq(
|
|
kw("function"),
|
|
$._qualified_method_name,
|
|
$._parameter_signature,
|
|
optional(field("return_type", $._type_annotation)),
|
|
kSemicolon,
|
|
field("modifier", $.method_modifier),
|
|
kSemicolon,
|
|
field("body", $.block_statement),
|
|
optional(kSemicolon),
|
|
),
|
|
|
|
operator_method: ($) =>
|
|
choice($._operator_method, $._operator_method_with_modifier),
|
|
|
|
normal_method: ($) =>
|
|
seq(
|
|
optional($.class),
|
|
kw("function"),
|
|
$._qualified_method_name,
|
|
$._parameter_signature,
|
|
optional(field("return_type", $._type_annotation)),
|
|
optional(kSemicolon),
|
|
field("body", $.block_statement),
|
|
optional(kSemicolon),
|
|
),
|
|
|
|
_operator_method: ($) =>
|
|
seq(
|
|
kw("function"),
|
|
kw("operator"),
|
|
field("class_name", $.identifier),
|
|
".",
|
|
field("operator", $._overloadable_operator),
|
|
$._parameter_signature,
|
|
optional(field("return_type", $._type_annotation)),
|
|
optional(kSemicolon),
|
|
field("body", $.block_statement),
|
|
optional(kSemicolon),
|
|
),
|
|
|
|
_operator_method_with_modifier: ($) =>
|
|
seq(
|
|
kw("function"),
|
|
kw("operator"),
|
|
field("class_name", $.identifier),
|
|
".",
|
|
field("operator", $._overloadable_operator),
|
|
$._parameter_signature,
|
|
optional(field("return_type", $._type_annotation)),
|
|
kSemicolon,
|
|
field("modifier", $.method_modifier),
|
|
kSemicolon,
|
|
field("body", $.block_statement),
|
|
optional(kSemicolon),
|
|
),
|
|
|
|
_qualified_method_name: ($) =>
|
|
seq(
|
|
field("class_name", $.identifier),
|
|
".",
|
|
field("method_name", $.identifier),
|
|
),
|
|
|
|
// unit
|
|
unit: ($) =>
|
|
seq(
|
|
kw("unit"),
|
|
field("name", $.identifier),
|
|
kSemicolon,
|
|
field("interface", $.interface_section),
|
|
field("implementation", $.implementation_section),
|
|
optional(field("initialization", $.initialization_section)),
|
|
optional(field("finalization", $.finalization_section)),
|
|
kw("end"),
|
|
".",
|
|
),
|
|
|
|
interface_section: ($) =>
|
|
seq(kw("interface"), optional(repeat($._statement))),
|
|
|
|
implementation_section: ($) =>
|
|
seq(kw("implementation"), optional(repeat($._statement))),
|
|
|
|
initialization_section: ($) =>
|
|
seq(kw("initialization"), optional(repeat($._statement))),
|
|
|
|
finalization_section: ($) =>
|
|
seq(kw("finalization"), optional(repeat($._statement))),
|
|
|
|
uses_statement: ($) =>
|
|
seq(kw("uses"), sep1(field("module", $.identifier), ","), kSemicolon),
|
|
},
|
|
});
|
|
|
|
// 辅助函数:用分隔符分隔的序列
|
|
function sep1(rule, separator) {
|
|
return seq(rule, repeat(seq(separator, rule)));
|
|
}
|
|
|
|
function kw(keyword) {
|
|
const escapedKeyword = keyword.replace(/[.*+?^${}()|[\]\\-]/g, "\\$&");
|
|
|
|
return alias(new RustRegex(`(?i)${escapedKeyword}`), keyword.toLowerCase());
|
|
}
|