Skip to content

Commit a331f41

Browse files
so far
1 parent feced68 commit a331f41

File tree

7 files changed

+237
-66
lines changed

7 files changed

+237
-66
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,8 @@ pgt_workspace_macros = { path = "./crates/pgt_workspace_macros", version =
9696
pgt_test_macros = { path = "./crates/pgt_test_macros" }
9797
pgt_test_utils = { path = "./crates/pgt_test_utils" }
9898

99+
[workspace.dev-dependencies]
100+
pgt_test_utils = { path = "./crates/pgt_test_utils", version = "0.0.0" }
101+
99102
[profile.dev.package]
100103
insta.opt-level = 3
Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use clap::*;
2+
use pgt_test_utils::print_ts_tree;
23

34
#[derive(Parser)]
45
#[command(
@@ -25,30 +26,8 @@ fn main() {
2526
.parse(query.clone(), None)
2627
.expect("Failed to parse query.");
2728

28-
print_tree(&tree.root_node(), &query, 0);
29-
}
29+
let mut result = String::new();
30+
print_ts_tree(&tree.root_node(), &query, 0, &mut result);
3031

31-
fn print_tree(node: &tree_sitter::Node, source: &str, level: usize) {
32-
let indent = " ".repeat(level);
33-
34-
let node_text = node
35-
.utf8_text(source.as_bytes())
36-
.unwrap_or("NO_NAME")
37-
.split_whitespace()
38-
.collect::<Vec<&str>>()
39-
.join(" ");
40-
41-
println!(
42-
"{}{} [{}..{}] '{}'",
43-
indent,
44-
node.kind(),
45-
node.start_position().column,
46-
node.end_position().column,
47-
node_text
48-
);
49-
50-
let mut cursor = node.walk();
51-
for child in node.children(&mut cursor) {
52-
print_tree(&child, source, level + 1);
53-
}
32+
print!("{}", result)
5433
}

crates/pgt_test_utils/src/lib.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,34 @@ impl Display for QueryWithCursorPosition {
4545
}
4646
}
4747

48+
pub fn print_ts_tree(node: &tree_sitter::Node, source: &str, level: usize, result: &mut String) {
49+
let indent = " ".repeat(level);
50+
51+
let node_text = node
52+
.utf8_text(source.as_bytes())
53+
.unwrap_or("NO_NAME")
54+
.split_whitespace()
55+
.collect::<Vec<&str>>()
56+
.join(" ");
57+
58+
result.push_str(
59+
format!(
60+
"{}{} [{}..{}] '{}'\n",
61+
indent,
62+
node.kind(),
63+
node.start_position().column,
64+
node.end_position().column,
65+
node_text
66+
)
67+
.as_str(),
68+
);
69+
70+
let mut cursor = node.walk();
71+
for child in node.children(&mut cursor) {
72+
print_ts_tree(&child, source, level + 1, result);
73+
}
74+
}
75+
4876
#[cfg(test)]
4977
mod tests {
5078

crates/pgt_treesitter_grammar/Cargo.toml

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pgt_treesitter_grammar/grammar.js

Lines changed: 94 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@ module.exports = grammar({
2121
],
2222

2323
conflicts: ($) => [
24-
[$.all_fields, $.field_qualifier],
25-
[$.object_reference, $._qualified_field],
2624
[$.object_reference],
2725
[$.between_expression, $.binary_expression],
2826
[$.time],
2927
[$.timestamp],
3028
[$.grantable_on_function, $.grantable_on_table],
3129
[$.any_identifier, $.column_identifier],
30+
[$.any_identifier, $.schema_identifier, $.table_identifier],
31+
[$.schema_identifier, $.table_identifier],
32+
[$.table_reference, $.column_reference],
3233
],
3334

3435
precedences: ($) => [
@@ -873,7 +874,7 @@ module.exports = grammar({
873874
// TODO: aggregate
874875
$.cast,
875876
// TODO: collation
876-
seq($.keyword_column, alias($._qualified_field, $.object_reference)),
877+
seq($.keyword_column, $.column_reference),
877878
// TODO: constraint (on domain)
878879
// TODO: conversion
879880
seq($.keyword_database, $.any_identifier),
@@ -1557,7 +1558,7 @@ module.exports = grammar({
15571558
seq(
15581559
$.keyword_owned,
15591560
$.keyword_by,
1560-
choice($.keyword_none, $.object_reference)
1561+
choice($.keyword_none, $.column_reference)
15611562
)
15621563
)
15631564
)
@@ -1993,7 +1994,7 @@ module.exports = grammar({
19931994
seq(
19941995
$.keyword_owned,
19951996
$.keyword_by,
1996-
choice($.keyword_none, $.object_reference)
1997+
choice($.keyword_none, $.column_reference)
19971998
)
19981999
)
19992000
),
@@ -2158,8 +2159,7 @@ module.exports = grammar({
21582159
optional($.keyword_concurrently),
21592160
optional($._if_exists),
21602161
field("name", $.any_identifier),
2161-
optional($._drop_behavior),
2162-
optional(seq($.keyword_on, $.object_reference))
2162+
optional($._drop_behavior)
21632163
),
21642164

21652165
drop_extension: ($) =>
@@ -2200,23 +2200,6 @@ module.exports = grammar({
22002200
)
22012201
),
22022202

2203-
object_reference: ($) =>
2204-
choice(
2205-
seq(
2206-
field("database", $.any_identifier),
2207-
".",
2208-
field("schema", $.any_identifier),
2209-
".",
2210-
field("name", $.any_identifier)
2211-
),
2212-
seq(
2213-
field("schema", $.any_identifier),
2214-
".",
2215-
field("name", $.any_identifier)
2216-
),
2217-
field("name", $.any_identifier)
2218-
),
2219-
22202203
_copy_statement: ($) =>
22212204
seq(
22222205
$.keyword_copy,
@@ -2305,12 +2288,15 @@ module.exports = grammar({
23052288
seq(
23062289
$.keyword_on,
23072290
$.keyword_conflict,
2308-
// todo: conflict target
2309-
seq(
2310-
$.keyword_do,
2311-
choice(
2312-
$.keyword_nothing,
2313-
seq($.keyword_update, $._set_values, optional($.where))
2291+
// todo(@juleswritescode): support column identifiers in conflict_target
2292+
unknown_until(
2293+
$,
2294+
seq(
2295+
$.keyword_do,
2296+
choice(
2297+
$.keyword_nothing,
2298+
seq($.keyword_update, $._set_values, optional($.where))
2299+
)
23142300
)
23152301
)
23162302
),
@@ -2596,7 +2582,7 @@ module.exports = grammar({
25962582

25972583
assignment: ($) =>
25982584
seq(
2599-
field("left", alias($._qualified_field, $.field)),
2585+
field("left", $.column_reference),
26002586
"=",
26012587
field("right", $._expression)
26022588
),
@@ -2776,7 +2762,7 @@ module.exports = grammar({
27762762

27772763
ordered_column: ($) => seq(field("name", $._column), optional($.direction)),
27782764

2779-
all_fields: ($) => seq(optional(seq($.object_reference, ".")), "*"),
2765+
all_fields: ($) => seq(optional(seq($.table_reference, ".")), "*"),
27802766

27812767
parameter: ($) => /\?|(\$[0-9]+)/,
27822768

@@ -2812,12 +2798,6 @@ module.exports = grammar({
28122798

28132799
field: ($) => field("name", $.column_identifier),
28142800

2815-
_qualified_field: ($) =>
2816-
seq(optional($.field_qualifier), $.column_identifier),
2817-
2818-
field_qualifier: ($) =>
2819-
seq(prec.left(optional_parenthesis($.object_reference)), "."),
2820-
28212801
implicit_cast: ($) => seq($._expression, "::", $.type),
28222802

28232803
// Postgres syntax for intervals
@@ -3241,7 +3221,7 @@ module.exports = grammar({
32413221
1,
32423222
choice(
32433223
$.literal,
3244-
alias($._qualified_field, $.field),
3224+
$.column_reference,
32453225
$.parameter,
32463226
$.list,
32473227
$.case,
@@ -3506,8 +3486,65 @@ module.exports = grammar({
35063486

35073487
bang: (_) => "!",
35083488

3489+
// todo: handle (table).col vs. (type).attribute
3490+
// todo: handle "schema"."table".column etc.
3491+
// todo: handle alias.col vs. table.col
3492+
// todo: handle table.column::type
3493+
// todo: handle schema.function(arg1, arg2)
3494+
// function_reference: $ => {},
3495+
3496+
// table_reference: $ => {},
3497+
// type_reference: $ => {},
3498+
// column_reference: $ => {},
3499+
3500+
object_reference: ($) =>
3501+
choice(
3502+
seq(
3503+
field("first", $.any_identifier),
3504+
".",
3505+
field("second", $.any_identifier),
3506+
".",
3507+
field("third", $.any_identifier)
3508+
),
3509+
seq(
3510+
field("first", $.any_identifier),
3511+
".",
3512+
field("second", $.any_identifier)
3513+
),
3514+
field("first", $.any_identifier)
3515+
),
3516+
3517+
type_reference: ($) =>
3518+
choice(
3519+
seq($.schema_identifier, ".", $.type_identifier),
3520+
field("first", $.type_identifier)
3521+
),
3522+
3523+
table_reference: ($) =>
3524+
choice(
3525+
seq($.schema_identifier, ".", $.table_identifier),
3526+
field("first", $.table_identifier)
3527+
),
3528+
3529+
column_reference: ($) =>
3530+
choice(
3531+
seq(
3532+
$.schema_identifier,
3533+
".",
3534+
$.table_identifier,
3535+
".",
3536+
$.column_identifier
3537+
),
3538+
seq($.table_identifier, ".", field("second", $.column_identifier)),
3539+
field("first", $.column_identifier)
3540+
),
3541+
35093542
any_identifier: ($) => $._any_identifier,
35103543
column_identifier: ($) => $._any_identifier,
3544+
schema_identifier: ($) => $._any_identifier,
3545+
table_identifier: ($) => $._any_identifier,
3546+
function_identifier: ($) => $._any_identifier,
3547+
type_identifier: ($) => $._any_identifier,
35113548

35123549
_any_identifier: ($) =>
35133550
choice(
@@ -3516,8 +3553,10 @@ module.exports = grammar({
35163553
$._sql_parameter,
35173554
seq("`", $._identifier, "`")
35183555
),
3519-
_sql_parameter: (_) => /[:$@?][a-zA-Z_][0-9a-zA-Z_]*/,
3520-
_identifier: (_) => /[a-zA-Z_][0-9a-zA-Z_]*/,
3556+
_sql_parameter: (_) => /[:$@?][a-zA-Z_][0-9a-zA-Z_]+/,
3557+
_identifier: (_) => /[a-zA-Z_][0-9a-zA-Z_]+/,
3558+
3559+
_anything: (_) => /\S+/,
35213560
},
35223561
});
35233562

@@ -3633,3 +3672,17 @@ function make_keyword(word) {
36333672
}
36343673
return new RegExp(str);
36353674
}
3675+
3676+
/**
3677+
* @param {RuleRecord} $
3678+
* @param {Rule} rule
3679+
* @param {number} [maxLength]
3680+
* @returns {PrecLeftRule}
3681+
*/
3682+
function unknown_until($, rule, maxLength) {
3683+
const unknowns = maxLength
3684+
? seq(...Array.from({ length: maxLength }).map(() => optional($._anything)))
3685+
: repeat($._anything);
3686+
3687+
return prec.left(seq(unknowns, rule));
3688+
}

0 commit comments

Comments
 (0)