| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293 |
- diff --git a/grammar.js b/grammar.js
- index 21c8523..00bf2b1 100644
- --- a/grammar.js
- +++ b/grammar.js
- @@ -21,10 +21,14 @@ const PRECEDENCE = {
-
- module.exports = grammar({
- name: "vbnet",
- + word: ($) => $._identifier_token,
- +
- + externals: ($) => [$._query_clause_continuation, $.xml_literal],
- +
- extras: $ => [
- $.comment,
- $.preprocessor_directive,
- - /[ \t\v\f]+/,
- + /[ \t\v\f\uFEFF]+/,
- /\r?\n/,
- /_[ \t]*\r?\n/,
- ],
- @@ -38,17 +42,14 @@ module.exports = grammar({
- $._type,
- ],
- conflicts: ($) => [
- + [$.binary_expression, $.assignment_expression, $.inline_assignment_statement],
- [$.simple_name, $.generic_name],
- [$.await_expression, $.with_expression],
- [$._name_reference, $._type],
- [$.object_creation_expression, $.array_creation_expression, $.array_type],
- - [$.string_literal, $.character_literal],
- [$._primary_expression, $.variable_declarator],
- - [$.lambda_expression, $.with_expression],
- - [$.lambda_expression],
- [$.binary_expression, $.assignment_expression],
- [$._primary_expression, $.select_element],
- - [$.with_expression, $.select_element],
- [$.select_clause],
- [$._primary_expression, $.group_element],
- [$._terminator, $._block_terminator],
- @@ -66,7 +67,6 @@ module.exports = grammar({
- [$.aggregate_element, $.into_element],
- [$.group_by_clause],
- [$.else_clause],
- - [$.if_statement],
- [$.case_else_clause],
- [$.case_clause],
- [$.elseif_clause],
- @@ -75,7 +75,6 @@ module.exports = grammar({
- [$._primary_expression, $.simple_name, $.generic_name],
- [$._primary_expression, $.variable_declarator, $.labeled_statement],
- [$._statement, $.with_statement],
- - [$.dictionary_initializer, $.collection_initializer],
- [
- $.class_declaration,
- $.structure_declaration,
- @@ -89,7 +88,6 @@ module.exports = grammar({
- ],
- ],
-
- - word: ($) => $._identifier_token,
-
- rules: {
- source_file: ($) =>
- @@ -157,13 +155,14 @@ module.exports = grammar({
- ),
-
- _terminator: ($) =>
- - choice(seq(optional(":"), choice("\n", "\r\n")), $._eof),
- + prec.right(choice(seq(optional(":"), choice("\n", "\r\n")), prec(-1, ":"), $._eof)),
-
- - _block_terminator: ($) => prec.right(repeat1(choice("\n", "\r\n", $._eof))),
- + _block_terminator: ($) => prec.right(repeat1(choice("\n", "\r\n", ":", $._eof))),
-
- _eof: ($) => token(prec(-10, "$")),
-
- - _identifier_token: ($) => token(prec(-1, /[a-zA-Z_][a-zA-Z0-9_]*/)),
- + _identifier_token: ($) =>
- + token(prec(-1, /[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Pc}]*[%$&!#@]?/u)),
-
- identifier: ($) =>
- choice(
- @@ -194,7 +193,6 @@ module.exports = grammar({
- ci("MustInherit"),
- ci("NotInheritable"),
- ci("Overrides"),
- - ci("MustOverride"),
- ci("NotOverridable"),
- ci("Overridable"),
- ci("Overloads"),
- @@ -225,43 +223,6 @@ module.exports = grammar({
- $._statement // Fallback to regular statements
- ),
-
- - _non_statement_identifier: $ => choice(
- - // Match identifiers that don't start with statement keywords
- - token(prec(1, seq(
- - negative_lookahead(seq(
- - choice(
- - /[Tt][Rr][Yy]/,
- - /[Ss][Ee][Ll][Ee][Cc][Tt]/,
- - /[Ii][Ff]/,
- - /[Ww][Hh][Ii][Ll][Ee]/,
- - /[Dd][Oo]/,
- - /[Ff][Oo][Rr]/,
- - /[Uu][Ss][Ii][Nn][Gg]/,
- - /[Ww][Ii][Tt][Hh]/,
- - /[Tt][Hh][Rr][Oo][Ww]/,
- - /[Rr][Ee][Tt][Uu][Rr][Nn]/,
- - /[Ee][Xx][Ii][Tt]/,
- - /[Cc][Oo][Nn][Tt][Ii][Nn][Uu][Ee]/,
- - /[Ss][Tt][Oo][Pp]/,
- - /[Ee][Nn][Dd]/,
- - /[Gg][Oo][Tt][Oo]/,
- - /[Rr][Ee][Ss][Uu][Mm][Ee]/,
- - /[Ee][Rr][Rr][Oo][Rr]/,
- - /[Oo][Nn]/,
- - /[Rr][Ee][Dd][Ii][Mm]/,
- - /[Ee][Rr][Aa][Ss][Ee]/,
- - /[Ss][Yy][Nn][Cc][Ll][Oo][Cc][Kk]/,
- - /[Rr][Aa][Ii][Ss][Ee][Ee][Vv][Ee][Nn][Tt]/,
- - /[Aa][Dd][Dd][Hh][Aa][Nn][Dd][Ll][Ee][Rr]/,
- - /[Rr][Ee][Mm][Oo][Vv][Ee][Hh][Aa][Nn][Dd][Ll][Ee][Rr]/
- - ),
- - choice(/\s/, /\r/, /\n/, /$/)
- - )),
- - /[a-zA-Z_][a-zA-Z0-9_]*/
- - ))),
- - seq("[", /[^\]]+/, "]") // Bracketed identifier can be anything
- - ),
- -
- local_declaration_modifier: ($) =>
- choice(ci("Dim"), ci("Const"), ci("Static")),
-
- @@ -300,6 +261,8 @@ module.exports = grammar({
- _primary_expression: ($) =>
- choice(
- $._literal,
- + $.array_literal,
- + $.tuple_expression,
- $.identifier,
- $.parenthesized_expression,
- $.generic_invocation_expression, // Add this before regular invocation
- @@ -320,17 +283,26 @@ module.exports = grammar({
- ),
-
- generic_invocation_expression: ($) =>
- - prec(
- - PRECEDENCE.INVOCATION + 1,
- + prec.right(
- + PRECEDENCE.INVOCATION + 1,
- seq(
- field("function", $._expression),
- field("type_arguments", $.type_argument_list),
- - field("arguments", $.argument_list)
- + optional(field("arguments", $.argument_list))
- )
- ),
-
- parenthesized_expression: ($) => seq("(", $._expression, ")"),
-
- + tuple_expression: ($) =>
- + seq(
- + "(",
- + choice($._expression, seq(field("name", $.identifier), ":=", $._expression)),
- + ",",
- + commaSep1(choice($._expression, seq(field("name", $.identifier), ":=", $._expression))),
- + ")"
- + ),
- +
- member_access_expression: ($) =>
- prec.left(
- PRECEDENCE.MEMBER_ACCESS,
- @@ -350,20 +322,23 @@ module.exports = grammar({
- )
- ),
-
- - argument_list: ($) => seq("(", optional(commaSep1($._argument)), ")"),
- + argument_list: ($) => seq("(", optional($._arguments), ")"),
-
- - _argument: ($) =>
- - choice($._expression, $.named_argument, $.omitted_argument),
- + // Argument slots may be omitted between commas (`f(a,, b)`, `f(, x)`) —
- + // VB passes Optional parameters positionally by leaving the slot empty.
- + _arguments: ($) =>
- + seq($._argument, repeat(seq(",", optional($._argument)))),
-
- - omitted_argument: ($) => token(prec(1, ",")),
- + _argument: ($) => choice($._expression, $.named_argument),
-
- array_access_expression: ($) =>
- prec(
- PRECEDENCE.ARRAY_ACCESS,
- seq(
- field("array", $._expression),
- + optional("?"),
- "(",
- - field("indices", commaSep1($._expression)),
- + field("indices", $._arguments),
- ")"
- )
- ),
- @@ -471,16 +446,53 @@ module.exports = grammar({
- ),
-
- lambda_expression: ($) =>
- - seq(
- - choice(ci("Function"), ci("Sub")),
- - field("parameters", $.lambda_parameter_list),
- - field("body", choice($._expression, $._statement_block))
- + choice(
- + prec.right(
- + seq(
- + optional(choice(ci("Async"), ci("Iterator"))),
- + choice(ci("Function"), ci("Sub")),
- + field("parameters", $.lambda_parameter_list),
- + field(
- + "body",
- + choice(
- + $._expression,
- + alias($.inline_if_statement, $.if_statement),
- + alias($.inline_throw_statement, $.throw_statement)
- + )
- + )
- + )
- + ),
- + seq(
- + optional(choice(ci("Async"), ci("Iterator"))),
- + ci("Function"),
- + field("parameters", $.lambda_parameter_list),
- + optional($.as_clause),
- + $._block_terminator,
- + repeat($._statement),
- + ci("End"), ci("Function")
- + ),
- + seq(
- + optional(choice(ci("Async"), ci("Iterator"))),
- + ci("Sub"),
- + field("parameters", $.lambda_parameter_list),
- + $._block_terminator,
- + repeat($._statement),
- + ci("End"), ci("Sub")
- + )
- ),
-
- lambda_parameter_list: ($) => seq("(", commaSep($.lambda_parameter), ")"),
-
- lambda_parameter: ($) =>
- - seq(field("name", $.identifier), optional($.as_clause)),
- + seq(
- + optional(field("modifiers", repeat1(choice(ci("ByVal"), ci("ByRef"))))),
- + field("name", $.identifier),
- + optional(choice(
- + $.array_rank_specifier,
- + seq("(", field("bounds", commaSep1($._expression)), ")")
- + )),
- + optional($.as_clause)
- + ),
-
- typeof_is_expression: ($) =>
- prec.left(
- @@ -488,7 +500,7 @@ module.exports = grammar({
- seq(
- ci("TypeOf"),
- field("expression", $._expression),
- - ci("Is"),
- + choice(seq(ci("Is"), ci("Not")), token(prec(12, ci("IsNot"))), ci("Is")),
- field("type", $._type)
- )
- ),
- @@ -504,29 +516,12 @@ module.exports = grammar({
- "initializer",
- choice(
- $.object_initializer,
- - $.collection_initializer,
- - $.dictionary_initializer // Add this new option
- + $.collection_initializer
- )
- )
- )
- ),
-
- - dictionary_initializer: ($) =>
- - seq(
- - ci("From"),
- - "{",
- - commaSep($.dictionary_element),
- - "}"
- - ),
- -
- - dictionary_element: ($) =>
- - seq(
- - "{",
- - field("key", $._expression),
- - ",",
- - field("value", $._expression),
- - "}"
- - ),
-
-
- object_initializer: ($) =>
- @@ -551,6 +546,8 @@ module.exports = grammar({
- collection_initializer: ($) =>
- seq(ci("From"), "{", commaSep($._expression), "}"),
-
- + array_literal: ($) => seq("{", commaSep($._expression), "}"),
- +
-
- array_creation_expression: ($) =>
- seq(
- @@ -646,6 +643,9 @@ module.exports = grammar({
- seq(field("object", $._expression), "!", field("member", $.identifier)),
- _literal: ($) =>
- choice(
- + $.xml_literal,
- + $.interpolated_string_literal,
- + $.date_literal,
- $.string_literal,
- $.character_literal,
- $.integer_literal,
- @@ -654,16 +654,49 @@ module.exports = grammar({
- $.nothing_literal,
- $.date_literal
- ),
- - string_literal: ($) => seq('"', repeat(choice(/[^"\n]+/, '""')), '"'),
- - character_literal: ($) => seq('"', choice(/[^"\n]/, '""'), '"', "c"),
- + string_literal: ($) => token(seq('"', repeat(choice(/[^"]/, '""')), '"')),
- + interpolated_string_literal: ($) =>
- + seq(
- + '$"',
- + repeat(
- + choice(
- + token.immediate(prec(101, /[^"{}]+/)),
- + token.immediate(prec(101, '""')),
- + token.immediate(prec(101, "{{")),
- + token.immediate(prec(101, "}}")),
- + $.interpolation
- + )
- + ),
- + token.immediate('"')
- + ),
- + interpolation: ($) =>
- + seq(
- + token.immediate(prec(101, "{")),
- + $._expression,
- + optional(seq(",", /-?\d+/)),
- + optional(seq(":", /[^}"\r\n]+/)),
- + "}"
- + ),
- + date_literal: ($) => token(prec(2, /#[ \t]*\d[^#\r\n]*#/)),
- + character_literal: ($) => token(seq('"', choice(/[^"\r\n]/, '""'), '"', /[cC]/)),
- integer_literal: ($) =>
- - token(seq(/\d+/, optional(choice("I", "UI", "L", "UL", "S", "US")))),
- + token(
- + seq(
- + choice(
- + /\d+(_+\d+)*/,
- + /&[Hh][0-9A-Fa-f]+(_+[0-9A-Fa-f]+)*/,
- + /&[Oo][0-7]+(_+[0-7]+)*/,
- + /&[Bb][01]+(_+[01]+)*/
- + ),
- + optional(choice(/[Uu][SsIiLl]/, /[SsIiLl]/, "%", "&"))
- + )
- + ),
- floating_point_literal: ($) =>
- token(
- seq(
- choice(seq(/\d+/, ".", /\d+/), seq(".", /\d+/), /\d+/),
- optional(/[eE][+-]?\d+/),
- - optional(choice("F", "D", "R"))
- + optional(/[FfRrDd!#@]/)
- )
- ),
- boolean_literal: ($) => choice(ci("True"), ci("False")),
- @@ -672,7 +705,7 @@ module.exports = grammar({
-
- // Names and types
- _name_reference: ($) =>
- - choice($.simple_name, $.qualified_name, $.global_qualified_name),
- + choice($.simple_name, $.generic_name, $.qualified_name, $.global_qualified_name),
-
- simple_name: ($) => $.identifier,
-
- @@ -682,7 +715,7 @@ module.exports = grammar({
- seq(
- field("qualifier", $._name_reference),
- ".",
- - field("name", $.simple_name)
- + field("name", choice($.simple_name, $.generic_name))
- )
- ),
- global_qualified_name: ($) =>
- @@ -694,6 +727,7 @@ module.exports = grammar({
- $.simple_name,
- $.qualified_name,
- $.generic_name,
- + $.global_qualified_name,
- $.predefined_type,
- $.array_type,
- $.tuple_type
- @@ -720,7 +754,8 @@ module.exports = grammar({
- ),
-
- generic_name: ($) => seq(field("name", $.identifier), $.type_argument_list),
- - type_argument_list: ($) => seq("(", ci("Of"), commaSep1($._type), ")"),
- + type_argument_list: ($) =>
- + seq("(", ci("Of"), optional($._type), repeat(seq(",", optional($._type))), ")"),
- array_type: ($) =>
- seq(field("element_type", $._type), $.array_rank_specifier),
- array_rank_specifier: ($) => seq("(", repeat(","), ")"),
- @@ -742,10 +777,14 @@ module.exports = grammar({
- field("type", $._type)
- ),
-
- - as_clause: ($) => seq(
- - ci("As"),
- - field("declared_type", $._type)
- - ),
- + as_clause: ($) =>
- + seq(
- + ci("As"),
- + choice(
- + $.object_creation_expression,
- + field("declared_type", $._type)
- + )
- + ),
-
- implements_member_clause: ($) =>
- seq(ci("Implements"), commaSep1($._name_reference)),
- @@ -856,7 +895,7 @@ module.exports = grammar({
-
- enum_member_declaration: ($) =>
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- field("name", $.identifier),
- optional(seq("=", field("value", $._expression))),
- $._terminator
- @@ -882,6 +921,10 @@ module.exports = grammar({
- prec(10, $.inherits_statement),
- prec(10, $.implements_statement),
- prec(100, $.constructor_declaration),
- + prec(150, $.external_method_declaration),
- + prec(160, $.custom_event_declaration),
- + prec(170, $.abstract_method_declaration),
- + prec(171, $.abstract_property_declaration),
- // Explicitly add statements that can appear at class level
- prec(200, $.try_statement), // Very high precedence
- prec(200, $.select_statement), // Very high precedence
- @@ -936,33 +979,21 @@ module.exports = grammar({
- variable_declarator: ($) =>
- seq(
- field("name", $.identifier),
- + optional("?"),
- optional(choice(
- // Array bounds specification
- seq("(", field("bounds", commaSep1($._expression)), ")"),
- // Array rank specification
- $.array_rank_specifier
- )),
- - optional(choice(
- - // Regular type declaration
- - $.as_clause,
- - seq(
- - ci("As"),
- - ci("New"),
- - field("type", $._type),
- - optional(field("arguments", $.argument_list)),
- - optional(field("initializer", choice(
- - $.object_initializer,
- - $.collection_initializer
- - )))
- - )
- - )),
- + optional($.as_clause),
- optional(seq("=", field("initializer", $._expression)))
- ),
-
-
- field_declaration: ($) =>
- prec.dynamic(-100, seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(field("modifiers", repeat1($.member_modifier))),
- commaSep1($.variable_declarator),
- $._terminator
- @@ -970,7 +1001,8 @@ module.exports = grammar({
-
- field_variable_declarator: ($) =>
- seq(
- - field("name", $._non_statement_identifier),
- + field("name", $.identifier),
- + optional("?"),
- optional($.array_rank_specifier),
- optional($.as_clause),
- optional(seq("=", field("initializer", $._expression)))
- @@ -978,12 +1010,13 @@ module.exports = grammar({
-
- property_declaration: ($) =>
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(field("modifiers", repeat1($.member_modifier))), // Changed
- ci("Property"),
- field("name", $.identifier),
- optional(field("parameters", $.parameter_list)),
- - $.as_clause,
- + optional($.as_clause),
- + optional(seq("=", field("initializer", $._expression))),
- optional($.implements_member_clause),
- optional(seq("=", field("initializer", $._expression))),
- choice(
- @@ -1001,7 +1034,7 @@ module.exports = grammar({
-
- property_getter: ($) =>
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(field("modifiers", repeat1($.member_modifier))),
- ci("Get"),
- $._block_terminator,
- @@ -1013,7 +1046,7 @@ module.exports = grammar({
-
- property_setter: ($) =>
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(field("modifiers", repeat1($.member_modifier))),
- ci("Set"),
- optional(seq("(", field("parameter", $.parameter), ")")),
- @@ -1028,7 +1061,7 @@ module.exports = grammar({
- prec(
- 1,
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(field("modifiers", repeat1($.member_modifier))),
- choice(
- seq(
- @@ -1063,7 +1096,7 @@ module.exports = grammar({
- prec(
- 100,
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(field("modifiers", repeat1($.member_modifier))),
- $._sub_new,
- optional(field("parameters", $.parameter_list)),
- @@ -1087,7 +1120,7 @@ module.exports = grammar({
-
- event_declaration: ($) =>
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(field("modifiers", repeat1($.member_modifier))), // Changed
- ci("Event"),
- field("name", $.identifier),
- @@ -1098,7 +1131,7 @@ module.exports = grammar({
-
- operator_declaration: ($) =>
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(field("modifiers", repeat1($.member_modifier))), // Changed
- ci("Operator"),
- field(
- @@ -1152,7 +1185,7 @@ module.exports = grammar({
-
- interface_method_declaration: ($) =>
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(field("modifiers", repeat1($.member_modifier))), // Changed
- choice(ci("Sub"), ci("Function")),
- field("name", $.identifier),
- @@ -1164,7 +1197,7 @@ module.exports = grammar({
-
- interface_property_declaration: ($) =>
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(field("modifiers", repeat1($.member_modifier))), // Changed
- ci("Property"),
- field("name", $.identifier),
- @@ -1175,7 +1208,7 @@ module.exports = grammar({
-
- interface_event_declaration: ($) =>
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(field("modifiers", repeat1($.member_modifier))), // Changed
- ci("Event"),
- field("name", $.identifier),
- @@ -1209,7 +1242,7 @@ module.exports = grammar({
-
- parameter: ($) =>
- seq(
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- optional(
- field(
- "modifiers",
- @@ -1273,7 +1306,7 @@ module.exports = grammar({
-
- declaration_statement: ($) =>
- prec(1, seq( // Add precedence
- - optional(field("attributes", $.attribute_list)),
- + repeat(field("attributes", $.attribute_list)),
- field("modifiers", choice(
- $.local_declaration_modifier,
- repeat1($.local_declaration_modifier)
- @@ -1282,6 +1315,65 @@ module.exports = grammar({
- $._terminator
- )),
-
- + _inline_statements: ($) =>
- + prec.right(seq($._inline_statement, repeat(seq(":", $._inline_statement)))),
- +
- + _inline_statement: ($) =>
- + choice(
- + alias($.inline_if_statement, $.if_statement),
- + alias($.inline_assignment_statement, $.assignment_statement),
- + alias($.inline_return_statement, $.return_statement),
- + alias($.inline_throw_statement, $.throw_statement),
- + alias($.inline_goto_statement, $.goto_statement),
- + alias($.inline_exit_statement, $.exit_statement),
- + alias($.inline_continue_statement, $.continue_statement),
- + alias($.inline_call_statement, $.call_statement),
- + alias($.inline_raiseevent_statement, $.raiseevent_statement),
- + alias($.inline_expression_statement, $.expression_statement)
- + ),
- +
- + inline_assignment_statement: ($) =>
- + prec.right(
- + PRECEDENCE.ASSIGNMENT + 1,
- + seq(
- + field("left", choice(
- + $.identifier,
- + $.member_access_expression,
- + $.array_access_expression
- + )),
- + field(
- + "operator",
- + choice("=", "+=", "-=", "*=", "/=", "\\=", "^=", "&=", "<<=", ">>=")
- + ),
- + field("right", $._expression)
- + )
- + ),
- + inline_return_statement: ($) => prec.right(1, seq(ci("Return"), optional($._expression))),
- + inline_throw_statement: ($) => prec.right(1, seq(ci("Throw"), optional($._expression))),
- + inline_goto_statement: ($) => seq(ci("GoTo"), field("label", $.identifier)),
- + inline_exit_statement: ($) =>
- + seq(
- + ci("Exit"),
- + choice(ci("Do"), ci("For"), ci("While"), ci("Select"), ci("Sub"), ci("Function"), ci("Property"), ci("Try"))
- + ),
- + inline_continue_statement: ($) =>
- + seq(ci("Continue"), choice(ci("Do"), ci("For"), ci("While"))),
- + inline_call_statement: ($) => prec.right(1, seq(ci("Call"), $._expression)),
- + inline_raiseevent_statement: ($) =>
- + prec.right(1, seq(ci("RaiseEvent"), field("event", $.identifier), optional(field("arguments", $.argument_list)))),
- + inline_expression_statement: ($) => prec.right(1, $._expression),
- +
- + inline_if_statement: ($) =>
- + prec.right(
- + seq(
- + ci("If"),
- + field("condition", $._expression),
- + ci("Then"),
- + field("then_statement", $._inline_statements),
- + optional(seq(ci("Else"), field("else_statement", $._inline_statements)))
- + )
- + ),
- +
- expression_statement: ($) => seq($._expression, $._terminator),
-
- assignment_statement: ($) =>
- @@ -1301,21 +1393,96 @@ module.exports = grammar({
- $._terminator
- )
- ),
- + custom_event_declaration: ($) =>
- + seq(
- + repeat(field("attributes", $.attribute_list)),
- + optional(field("modifiers", repeat1($.member_modifier))),
- + ci("Custom"),
- + ci("Event"),
- + field("name", $.identifier),
- + $.as_clause,
- + optional($.implements_member_clause),
- + $._block_terminator,
- + repeat($.event_accessor),
- + ci("End"), ci("Event"),
- + $._terminator
- + ),
- +
- + event_accessor: ($) =>
- + seq(
- + choice(ci("AddHandler"), ci("RemoveHandler"), ci("RaiseEvent")),
- + optional(field("parameters", $.parameter_list)),
- + $._block_terminator,
- + repeat($._statement),
- + ci("End"),
- + choice(ci("AddHandler"), ci("RemoveHandler"), ci("RaiseEvent")),
- + $._terminator
- + ),
- +
- + _mustoverride_token: ($) => token(prec(11, ci("MustOverride"))),
- +
- + abstract_method_declaration: ($) =>
- + seq(
- + repeat(field("attributes", $.attribute_list)),
- + optional(field("modifiers", repeat1($.member_modifier))),
- + $._mustoverride_token,
- + optional(field("modifiers", repeat1($.member_modifier))),
- + choice(ci("Sub"), ci("Function")),
- + field("name", $.identifier),
- + optional(field("type_parameters", $.type_parameter_list)),
- + optional(field("parameters", $.parameter_list)),
- + optional($.as_clause),
- + optional($.implements_member_clause),
- + $._terminator
- + ),
- +
- + abstract_property_declaration: ($) =>
- + seq(
- + repeat(field("attributes", $.attribute_list)),
- + optional(field("modifiers", repeat1($.member_modifier))),
- + $._mustoverride_token,
- + optional(field("modifiers", repeat1($.member_modifier))),
- + ci("Property"),
- + field("name", $.identifier),
- + optional(field("parameters", $.parameter_list)),
- + optional($.as_clause),
- + optional($.implements_member_clause),
- + $._terminator
- + ),
- +
- + external_method_declaration: ($) =>
- + seq(
- + repeat(field("attributes", $.attribute_list)),
- + optional(field("modifiers", repeat1($.member_modifier))),
- + ci("Declare"),
- + optional(choice(ci("Auto"), ci("Ansi"), ci("Unicode"))),
- + choice(ci("Sub"), ci("Function")),
- + field("name", $.identifier),
- + ci("Lib"),
- + field("library", $.string_literal),
- + optional(seq(ci("Alias"), field("alias", $.string_literal))),
- + optional(field("parameters", $.parameter_list)),
- + optional($.as_clause),
- + $._terminator
- + ),
- +
- call_statement: ($) => seq(ci("Call"), $._expression, $._terminator),
-
- if_statement: ($) =>
- seq(
- ci("If"),
- field("condition", $._expression),
- - ci("Then"),
- choice(
- - // Single-line if
- + // Single-line if: inline statements, optional Else, one terminator
- seq(
- - field("then_statement", $._statement),
- - optional(seq(ci("Else"), field("else_statement", $._statement)))
- + ci("Then"),
- + field("then_statement", $._inline_statements),
- + optional(seq(ci("Else"), field("else_statement", $._inline_statements))),
- + $._terminator
- ),
- // Multi-line if
- seq(
- + optional(ci("Then")),
- $._block_terminator,
- field("then_branch", repeat($._statement)),
- repeat($.elseif_clause),
- @@ -1331,7 +1498,7 @@ module.exports = grammar({
- seq(
- ci("ElseIf"),
- field("condition", $._expression),
- - ci("Then"),
- + optional(ci("Then")),
- $._block_terminator,
- field("body", repeat($._statement))
- ),
- @@ -1445,7 +1612,7 @@ module.exports = grammar({
- using_statement: ($) =>
- seq(
- ci("Using"),
- - field("resource", choice($.variable_declarator, $._expression)),
- + commaSep1(field("resource", choice($.variable_declarator, $._expression))),
- $._block_terminator,
- field("body", repeat($._statement)),
- ci("End"),
- @@ -1590,14 +1757,25 @@ module.exports = grammar({
- $._terminator
- ), // LINQ Query expressions
- query_expression: ($) =>
- - seq($.from_clause, repeat($.query_body_clause), $.select_or_group_clause),
- - from_clause: ($) => seq(ci("From"), commaSep1($.collection_range_variable)),
- + prec.right(
- + choice(
- + seq(
- + $.from_clause,
- + repeat(seq(optional($._query_clause_continuation), $.query_body_clause)),
- + optional(seq(optional($._query_clause_continuation), $.select_or_group_clause))
- + ),
- + $.aggregate_clause
- + )
- + ),
- + from_clause: ($) => prec.right(seq(ci("From"), commaSep1($.collection_range_variable))),
- collection_range_variable: ($) =>
- - seq(
- - field("variable", $.identifier),
- - optional($.as_clause),
- - ci("In"),
- - field("collection", $._expression)
- + prec.right(
- + seq(
- + field("variable", $.identifier),
- + optional($.as_clause),
- + ci("In"),
- + field("collection", $._expression)
- + )
- ),
- query_body_clause: ($) =>
- choice(
- @@ -1606,48 +1784,62 @@ module.exports = grammar({
- $.where_clause,
- $.join_clause,
- $.order_by_clause,
- - $.aggregate_clause
- - ),
- - let_clause: ($) => seq(ci("Let"), commaSep1($.expression_range_variable)),
- + $.aggregate_clause,
- + $.distinct_clause,
- + $.skip_take_clause
- + ),
- + distinct_clause: ($) => ci("Distinct"),
- + skip_take_clause: ($) =>
- + prec.right(seq(choice(ci("Skip"), ci("Take")), optional(ci("While")), $._expression)),
- + let_clause: ($) => prec.right(seq(ci("Let"), commaSep1($.expression_range_variable))),
- expression_range_variable: ($) =>
- - seq(
- + prec.right(seq(
- field("variable", $.identifier),
- "=",
- field("expression", $._expression)
- - ),
- - where_clause: ($) => seq(ci("Where"), field("condition", $._expression)),
- + )),
- + where_clause: ($) =>
- + prec.right(seq(ci("Where"), field("condition", $._expression))),
- join_clause: ($) =>
- - seq(
- - ci("Join"),
- - $.collection_range_variable,
- - ci("On"),
- - commaSep1($.join_condition)
- + prec.right(
- + seq(
- + ci("Join"),
- + $.collection_range_variable,
- + optional($._query_clause_continuation),
- + ci("On"),
- + commaSep1($.join_condition)
- + )
- ),
- join_condition: ($) =>
- - seq(
- + prec.right(seq(
- field("left", $._expression),
- ci("Equals"),
- field("right", $._expression)
- - ),
- - order_by_clause: ($) => seq(ci("Order"), ci("By"), commaSep1($.ordering)),
- + )),
- + order_by_clause: ($) => prec.right(seq(ci("Order"), ci("By"), commaSep1($.ordering))),
- ordering: ($) =>
- - seq(
- - field("expression", $._expression),
- - optional(choice(ci("Ascending"), ci("Descending")))
- + prec.right(
- + seq(
- + field("expression", $._expression),
- + optional(choice(ci("Ascending"), ci("Descending")))
- + )
- ),
- aggregate_clause: ($) =>
- - seq(
- - ci("Aggregate"),
- - $.collection_range_variable,
- - repeat($.query_body_clause),
- - ci("Into"),
- - commaSep1($.aggregate_element)
- + prec.right(
- + seq(
- + ci("Aggregate"),
- + $.collection_range_variable,
- + repeat(seq(optional($._query_clause_continuation), $.query_body_clause)),
- + optional($._query_clause_continuation),
- + ci("Into"),
- + commaSep1($.aggregate_element)
- + )
- ),
- aggregate_element: ($) =>
- - seq(
- + prec.right(seq(
- optional(seq(field("name", $.identifier), "=")),
- field("function", $.aggregate_function)
- - ),
- + )),
- aggregate_function: ($) =>
- seq(
- field(
- @@ -1668,42 +1860,44 @@ module.exports = grammar({
- select_or_group_clause: ($) => choice($.select_clause, $.group_by_clause),
- select_clause: ($) => seq(ci("Select"), commaSep1($.select_element)),
- select_element: ($) =>
- - choice(
- + prec.right(choice(
- $._expression,
- seq(
- field("name", $.identifier),
- "=",
- field("expression", $._expression)
- )
- - ),
- + )),
- group_by_clause: ($) =>
- - seq(
- - ci("Group"),
- - commaSep1($.group_element),
- - ci("By"),
- - commaSep1($.by_element),
- - ci("Into"),
- - commaSep1($.into_element)
- + prec.right(
- + seq(
- + ci("Group"),
- + commaSep1($.group_element),
- + ci("By"),
- + commaSep1($.by_element),
- + ci("Into"),
- + commaSep1($.into_element)
- + )
- ),
- group_element: ($) =>
- - choice(
- + prec.right(choice(
- $._expression,
- seq(
- field("name", $.identifier),
- "=",
- field("expression", $._expression)
- )
- - ),
- + )),
- by_element: ($) =>
- - choice(
- + prec.right(choice(
- $._expression,
- seq(
- field("name", $.identifier),
- "=",
- field("expression", $._expression)
- )
- - ),
- - into_element: ($) => choice($.identifier, $.aggregate_element),
- + )),
- + into_element: ($) => prec.right(choice($.identifier, $.aggregate_element)),
-
- // Comments
- comment: ($) => token(prec(100, choice(
- @@ -1714,7 +1908,7 @@ module.exports = grammar({
- ))),
-
- // Preprocessor Directives
- - preprocessor_directive: ($) => token(seq("#", /[^\r\n]*/)),
- + preprocessor_directive: ($) => token(seq("#", /[ \t]*[A-Za-z][^\r\n]*/)),
- },
- });
-
- diff --git a/src/scanner.c b/src/scanner.c
- new file mode 100644
- index 0000000..8334fdb
- --- /dev/null
- +++ b/src/scanner.c
- @@ -0,0 +1,303 @@
- +#include "tree_sitter/parser.h"
- +#include <string.h>
- +#include <wctype.h>
- +
- +// External tokens for the two constructs that are not LR(1)-parseable with
- +// tree-sitter's newline-as-extra treatment:
- +//
- +// 1. QUERY_CLAUSE_CONTINUATION — a newline run that CONTINUES a LINQ query
- +// (`From x In xs` ↵ `Where …`). At a clause boundary the parser cannot
- +// know from the newline alone whether the query ends (newline = statement
- +// terminator) or continues (newline = insignificant, next line starts with
- +// a query keyword). The scanner looks past the newline at the next word
- +// and only emits the token when it is a query-clause keyword — so the
- +// terminator/continuation choice is made by the lexer, not the LR table.
- +//
- +// 2. XML_LITERAL — a whole VB XML literal (`<Tags><Tag/></Tags>`, including
- +// `<%= expr %>` embedded expressions, comments, CDATA) consumed as one
- +// opaque token. Only valid where a literal can begin an expression, so a
- +// relational `<` (which always FOLLOWS an expression) can never collide.
- +
- +enum TokenType {
- + QUERY_CLAUSE_CONTINUATION,
- + XML_LITERAL,
- +};
- +
- +void *tree_sitter_vbnet_external_scanner_create(void) { return NULL; }
- +void tree_sitter_vbnet_external_scanner_destroy(void *payload) { (void)payload; }
- +unsigned tree_sitter_vbnet_external_scanner_serialize(void *payload, char *buffer) {
- + (void)payload; (void)buffer;
- + return 0; // stateless
- +}
- +void tree_sitter_vbnet_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
- + (void)payload; (void)buffer; (void)length;
- +}
- +
- +static inline void advance(TSLexer *lexer) { lexer->advance(lexer, false); }
- +static inline void skip_ws(TSLexer *lexer) { lexer->advance(lexer, true); }
- +
- +// Read one alphabetic word (advancing past it), lowercased into buf.
- +// Returns its length (0 if the next char is not a letter).
- +static int read_word(TSLexer *lexer, char *buf, int cap) {
- + int n = 0;
- + while (iswalpha((wint_t)lexer->lookahead)) {
- + if (n < cap - 1) buf[n] = (char)towlower((wint_t)lexer->lookahead);
- + n++;
- + advance(lexer);
- + }
- + buf[n < cap - 1 ? n : cap - 1] = 0;
- + return n;
- +}
- +
- +static bool is_query_keyword(const char *w) {
- + static const char *kws[] = {
- + "where", "select", "order", "group", "join", "let", "skip",
- + "take", "distinct", "aggregate", "from", "into", "on", NULL,
- + };
- + for (int i = 0; kws[i]; i++)
- + if (strcmp(w, kws[i]) == 0) return true;
- + return false;
- +}
- +
- +// [ \t\r]* '\n' [ \t\r\n]* followed by a query-clause keyword.
- +// The token covers only the whitespace/newline run (mark_end before the
- +// keyword lookahead), so the clause keyword itself lexes normally after it.
- +static bool scan_query_continuation(TSLexer *lexer) {
- + bool saw_newline = false;
- + for (;;) {
- + int32_t c = lexer->lookahead;
- + if (c == ' ' || c == '\t' || c == '\r') {
- + advance(lexer);
- + } else if (c == '\n') {
- + saw_newline = true;
- + advance(lexer);
- + } else {
- + break;
- + }
- + }
- + if (!saw_newline) return false;
- + lexer->mark_end(lexer);
- +
- + char w[12];
- + int n = read_word(lexer, w, sizeof w);
- + if (n == 0 || n >= (int)(sizeof w)) return false;
- + if (!is_query_keyword(w)) return false;
- +
- + // `Select Case` opens a statement, never a select clause.
- + if (strcmp(w, "select") == 0) {
- + while (lexer->lookahead == ' ' || lexer->lookahead == '\t') advance(lexer);
- + char w2[8];
- + int m = read_word(lexer, w2, sizeof w2);
- + if (m > 0 && m < (int)(sizeof w2) && strcmp(w2, "case") == 0) return false;
- + }
- +
- + lexer->result_symbol = QUERY_CLAUSE_CONTINUATION;
- + return true;
- +}
- +
- +// Consume a VB string inside an embedded `<%= … %>` region ("" escapes).
- +static void consume_vb_string(TSLexer *lexer) {
- + advance(lexer); // opening quote
- + for (;;) {
- + if (lexer->lookahead == 0) return;
- + if (lexer->lookahead == '"') {
- + advance(lexer);
- + if (lexer->lookahead != '"') return; // closing (not an escaped "")
- + // escaped quote: fall through, keep consuming
- + }
- + advance(lexer);
- + }
- +}
- +
- +// Consume `<%= … %>` starting at the '%' (the '<' is already consumed).
- +// Embedded expressions NEST (`<%= From t In ts Select <Tag><%= t.Name %></Tag> %>`,
- +// the staxrip WriteTagfile shape), so track <% / %> depth.
- +static bool consume_embedded_expression(TSLexer *lexer) {
- + advance(lexer); // '%'
- + int depth = 1;
- + for (;;) {
- + int32_t c = lexer->lookahead;
- + if (c == 0) return false;
- + if (c == '"') { consume_vb_string(lexer); continue; }
- + if (c == '<') {
- + advance(lexer);
- + if (lexer->lookahead == '%') { depth++; advance(lexer); }
- + continue;
- + }
- + if (c == '%') {
- + advance(lexer);
- + if (lexer->lookahead == '>') {
- + advance(lexer);
- + if (--depth == 0) return true;
- + }
- + continue;
- + }
- + advance(lexer);
- + }
- +}
- +
- +// Consume `<!-- … -->` / `<![CDATA[ … ]]>` / `<!DOCTYPE …>` starting at '!'.
- +static bool consume_bang_construct(TSLexer *lexer) {
- + advance(lexer); // '!'
- + if (lexer->lookahead == '-') {
- + // comment: to -->
- + int dashes = 0;
- + for (;;) {
- + int32_t c = lexer->lookahead;
- + if (c == 0) return false;
- + if (c == '-') { dashes++; advance(lexer); continue; }
- + if (c == '>' && dashes >= 2) { advance(lexer); return true; }
- + dashes = 0;
- + advance(lexer);
- + }
- + }
- + if (lexer->lookahead == '[') {
- + // CDATA: to ]]>
- + int brackets = 0;
- + for (;;) {
- + int32_t c = lexer->lookahead;
- + if (c == 0) return false;
- + if (c == ']') { brackets++; advance(lexer); continue; }
- + if (c == '>' && brackets >= 2) { advance(lexer); return true; }
- + brackets = 0;
- + advance(lexer);
- + }
- + }
- + // DOCTYPE-ish: to bare >
- + for (;;) {
- + int32_t c = lexer->lookahead;
- + if (c == 0) return false;
- + if (c == '>') { advance(lexer); return true; }
- + advance(lexer);
- + }
- +}
- +
- +// Consume `<? … ?>` starting at the '?'.
- +static bool consume_processing_instruction(TSLexer *lexer) {
- + advance(lexer); // '?'
- + for (;;) {
- + int32_t c = lexer->lookahead;
- + if (c == 0) return false;
- + if (c == '?') {
- + advance(lexer);
- + if (lexer->lookahead == '>') { advance(lexer); return true; }
- + continue;
- + }
- + advance(lexer);
- + }
- +}
- +
- +static bool is_name_start(int32_t c) {
- + return iswalpha((wint_t)c) || c == '_';
- +}
- +
- +static bool scan_xml_literal(TSLexer *lexer) {
- + // Only same-line blanks are skipped: a leading newline must stay unconsumed
- + // so it can serve as a statement/block terminator (a successful scan would
- + // otherwise swallow it as trivia). XML on a continuation line still works:
- + // the newline is consumed as an extra first, then the scanner re-runs.
- + while (lexer->lookahead == ' ' || lexer->lookahead == '\t') skip_ws(lexer);
- + if (lexer->lookahead != '<') return false;
- + advance(lexer);
- + // Only element-start markup opens an XML literal here; comments/PIs as the
- + // outermost construct (`Dim d = <?xml …`) are rare enough to leave alone,
- + // and a bare `<` (comparison) never begins an expression.
- + if (!is_name_start(lexer->lookahead)) return false;
- +
- + int depth = 0; // open (unclosed) elements
- + bool in_tag = true; // inside <...> of an element tag
- + bool closing = false;
- + int32_t quote = 0;
- +
- + for (;;) {
- + int32_t c = lexer->lookahead;
- + if (c == 0) return false; // unterminated: let the normal parser error
- +
- + if (in_tag) {
- + if (quote) {
- + if (c == quote) quote = 0;
- + advance(lexer);
- + continue;
- + }
- + if (c == '"' || c == '\'') { quote = c; advance(lexer); continue; }
- + if (c == '<') {
- + advance(lexer);
- + if (lexer->lookahead == '%') {
- + // attribute value embedded expression: attr=<%= x %>
- + if (!consume_embedded_expression(lexer)) return false;
- + continue;
- + }
- + continue; // stray < in a tag: malformed, keep consuming
- + }
- + if (c == '/') {
- + advance(lexer);
- + if (lexer->lookahead == '>') {
- + // self-closing tag
- + advance(lexer);
- + in_tag = false;
- + if (depth == 0) break; // single self-closed root: done
- + continue;
- + }
- + continue;
- + }
- + if (c == '>') {
- + advance(lexer);
- + if (closing) {
- + depth--;
- + if (depth <= 0) break; // root element closed: done
- + } else {
- + depth++;
- + }
- + in_tag = false;
- + continue;
- + }
- + advance(lexer);
- + continue;
- + }
- +
- + // text content between tags
- + if (c == '<') {
- + advance(lexer);
- + int32_t d = lexer->lookahead;
- + if (d == '/') { advance(lexer); closing = true; in_tag = true; continue; }
- + if (d == '%') {
- + if (!consume_embedded_expression(lexer)) return false;
- + continue;
- + }
- + if (d == '!') {
- + if (!consume_bang_construct(lexer)) return false;
- + continue;
- + }
- + if (d == '?') {
- + if (!consume_processing_instruction(lexer)) return false;
- + continue;
- + }
- + closing = false;
- + in_tag = true; // opening tag
- + continue;
- + }
- + advance(lexer);
- + }
- +
- + lexer->mark_end(lexer);
- + lexer->result_symbol = XML_LITERAL;
- + return true;
- +}
- +
- +bool tree_sitter_vbnet_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) {
- + (void)payload;
- + int32_t c = lexer->lookahead;
- + bool ws = (c == ' ' || c == '\t' || c == '\n' || c == '\r');
- +
- + // A scan attempt advances the lexer, so exactly ONE attempt runs per
- + // invocation — never chain a second attempt after a failed first (its
- + // reads would start mid-stream). The leading character picks the branch;
- + // a false return discards the attempt entirely.
- + if (valid_symbols[QUERY_CLAUSE_CONTINUATION] && ws) {
- + return scan_query_continuation(lexer);
- + }
- + if (valid_symbols[XML_LITERAL] && (c == '<' || ws)) {
- + return scan_xml_literal(lexer);
- + }
- + return false;
- +}
|