Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 10 additions & 14 deletions grammar.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export default grammar({
[$.between_expression, $.binary_expression],
[$.time],
[$.timestamp],
[$.statement, $._tsql_function_body_statement],
[$.return_statement, $._function_return],
[$.var_declaration, $.function_declaration],
],

precedences: $ => [
Expand All @@ -54,21 +57,14 @@ export default grammar({
word: $ => $._identifier,

rules: {
program: $ => seq(
// any number of transactions, statements, or blocks with a terminating ;
repeat(
seq(
choice(
$.transaction,
$.statement,
$.block,
),
';',
program: $ => repeat(
seq(
choice(
$.statement,
$.block,

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

program no longer includes the transaction rule (it now only allows statement, block, or GO). Since the repository still has test/corpus/transaction.txt asserting a (transaction ...) node, this change will break existing corpus tests unless the transaction corpus (and any dependent queries) are updated accordingly or the transaction rule is reintroduced.

Suggested change
$.block,
$.block,
$.transaction,

Copilot uses AI. Check for mistakes.
$.keyword_go,
),
),
// optionally, a single statement without a terminating ;
optional(
$.statement,
optional(';'),
),
),

Expand Down
109 changes: 56 additions & 53 deletions grammar/expressions.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,55 @@ export default {
$.interval,
$.between_expression,
$.parenthesized_expression,
$.object_id,
)
),

object_reference: $ => choice(
seq(
field('database', $.identifier),
'.',
field('schema', $.identifier),
'.',
field('name', $.identifier),
),
seq(
field('schema', $.identifier),
'.',
field('name', $.identifier),
),
object_reference: $ => choice(
seq(
field('server', $.identifier),
'.',
field('database', $.identifier),
'.',
field('schema', $.identifier),
'.',
field('name', $.identifier),
),
seq(
field('database', $.identifier),
'.',
field('schema', $.identifier),
'.',
field('name', $.identifier),
),
seq(
field('database', $.identifier),
'..',
field('name', $.identifier),
),
seq(
field('schema', $.identifier),
'.',
field('name', $.identifier),
),
field('name', $.identifier),
),

field: $ => field('name', $.identifier),
field: $ => field('name', $.identifier),

_qualified_field: $ => seq(
optional(
seq(
optional_parenthesis($.object_reference),
'.',
),
_qualified_field: $ => seq(
optional(
seq(
optional_parenthesis($.object_reference),
'.',
),
field('name', $.identifier),
),
field('name', $.identifier),
),

parameter: $ => /\?|(\$[0-9]+)/,
parameter: $ => choice(
/\?|(\$[0-9]+)/,
$._tsql_parameter,
),

case: $ => seq(
$.keyword_case,
Expand Down Expand Up @@ -171,7 +187,7 @@ export default {
),
),

filter_expression : $ => seq(
filter_expression: $ => seq(
$.keyword_filter,
wrapped_in_parenthesis($.where),
),
Expand Down Expand Up @@ -330,23 +346,23 @@ export default {

// Postgres syntax for intervals
interval: $ => seq(
$.keyword_interval,
$._literal_string,
$.keyword_interval,
$._literal_string,
),

between_expression: $ => choice(
...[
[$.keyword_between, 'between'],
[seq($.keyword_not, $.keyword_between), 'between'],
].map(([operator, precedence]) =>
prec.left(precedence, seq(
field('left', $._expression),
field('operator', operator),
field('low', $._expression),
$.keyword_and,
field('high', $._expression)
))
),
[$.keyword_between, 'between'],
[seq($.keyword_not, $.keyword_between), 'between'],
].map(([operator, precedence]) =>
prec.left(precedence, seq(
field('left', $._expression),
field('operator', operator),
field('low', $._expression),
$.keyword_and,
field('high', $._expression)
))
),
),

not_in: $ => seq(
Expand Down Expand Up @@ -409,26 +425,13 @@ export default {
$._identifier,
$._double_quote_string,
$._backtick_quoted_string,
$._tsql_parameter,
seq("`", $._identifier, "`"),
$._tsql_bracket_identifier,
),
_tsql_parameter: $ => seq('@', $._identifier),
// support nordic chars and umlaue
_identifier: _ => /[A-Za-z_\u00C0-\u017F][0-9A-Za-z_\u00C0-\u017F]*/,

object_id: $ => seq(
$.keyword_object_id,
wrapped_in_parenthesis(
seq(
alias($._literal_string, $.literal),
optional(
seq(
',',
alias($._literal_string, $.literal),
),
),
),
),
),
_tsql_bracket_identifier: _ => /\[[^\]]*\]/,
_tsql_parameter: _ => /@[A-Za-z_0-9]*/,

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_tsql_parameter currently matches @ by itself (because of *) and also allows names starting with digits. That will accept invalid T-SQL and can create ambiguous parses. Tighten the regex to require at least one identifier character after @ and (ideally) enforce a valid starting character, e.g. @[A-Za-z_][A-Za-z_0-9]*.

Suggested change
_tsql_parameter: _ => /@[A-Za-z_0-9]*/,
_tsql_parameter: _ => /@[_A-Za-z\u00C0-\u017F][0-9A-Za-z_\u00C0-\u017F]*/,

Copilot uses AI. Check for mistakes.

};
33 changes: 20 additions & 13 deletions grammar/keywords.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ export default {
keyword_hash: _ => make_keyword("hash"),
keyword_gist: _ => make_keyword("gist"),
keyword_spgist: _ => make_keyword("spgist"),
keyword_gin: _ => make_keyword("gin"),
keyword_gin: _ => make_keyword("gin"),
keyword_brin: _ => make_keyword("brin"),
keyword_like: _ => choice(make_keyword("like"),make_keyword("ilike")),
keyword_like: _ => choice(make_keyword("like"), make_keyword("ilike")),
keyword_similar: _ => make_keyword("similar"),
keyword_unsigned: _ => make_keyword("unsigned"),
keyword_zerofill: _ => make_keyword("zerofill"),
Expand Down Expand Up @@ -244,7 +244,6 @@ export default {
keyword_invoker: _ => make_keyword("invoker"),
keyword_security: _ => make_keyword("security"),
keyword_version: _ => make_keyword("version"),
keyword_extension: _ => make_keyword("extension"),
keyword_out: _ => make_keyword("out"),

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property is duplicated in a later property.

Suggested change
keyword_out: _ => make_keyword("out"),

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remobe duplicate

keyword_inout: _ => make_keyword("inout"),
keyword_variadic: _ => make_keyword("variadic"),
Expand All @@ -264,7 +263,7 @@ export default {
keyword_zone: _ => make_keyword("zone"),
keyword_immediate: _ => make_keyword("immediate"),
keyword_deferred: _ => make_keyword("deferred"),
keyword_constraints : _ => make_keyword("constraints"),
keyword_constraints: _ => make_keyword("constraints"),
keyword_snapshot: _ => make_keyword("snapshot"),
keyword_characteristics: _ => make_keyword("characteristics"),
keyword_follows: _ => make_keyword("follows"),
Expand All @@ -279,7 +278,15 @@ export default {
keyword_statement: _ => make_keyword("statement"),
keyword_execute: _ => make_keyword("execute"),
keyword_procedure: _ => make_keyword("procedure"),
keyword_object_id: _ => make_keyword("object_id"),
keyword_proc: _ => make_keyword("proc"),
keyword_go: _ => make_keyword("go"),
keyword_nocount: _ => make_keyword("nocount"),

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keyword_object_id appears to have been removed, but test/corpus/expressions.txt and queries/highlights.scm still reference (keyword_object_id) / object_id. Either reintroduce the keyword (and corresponding object_id expression rule) or update those tests/queries to match the new intended representation.

Suggested change
keyword_nocount: _ => make_keyword("nocount"),
keyword_nocount: _ => make_keyword("nocount"),
keyword_object_id: _ => make_keyword("object_id"),

Copilot uses AI. Check for mistakes.
keyword_print: _ => make_keyword("print"),
keyword_raiserror: _ => make_keyword("raiserror"),
keyword_goto: _ => make_keyword("goto"),
keyword_exec: _ => make_keyword("exec"),
keyword_out: _ => make_keyword("out"),

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keyword_out is defined twice in this file (once earlier and again here). Even though the definitions are identical, the duplicate key is easy to miss and can cause confusion during future edits; remove one of them to keep the keyword list canonical.

Suggested change
keyword_out: _ => make_keyword("out"),

Copilot uses AI. Check for mistakes.
keyword_output: _ => make_keyword("output"),

// Hive Keywords
keyword_external: _ => make_keyword("external"),
Expand Down Expand Up @@ -356,17 +363,17 @@ export default {
keyword_varbinary: _ => make_keyword("varbinary"),
keyword_image: _ => make_keyword("image"),

keyword_smallserial: _ => choice(make_keyword("smallserial"),make_keyword("serial2")),
keyword_serial: _ => choice(make_keyword("serial"),make_keyword("serial4")),
keyword_bigserial: _ => choice(make_keyword("bigserial"),make_keyword("serial8")),
keyword_tinyint: _ => choice(make_keyword("tinyint"),make_keyword("int1")),
keyword_smallint: _ => choice(make_keyword("smallint"),make_keyword("int2")),
keyword_mediumint: _ => choice(make_keyword("mediumint"),make_keyword("int3")),
keyword_smallserial: _ => choice(make_keyword("smallserial"), make_keyword("serial2")),
keyword_serial: _ => choice(make_keyword("serial"), make_keyword("serial4")),
keyword_bigserial: _ => choice(make_keyword("bigserial"), make_keyword("serial8")),
keyword_tinyint: _ => choice(make_keyword("tinyint"), make_keyword("int1")),
keyword_smallint: _ => choice(make_keyword("smallint"), make_keyword("int2")),
keyword_mediumint: _ => choice(make_keyword("mediumint"), make_keyword("int3")),
keyword_int: _ => choice(make_keyword("int"), make_keyword("integer"), make_keyword("int4")),
keyword_bigint: _ => choice(make_keyword("bigint"),make_keyword("int8")),
keyword_bigint: _ => choice(make_keyword("bigint"), make_keyword("int8")),
keyword_decimal: _ => make_keyword("decimal"),
keyword_numeric: _ => make_keyword("numeric"),
keyword_real: _ => choice(make_keyword("real"),make_keyword("float4")),
keyword_real: _ => choice(make_keyword("real"), make_keyword("float4")),
keyword_float: _ => make_keyword("float"),
keyword_double: _ => make_keyword("double"),
keyword_precision: _ => make_keyword("precision"),
Expand Down
12 changes: 6 additions & 6 deletions grammar/statements/create-function.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ export default {
false,
),

_function_return: $ => seq(
_function_return: $ => prec(2, seq(
$.keyword_return,
$._expression,
),
)),

function_declaration: $ => seq(
function_declaration: $ => prec(2, seq(
$.identifier,
$._type,
optional(
Expand All @@ -96,14 +96,14 @@ export default {
),
),
';',
),
)),

_function_body_statement: $ => choice(
$.statement,
$._function_return,
),

_tsql_function_body_statement: $ => seq(
_tsql_function_body_statement: $ => prec(1, seq(
optional($.keyword_as),
$.keyword_begin,
optional($.var_declarations),
Expand All @@ -117,7 +117,7 @@ export default {
),
$._function_return,
$.keyword_end,
),
)),

function_body: $ => choice(
seq(
Expand Down
Loading
Loading