1339 lines
34 KiB
JavaScript
1339 lines
34 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 (左结合)
|
||
kMultDiv: 13, // * / \ % mod div (左结合)
|
||
kMatrixMultDiv: 13, // :* :/ :\ (左结合)
|
||
|
||
kConcat: 14, // $ (左结合)
|
||
kLogarithm: 14, // ~ (左结合)
|
||
|
||
kUnaryPrefix: 15, // + - not .! .!! ## ! `(右结合)
|
||
|
||
kPower: 16, // ^ :^ (右结合)
|
||
kPrefixIncDec: 16, // ++ -- (右结合)
|
||
kPostfixIncDec: 17, // ++ -- (左结合)
|
||
|
||
kCall: 18, // func() (左结合)
|
||
kAttribute: 18, // obj.attr (左结合)
|
||
kSubscript: 18, // a[] a[:] a[1:] a[:1,2] (左结合)
|
||
kParenthesized: 19, // (expr)
|
||
|
||
kPrimary: 20,
|
||
kArray: 20,
|
||
};
|
||
|
||
const kSemicolon = ";";
|
||
|
||
module.exports = grammar({
|
||
name: "tsf",
|
||
|
||
word: ($) => $.identifier,
|
||
|
||
externals: ($) => [
|
||
$.tslx_content,
|
||
$.tsl_statement_start_tag, // <?tsl
|
||
$.tsl_statement_end_tag, // ?>
|
||
$.tsl_expression_start_tag, // <?=
|
||
$.tsl_expression_end_tag, // ?>
|
||
$.tslx_end_tag, // 表示tslx块结束
|
||
],
|
||
|
||
extras: ($) => [/\s/, $.line_comment, $.block_comment, $.nested_comment],
|
||
|
||
conflicts: ($) => [
|
||
[$.lvalue_expression, $._primary_expression],
|
||
[$.lvalue_expression, $.expression],
|
||
[$.select_expression, $.select],
|
||
[$.sselect_expression, $.sselect],
|
||
[$.vselect_expression, $.vselect],
|
||
[$.insert_expression, $.insert],
|
||
[$.update_expression, $.update],
|
||
[$.delete_expression, $.delete],
|
||
[$.function_declaration, $.function_definition],
|
||
[$.parameter_mode, $._soft_keyword],
|
||
],
|
||
|
||
inline: ($) => [$._statement],
|
||
|
||
rules: {
|
||
root: ($) => repeat($._statement),
|
||
|
||
_statement: ($) =>
|
||
choice(
|
||
$.unit_definition,
|
||
$.class_definition, // type关键字可以二元运算 type = b
|
||
$.external_method_definition,
|
||
$.function_declaration, // unit里面
|
||
$.function_definition,
|
||
|
||
$.tslx_block,
|
||
$.compiler_directive_statement,
|
||
$._conditional_compilation_statement,
|
||
$.matrix_iteration_statement,
|
||
|
||
$.if_statement,
|
||
$._for_statement,
|
||
$.while_statement,
|
||
$.repeat_statement,
|
||
$.case_statement,
|
||
$.try_statement,
|
||
$.break_statement,
|
||
$.continue_statement,
|
||
$.return_statement,
|
||
|
||
$.block_statement,
|
||
$.uses_statement,
|
||
|
||
$.var_declaration,
|
||
$.static_declaration,
|
||
$.global_declaration,
|
||
$.const_declaration,
|
||
|
||
$.anonymous_function_statement, // 特殊--因为分号可选
|
||
$.expression_statement,
|
||
$._empty_statement,
|
||
),
|
||
|
||
unit_definition: ($) =>
|
||
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"), repeat($._statement)),
|
||
|
||
implementation_section: ($) =>
|
||
seq(kw("implementation"), repeat($._statement)),
|
||
|
||
initialization_section: ($) =>
|
||
seq(kw("initialization"), repeat($._statement)),
|
||
|
||
finalization_section: ($) => seq(kw("finalization"), repeat($._statement)),
|
||
|
||
class_definition: ($) =>
|
||
seq(
|
||
kw("type"),
|
||
field("name", $.identifier),
|
||
"=",
|
||
kw("class"),
|
||
optional($._parent_list),
|
||
optional(field("body", $.class_body)),
|
||
kw("end"),
|
||
),
|
||
|
||
external_method_definition: ($) =>
|
||
choice($.external_method, $.external_operator_method),
|
||
|
||
_parent_list: ($) =>
|
||
seq(
|
||
"(",
|
||
optional(
|
||
sep1(
|
||
field("parent", choice($.identifier, $.attribute_expression)),
|
||
",",
|
||
),
|
||
),
|
||
")",
|
||
),
|
||
|
||
class_body: ($) => seq(optional($.uses_statement), repeat1($.class_member)),
|
||
|
||
class_member: ($) =>
|
||
choice(
|
||
field("access_modifier", $.access_modifier),
|
||
field("reference_modifier", $.reference_modifier),
|
||
choice(
|
||
$.method_declaration,
|
||
$.method_definition,
|
||
$.variable_declaration,
|
||
$.property_declaration,
|
||
),
|
||
),
|
||
|
||
access_modifier: (_) =>
|
||
choice(kw("public"), kw("protected"), kw("private")),
|
||
|
||
variable_declaration: ($) =>
|
||
seq(
|
||
optional($._reference_tag),
|
||
field("variable", $.member_variable),
|
||
kSemicolon,
|
||
),
|
||
|
||
_reference_tag: ($) =>
|
||
seq("[", field("ref_modifier", $.reference_modifier), "]"),
|
||
|
||
reference_modifier: (_) => choice(kw("weakref"), kw("autoref")),
|
||
|
||
member_variable: ($) =>
|
||
choice($.static_member_variable, $.field_member_variable),
|
||
|
||
static_member_variable: ($) =>
|
||
seq(
|
||
kw("static"),
|
||
$._identifier_list,
|
||
optional($._type_clause),
|
||
optional(seq("=", field("value", $.expression))),
|
||
),
|
||
|
||
field_member_variable: ($) =>
|
||
seq(
|
||
$._identifier_list,
|
||
optional($._type_clause),
|
||
optional(seq("=", field("value", $.expression))),
|
||
),
|
||
|
||
_method_header: ($) =>
|
||
seq(
|
||
optional(kw("class")),
|
||
choice(kw("function"), kw("procedure")),
|
||
field("name", $.method_name),
|
||
$._parameter_signature,
|
||
optional(field("return_type", $._type_clause)),
|
||
),
|
||
|
||
method_declaration: ($) =>
|
||
seq(
|
||
$._method_header,
|
||
kSemicolon,
|
||
optional(seq(field("modifier", $.method_modifier), kSemicolon)),
|
||
),
|
||
|
||
method_definition: ($) =>
|
||
seq(
|
||
$._method_header,
|
||
optional(
|
||
seq(kSemicolon, field("modifier", $.method_modifier), kSemicolon),
|
||
),
|
||
optional(kSemicolon),
|
||
field("body", $.block_statement),
|
||
optional(kSemicolon),
|
||
),
|
||
|
||
method_name: ($) => choice($._identifier_or_keyword, $.operator_overload),
|
||
|
||
external_method: ($) =>
|
||
seq(
|
||
optional(kw("class")),
|
||
choice(kw("function"), kw("procedure")),
|
||
$._qualified_method_name,
|
||
$._parameter_signature,
|
||
optional(field("return_type", $._type_clause)),
|
||
optional(
|
||
seq(kSemicolon, field("modifier", $.method_modifier), kSemicolon),
|
||
),
|
||
optional(kSemicolon),
|
||
field("body", $.block_statement),
|
||
),
|
||
|
||
external_operator_method: ($) =>
|
||
seq(
|
||
choice(kw("function"), kw("procedure")),
|
||
kw("operator"),
|
||
field("class_name", $.identifier),
|
||
".",
|
||
field("operator", $._overloadable_operator),
|
||
$._parameter_signature,
|
||
optional(field("return_type", $._type_clause)),
|
||
optional(
|
||
seq(kSemicolon, field("modifier", $.method_modifier), kSemicolon),
|
||
),
|
||
optional(kSemicolon),
|
||
field("body", $.block_statement),
|
||
),
|
||
|
||
_qualified_method_name: ($) =>
|
||
seq(
|
||
field("class_name", $.identifier),
|
||
".",
|
||
field("method_name", $._identifier_or_keyword),
|
||
),
|
||
|
||
_identifier_or_keyword: ($) => choice($.identifier, $._soft_keyword),
|
||
|
||
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_clause),
|
||
optional($._property_index),
|
||
field("accessors", $.property_accessors),
|
||
kSemicolon,
|
||
),
|
||
|
||
_property_index: ($) =>
|
||
seq(kw("index"), field("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"), field("read", $.identifier)),
|
||
|
||
_write_only_accessor: ($) => seq(kw("write"), field("write", $.identifier)),
|
||
|
||
_read_write_accessor: ($) =>
|
||
seq(
|
||
kw("read"),
|
||
field("read", $.identifier),
|
||
kw("write"),
|
||
field("write", $.identifier),
|
||
),
|
||
|
||
_write_read_accessor: ($) =>
|
||
seq(
|
||
kw("write"),
|
||
field("write", $.identifier),
|
||
kw("read"),
|
||
field("read", $.identifier),
|
||
),
|
||
|
||
_function_header: ($) =>
|
||
seq(
|
||
choice(kw("function"), kw("procedure")),
|
||
field("name", $.identifier),
|
||
$._parameter_signature,
|
||
optional(field("return_type", $._type_clause)),
|
||
),
|
||
|
||
function_declaration: ($) =>
|
||
seq(
|
||
$._function_header,
|
||
kSemicolon,
|
||
optional(seq(kw("overload"), kSemicolon)),
|
||
),
|
||
|
||
function_definition: ($) =>
|
||
seq(
|
||
$._function_header,
|
||
choice(
|
||
optional(kSemicolon),
|
||
seq(kSemicolon, kw("overload"), repeat1(kSemicolon)),
|
||
),
|
||
field("body", $.block_statement),
|
||
),
|
||
|
||
_parameter_signature: ($) =>
|
||
seq("(", optional(field("parameters", $.parameters)), ")"),
|
||
|
||
parameters: ($) =>
|
||
seq(
|
||
field("parameter", $.parameter),
|
||
repeat(seq(choice(",", kSemicolon), field("parameter", $.parameter))),
|
||
optional(kSemicolon),
|
||
),
|
||
|
||
parameter: ($) =>
|
||
seq(
|
||
optional(field("mode", $.parameter_mode)),
|
||
field("name", $.identifier),
|
||
optional($._type_clause),
|
||
optional(seq("=", field("default_value", $.expression))),
|
||
),
|
||
|
||
parameter_mode: ($) => choice(kw("var"), kw("out"), $.in, kw("const")),
|
||
|
||
// TSLX 块:可以包含文本、TSL 语句、TSL 表达式的混合内容
|
||
// <?tslx匹配到之后,后面的所有内容都当作文本,除非遇到1. <?tsl ?>,必须对应才是tsl_statement 2. <?= ?>必须对应才是tsl_expression 3. 如果遇到了<?tsl,并且没有?>与其对应,应该将<?tsl当作<?tslx的结束块标记,然后结束后交给grammar.js匹配其他规则
|
||
tslx_block: ($) =>
|
||
prec.right(
|
||
seq(
|
||
$.tslx_tag,
|
||
repeat(
|
||
choice(
|
||
$.tslx_content, // 普通文本内容
|
||
$._tsl_statement_block, // <?tsl ... ?>
|
||
$._tsl_expression_block, // <?= ... ?>
|
||
),
|
||
),
|
||
$.tslx_end_tag,
|
||
),
|
||
),
|
||
|
||
_tsl_statement_block: ($) =>
|
||
seq(
|
||
$.tsl_statement_start_tag,
|
||
repeat1($._statement),
|
||
$.tsl_statement_end_tag,
|
||
),
|
||
|
||
_tsl_expression_block: ($) =>
|
||
seq($.tsl_expression_start_tag, $.expression, $.tsl_expression_end_tag),
|
||
|
||
tslx_tag: (_) => seq("<?", kw("tslx"), ">"),
|
||
|
||
compiler_directive_statement: ($) =>
|
||
seq(
|
||
"{$",
|
||
field("name", $.identifier),
|
||
optional(field("switch", choice("+", "-"))),
|
||
"}",
|
||
),
|
||
|
||
_conditional_compilation_statement: ($) =>
|
||
choice($.conditional_block_statement, $.conditional_directive_statement),
|
||
|
||
conditional_directive_statement: ($) =>
|
||
seq(
|
||
"{$",
|
||
choice(kw("define"), kw("undef")),
|
||
field("name", $.identifier),
|
||
"}",
|
||
),
|
||
|
||
conditional_block_statement: ($) =>
|
||
seq(
|
||
"{$",
|
||
field("keyword", choice(kw("ifdef"), kw("ifndef"))),
|
||
field("name", $.identifier),
|
||
"}",
|
||
repeat(field("consequence", $._statement)),
|
||
optional(
|
||
seq(
|
||
"{$",
|
||
kw("else"),
|
||
"}",
|
||
repeat(field("alternative", $._statement)),
|
||
),
|
||
),
|
||
"{$",
|
||
kw("endif"),
|
||
"}",
|
||
),
|
||
|
||
matrix_iteration_statement: ($) =>
|
||
seq(
|
||
field("target", $.expression),
|
||
"::",
|
||
field("body", $.block_statement),
|
||
),
|
||
|
||
if_statement: ($) =>
|
||
prec.right(
|
||
kPrec.kIf,
|
||
seq($.if_clause, repeat($.else_if_clause), optional($.else_clause)),
|
||
),
|
||
|
||
if_clause: ($) =>
|
||
seq(
|
||
kw("if"),
|
||
field("condition", $.expression),
|
||
kw("then"),
|
||
field("consequence", $._statement),
|
||
),
|
||
|
||
else_if_clause: ($) =>
|
||
prec(
|
||
kPrec.kElif,
|
||
seq(
|
||
kw("else"),
|
||
kw("if"),
|
||
field("condition", $.expression),
|
||
kw("then"),
|
||
field("consequence", $._statement),
|
||
),
|
||
),
|
||
|
||
else_clause: ($) => seq(kw("else"), field("consequence", $._statement)),
|
||
|
||
_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),
|
||
),
|
||
|
||
for_to_statement: ($) =>
|
||
seq(
|
||
kw("for"),
|
||
field("counter", $.identifier),
|
||
":=",
|
||
field("start", $.expression),
|
||
field("direction", choice(kw("to"), kw("downto"))),
|
||
field("end", $.expression),
|
||
optional(seq(kw("step"), field("step", $.expression))),
|
||
$.do,
|
||
field("body", $._statement),
|
||
),
|
||
|
||
while_statement: ($) =>
|
||
seq(
|
||
kw("while"),
|
||
field("condition", $.expression),
|
||
$.do,
|
||
field("body", $._statement),
|
||
),
|
||
|
||
repeat_statement: ($) =>
|
||
seq(
|
||
kw("repeat"),
|
||
field("body", repeat($._statement)),
|
||
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"),
|
||
),
|
||
|
||
case_branch: ($) =>
|
||
seq(
|
||
$._case_values,
|
||
":",
|
||
field("consequence", $._statement),
|
||
optional(kSemicolon),
|
||
),
|
||
|
||
_case_values: ($) => sep1(field("value", $.expression), ","),
|
||
|
||
case_else: ($) =>
|
||
seq(kw("else"), field("consequence", $._statement), optional(kSemicolon)),
|
||
|
||
try_statement: ($) =>
|
||
seq(
|
||
kw("try"),
|
||
field("try_body", optional($.block_body)),
|
||
kw("except"),
|
||
field("except_body", optional($.block_body)),
|
||
kw("end"),
|
||
),
|
||
|
||
block_body: ($) =>
|
||
choice(seq(repeat1($._statement), optional($.expression)), $.expression),
|
||
|
||
block_statement: ($) =>
|
||
seq(kw("begin"), optional(field("body", $.block_body)), kw("end")), // optional为了兼容begin end上一句可以没用分号
|
||
|
||
uses_statement: ($) =>
|
||
seq(kw("uses"), sep1(field("unit", $.identifier), ","), kSemicolon),
|
||
|
||
break_statement: (_) => seq(kw("break"), kSemicolon),
|
||
|
||
continue_statement: (_) => seq(kw("continue"), kSemicolon),
|
||
|
||
return_statement: ($) =>
|
||
seq(kw("return"), field("value", optional($.expression)), kSemicolon),
|
||
|
||
var_declaration: ($) =>
|
||
seq(
|
||
kw("var"),
|
||
$._identifier_list,
|
||
optional($._type_clause),
|
||
optional($._initializer),
|
||
kSemicolon,
|
||
),
|
||
|
||
static_declaration: ($) =>
|
||
seq(
|
||
kw("static"),
|
||
$._identifier_list,
|
||
optional($._type_clause),
|
||
optional($._initializer),
|
||
kSemicolon,
|
||
),
|
||
|
||
global_declaration: ($) =>
|
||
seq(
|
||
kw("global"),
|
||
$._identifier_list,
|
||
optional($._type_clause),
|
||
optional($._initializer),
|
||
kSemicolon,
|
||
),
|
||
|
||
const_declaration: ($) =>
|
||
seq(
|
||
kw("const"),
|
||
field("name", $.identifier),
|
||
optional($._type_clause),
|
||
"=",
|
||
field("value", $.expression),
|
||
kSemicolon,
|
||
),
|
||
|
||
_identifier_list: ($) => sep1(field("name", $.identifier), ","),
|
||
|
||
_initializer: ($) => seq(":=", field("initializer", $.expression)),
|
||
|
||
_type_clause: ($) => seq(":", field("type", $.type_name)),
|
||
|
||
type_name: (_) =>
|
||
token(
|
||
choice(
|
||
// array of xxx
|
||
seq("array", /\s+/, "of", /\s+/, /[_a-zA-Z][_a-zA-Z0-9_.]*/),
|
||
/[_a-zA-Z][_a-zA-Z0-9_.]*/,
|
||
),
|
||
),
|
||
|
||
anonymous_function_statement: ($) =>
|
||
seq(
|
||
optional(
|
||
seq(
|
||
field("left", $.lvalue_expression),
|
||
field("operator", $._assignment_operator),
|
||
),
|
||
),
|
||
field("right", $.anonymous_function_expression),
|
||
),
|
||
|
||
anonymous_function_expression: ($) =>
|
||
seq(
|
||
optional(kw("static")),
|
||
kw("function"),
|
||
$._parameter_signature,
|
||
optional(field("return_type", $._type_clause)),
|
||
optional(kSemicolon),
|
||
field("body", $.block_statement),
|
||
),
|
||
|
||
_empty_statement: (_) => kSemicolon,
|
||
|
||
expression_statement: ($) => seq($.expression, kSemicolon),
|
||
|
||
expression: ($) =>
|
||
choice(
|
||
$._tssql_select_expression,
|
||
$._tssql_dml_expression,
|
||
|
||
$.assignment_expression,
|
||
$.ternary_expression,
|
||
$.binary_expression,
|
||
$.unary_expression,
|
||
|
||
$.call_expression,
|
||
$.subscript_expression,
|
||
$.attribute_expression,
|
||
|
||
$._primary_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", $.from_item),
|
||
kw("set"),
|
||
field("assignments", sep1($.update_assignment, ",")),
|
||
optional(field("where", $.where_clause)),
|
||
kw("end"),
|
||
),
|
||
|
||
delete_expression: ($) =>
|
||
prec.right(
|
||
seq(
|
||
kw("delete"),
|
||
kw("from"),
|
||
field("table", $.delete_or_insert_item),
|
||
optional(field("where", $.where_clause)),
|
||
),
|
||
),
|
||
|
||
insert_expression: ($) =>
|
||
prec.right(
|
||
seq(
|
||
kw("insert"),
|
||
optional(kw("into")),
|
||
field("table", $.delete_or_insert_item),
|
||
optional($.insert_fields),
|
||
optional(choice($.values_clause, field("source", $.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: ($) =>
|
||
choice(
|
||
seq(kw("drange"), "(", choice($.drange_to, $.drange_of), ")"),
|
||
$.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_item, repeat(seq(",", $.select_item))),
|
||
|
||
select_item: ($) =>
|
||
seq(field("expression", $.expression), optional($.alias_clause)),
|
||
|
||
alias_clause: ($) => seq(kw("as"), $.expression),
|
||
|
||
from_clause: ($) => seq(kw("from"), $.from_item),
|
||
|
||
from_item: ($) => choice($.join_clause, $.sqltable, $._table_or_subquery),
|
||
|
||
delete_or_insert_item: ($) => choice($.sqltable, $._table_or_subquery),
|
||
|
||
join_clause: ($) => 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: ($) =>
|
||
prec.left(
|
||
seq(
|
||
kw("with"),
|
||
"(",
|
||
field("left_fields", sep1($.expression, ",")),
|
||
kw("on"),
|
||
field("right_fields", sep1($.expression, ",")),
|
||
")",
|
||
),
|
||
),
|
||
|
||
sqltable: ($) => seq(kw("sqltable"), $.expression, kw("of"), $.expression),
|
||
|
||
_table_or_subquery: ($) =>
|
||
choice(
|
||
prec(0, $.expression),
|
||
prec(1, seq("(", $.select_expression, ")")),
|
||
),
|
||
|
||
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)),
|
||
|
||
column_reference: ($) =>
|
||
prec(kPrec.kPrimary, seq("[", field("value", $.expression), "]")),
|
||
|
||
update_assignment: ($) =>
|
||
seq(
|
||
field("column", $.lvalue_expression),
|
||
"=",
|
||
field("value", $.expression),
|
||
),
|
||
|
||
insert_fields: ($) => seq(kw("insertfields"), $.parenthesized_expression),
|
||
|
||
values_clause: ($) => seq(kw("values"), "(", sep1($.expression, ","), ")"),
|
||
|
||
assignment_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kAssignment,
|
||
seq(
|
||
field("left", $.lvalue_expression),
|
||
field("operator", $._assignment_operator),
|
||
field("right", $.expression),
|
||
),
|
||
),
|
||
|
||
lvalue_expression: ($) =>
|
||
choice(
|
||
$._identifier_or_keyword,
|
||
$.subscript_expression,
|
||
$.attribute_expression,
|
||
$.unpack_pattern,
|
||
$.column_reference,
|
||
$.sql_keyword,
|
||
),
|
||
|
||
_assignment_operator: (_) =>
|
||
choice(
|
||
":=",
|
||
"+=",
|
||
"-=",
|
||
"*=",
|
||
"/=",
|
||
"\\=",
|
||
"^=",
|
||
"~=",
|
||
"%=",
|
||
seq(kw("div"), "="),
|
||
"|=",
|
||
":|=",
|
||
"&=",
|
||
":*=",
|
||
":/=",
|
||
":\\=",
|
||
":^=",
|
||
"::=",
|
||
".|=",
|
||
".&=",
|
||
".||=",
|
||
".&&=",
|
||
".^=",
|
||
seq(kw("union"), "="),
|
||
seq(kw("union2"), "="),
|
||
seq(kw("intersect"), "="),
|
||
seq(kw("outersect"), "="),
|
||
seq(kw("minus"), "="),
|
||
),
|
||
|
||
ternary_expression: ($) =>
|
||
prec.left(
|
||
kPrec.kTernary,
|
||
seq(
|
||
field("condition", $.expression),
|
||
"?",
|
||
optional(field("consequence", $.expression)),
|
||
":",
|
||
field("alternative", $.expression),
|
||
),
|
||
),
|
||
|
||
binary_expression: ($) => {
|
||
const operators = [
|
||
[kPrec.kLogicalOr, choice(kw("or"), ".||", "||")],
|
||
[kPrec.kLogicalAnd, choice(kw("and"), ".&&", "&&")],
|
||
|
||
[kPrec.kBitwiseOr, ".|"],
|
||
[kPrec.kBitwiseXor, ".^"],
|
||
[kPrec.kBitwiseAnd, ".&"],
|
||
|
||
[
|
||
kPrec.kComparsion,
|
||
choice(
|
||
"=",
|
||
".=",
|
||
"<>",
|
||
".<>",
|
||
">",
|
||
".>",
|
||
"<",
|
||
".<",
|
||
">=",
|
||
".>=",
|
||
"<=",
|
||
".<=",
|
||
kw("like"),
|
||
kw("in"),
|
||
kw("is"),
|
||
),
|
||
],
|
||
|
||
[
|
||
kPrec.kSet,
|
||
choice(
|
||
kw("union"),
|
||
kw("union2"),
|
||
kw("intersect"),
|
||
kw("outersect"),
|
||
kw("minus"),
|
||
),
|
||
],
|
||
|
||
[kPrec.kRange, "->"],
|
||
[kPrec.kMatrixConcat, choice("|", ":|")],
|
||
|
||
[kPrec.kAddSub, choice("+", "-")],
|
||
|
||
[kPrec.kShift, choice(kw("shl"), kw("shr"), kw("rol"), kw("ror"))],
|
||
|
||
[kPrec.kMultDiv, choice("*", "/", "\\", "%", kw("mod"), kw("div"))],
|
||
[kPrec.kMatrixMultDiv, choice(":*", ":/", ":\\")],
|
||
|
||
[kPrec.kLogarithm, "~"],
|
||
[kPrec.kConcat, "$"],
|
||
];
|
||
|
||
return choice(
|
||
...operators.map(([precedence, operator]) =>
|
||
prec.left(
|
||
precedence,
|
||
seq(
|
||
field("left", $.expression),
|
||
field("operator", operator),
|
||
field("right", $.expression),
|
||
),
|
||
),
|
||
),
|
||
|
||
// 幂运算(右结合)
|
||
prec.right(
|
||
kPrec.kPower,
|
||
seq(
|
||
field("left", $.expression),
|
||
field("operator", choice("^", ":^")),
|
||
field("right", $.expression),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
|
||
unary_expression: ($) =>
|
||
choice(
|
||
$.unary_plus_expression,
|
||
$.unary_minus_expression,
|
||
$.prefix_increment_expression,
|
||
$.prefix_decrement_expression,
|
||
$.postfix_increment_expression,
|
||
$.postfix_decrement_expression,
|
||
$.logical_not_expression,
|
||
$.bitwise_not_expression,
|
||
$.derivative_expression,
|
||
$.function_pointer_expression,
|
||
$.matrix_transpose_expression,
|
||
$.expr_operator_expression,
|
||
),
|
||
|
||
unary_plus_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kUnaryPrefix,
|
||
seq(field("operator", "+"), field("argument", $.expression)),
|
||
),
|
||
|
||
unary_minus_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kUnaryPrefix,
|
||
seq(field("operator", "-"), field("argument", $.expression)),
|
||
),
|
||
|
||
prefix_increment_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kUnaryPrefix,
|
||
seq(field("operator", "++"), field("argument", $.expression)),
|
||
),
|
||
|
||
prefix_decrement_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kUnaryPrefix,
|
||
seq(field("operator", "--"), field("argument", $.expression)),
|
||
),
|
||
|
||
postfix_increment_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kUnaryPrefix,
|
||
seq(field("argument", $.expression), field("operator", "++")),
|
||
),
|
||
|
||
postfix_decrement_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kUnaryPrefix,
|
||
seq(field("argument", $.expression), field("operator", "--")),
|
||
),
|
||
|
||
logical_not_expression: ($) =>
|
||
prec.left(
|
||
kPrec.kUnaryPrefix,
|
||
seq(
|
||
field("operator", choice(kw("not"), ".!!")),
|
||
field("argument", $.expression),
|
||
),
|
||
),
|
||
|
||
bitwise_not_expression: ($) =>
|
||
prec.left(
|
||
kPrec.kUnaryPrefix,
|
||
seq(field("operator", ".!"), field("argument", $.expression)),
|
||
),
|
||
|
||
derivative_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kUnaryPrefix,
|
||
seq(field("operator", "!"), field("argument", $.expression)),
|
||
),
|
||
|
||
function_pointer_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kUnaryPrefix,
|
||
seq(field("operator", "##"), field("argument", $.expression)),
|
||
),
|
||
|
||
matrix_transpose_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kUnaryPrefix,
|
||
seq(field("operator", "`"), field("argument", $.expression)),
|
||
),
|
||
|
||
expr_operator_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kExprOperator,
|
||
seq(
|
||
field("operator", choice("@", "&")),
|
||
field("argument", $.expression),
|
||
),
|
||
),
|
||
|
||
call_expression: ($) =>
|
||
prec.left(
|
||
kPrec.kCall,
|
||
seq(
|
||
field("callee", $.expression),
|
||
"(",
|
||
optional(
|
||
sep1(
|
||
field("argument", seq(optional($.parameter_mode), $.argument)),
|
||
",",
|
||
),
|
||
),
|
||
")",
|
||
),
|
||
),
|
||
|
||
argument: ($) => choice($.expression, $.named_argument),
|
||
|
||
named_argument: ($) =>
|
||
seq(field("name", $.identifier), ":", field("value", $.expression)),
|
||
|
||
subscript_expression: ($) =>
|
||
prec.left(
|
||
kPrec.kSubscript,
|
||
seq(
|
||
field("base", $.expression),
|
||
"[",
|
||
field("index", optional($.subscript_index)),
|
||
"]",
|
||
),
|
||
),
|
||
|
||
subscript_index: ($) => choice($.expression, $.slice, $.matrix_slice),
|
||
|
||
slice: ($) =>
|
||
seq(
|
||
optional(field("start", $.expression)),
|
||
":",
|
||
optional(field("end", $.expression)),
|
||
),
|
||
|
||
matrix_slice: ($) =>
|
||
seq(
|
||
choice($.expression, $.slice),
|
||
repeat1(seq(",", choice($.expression, $.slice))),
|
||
),
|
||
|
||
attribute_expression: ($) =>
|
||
prec.left(
|
||
kPrec.kAttribute,
|
||
seq(
|
||
field("object", $.expression),
|
||
".",
|
||
field("attribute", $.expression),
|
||
),
|
||
),
|
||
|
||
unpack_pattern: ($) =>
|
||
seq(
|
||
"[",
|
||
$.lvalue_expression,
|
||
repeat1(seq(",", $.lvalue_expression)),
|
||
"]",
|
||
),
|
||
|
||
_primary_expression: ($) =>
|
||
choice(
|
||
$._builtin_expression,
|
||
$.array_expression,
|
||
$.parenthesized_expression,
|
||
$._identifier_or_keyword,
|
||
$._literal,
|
||
|
||
// 特殊符号
|
||
$.ellipsis,
|
||
|
||
// 目前sql才用到
|
||
$.asterisk,
|
||
$.column_reference,
|
||
$.sql_keyword,
|
||
),
|
||
|
||
_builtin_expression: ($) =>
|
||
choice(
|
||
$.new_expression,
|
||
$.echo_expression,
|
||
$.raise_expression,
|
||
$.inherited_expression,
|
||
),
|
||
|
||
new_expression: ($) => seq(kw("new"), field("target", $.expression)),
|
||
|
||
echo_expression: ($) => prec.left(seq(kw("echo"), sep1($.expression, ","))),
|
||
|
||
raise_expression: ($) => seq(kw("raise"), field("exception", $.expression)),
|
||
|
||
inherited_expression: ($) =>
|
||
prec.right(
|
||
kPrec.kCall,
|
||
seq(kw("inherited"), optional(field("class", $.call_expression))),
|
||
),
|
||
|
||
array_expression: ($) =>
|
||
prec(
|
||
kPrec.kArray,
|
||
seq(kw("array"), "(", optional($._array_elements), ")"),
|
||
),
|
||
|
||
_array_elements: ($) => seq(sep1($.array_element, ","), optional(",")),
|
||
|
||
array_element: ($) => choice($.key_value_pair, $.expression),
|
||
|
||
key_value_pair: ($) =>
|
||
seq(field("key", $.expression), ":", field("value", $.expression)),
|
||
|
||
parenthesized_expression: ($) =>
|
||
prec(
|
||
kPrec.kParenthesized,
|
||
choice(
|
||
seq("(", ")"),
|
||
seq("(", sep1($._parenthesized_element, ","), optional(","), ")"),
|
||
),
|
||
),
|
||
|
||
_parenthesized_element: ($) => choice($.key_value_pair, $.expression),
|
||
|
||
_soft_keyword: ($) =>
|
||
choice(
|
||
alias($.unit, $.identifier),
|
||
alias($.class, $.identifier),
|
||
alias($.in, $.identifier),
|
||
alias($.type, $.identifier),
|
||
alias($.do, $.identifier),
|
||
alias($.select, $.identifier),
|
||
alias($.sselect, $.identifier),
|
||
alias($.vselect, $.identifier),
|
||
alias($.update, $.identifier),
|
||
alias($.insert, $.identifier),
|
||
alias($.delete, $.identifier),
|
||
),
|
||
|
||
unit: (_) => kw("unit"),
|
||
class: (_) => kw("class"),
|
||
in: (_) => kw("in"),
|
||
type: (_) => kw("type"),
|
||
do: (_) => kw("do"),
|
||
select: (_) => kw("select"),
|
||
sselect: (_) => kw("sselect"),
|
||
vselect: (_) => kw("vselect"),
|
||
update: (_) => kw("update"),
|
||
insert: (_) => kw("insert"),
|
||
delete: (_) => kw("delete"),
|
||
|
||
sql_keyword: (_) => choice(kw("thisrow"), kw("thisrowindex")),
|
||
|
||
identifier: (_) =>
|
||
token(
|
||
prec(
|
||
kPrec.kIdentifier,
|
||
/[a-zA-Z_\u4e00-\u9fa5][\w\u4e00-\u9fa5]*/, // 使用Unicode中文范围
|
||
),
|
||
),
|
||
|
||
_literal: ($) =>
|
||
choice($.number, $.string, $.char, $.boolean, $.nil, $.nan, $.infinity),
|
||
|
||
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(
|
||
"\\",
|
||
choice(
|
||
/./, // 任意单字符转义 (\n, \t, \", \\, 等)
|
||
/x[0-9a-fA-F]{2}/, // \xHH
|
||
/u[0-9a-fA-F]{4}/, // \uHHHH
|
||
/U[0-9a-fA-F]{8}/, // \UHHHHHHHH
|
||
),
|
||
),
|
||
),
|
||
),
|
||
'"',
|
||
),
|
||
|
||
// 单引号字符串
|
||
seq(
|
||
"'",
|
||
repeat(
|
||
choice(
|
||
/[^'\\]+/, // 普通字符(允许换行)
|
||
seq(
|
||
"\\",
|
||
choice(
|
||
/./,
|
||
/x[0-9a-fA-F]{2}/,
|
||
/u[0-9a-fA-F]{4}/,
|
||
/U[0-9a-fA-F]{8}/,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
"'",
|
||
),
|
||
|
||
// L 字符串(保持原样)
|
||
seq(
|
||
"L",
|
||
choice(
|
||
seq("'", repeat(choice(/[^'\\]+/, /\\./)), "'"),
|
||
seq('"', repeat(choice(/[^"\\]+/, /\\./)), '"'),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
|
||
boolean: ($) => choice($.true, $.false),
|
||
|
||
char: (_) => token(seq("#", choice(/\d+/, /\$[0-9a-fA-F]+/))),
|
||
|
||
true: (_) => kw("true"),
|
||
|
||
false: (_) => kw("false"),
|
||
|
||
nil: (_) => kw("nil"),
|
||
|
||
nan: (_) => kw("nan"),
|
||
|
||
infinity: ($) => choice($.minus_inf, $.plus_inf),
|
||
|
||
minus_inf: (_) => kw("-inf"),
|
||
|
||
plus_inf: (_) => kw("+inf"),
|
||
|
||
ellipsis: (_) => "...",
|
||
|
||
asterisk: (_) => "*",
|
||
|
||
line_comment: (_) => token(seq("//", /.*/)),
|
||
|
||
block_comment: (_) => token(seq("{", /([^$}][^}]*)?/, "}")),
|
||
|
||
nested_comment: (_) => token(/[(][*]([^*]*[*]+[^)*])*[^*]*[*]+[)]/),
|
||
},
|
||
});
|
||
|
||
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());
|
||
}
|