Skip to content

Commit 9d72a52

Browse files
authored
Merge pull request #52 from supabase/chore/polish
2 parents c8f1708 + e3f55fc commit 9d72a52

File tree

3 files changed

+79
-6
lines changed

3 files changed

+79
-6
lines changed

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,8 @@ Once the parser is stable, and a robust and scalable data model is implemented,
3333
This is a proof of concept for building both a concrete syntax tree and an abstract syntax tree from a potentially malformed PostgreSQL source code. The `postgres_lsp` crate was created to prove that it works end-to-end, and is just a very basic language server with semantic highlighting and error diagnostics. Before further feature development, we have to complete a bit of groundwork:
3434

3535
1. _Finish the parser_
36-
- The parser works, but the enum values for all the different syntax elements and internal conversations are manually written or copied, and, in some places, only cover a few elements required for a simple select statement. To have full coverage without possibilities for a copy and paste error, they should be generated from `pg_query.rs` source code. ([#4](https://github.com/supabase/postgres_lsp/pull/4)) ✅
37-
- There are a few cases such as nested and named dollar quoted strings that cause the parser to fail due to limitations of the regex-based lexer. Nothing that is impossible to fix, or requires any fundamental change in the parser though. ✅
38-
- Add support for parsing function bodies ([#34](https://github.com/supabase/postgres_lsp/issues/34))
39-
- Implement a custom parser to extract statements from a source and replace the [regexp-based approach](https://github.com/supabase/postgres_lsp/blob/2f06c49f914b331cf93ea52d9edde8722d27ad05/crates/parser/src/source_parser.rs#L78)
36+
- ✅ The core parser algorithm is implemented.
37+
- 🚧 But we need help from the community to finalize it: https://github.com/supabase/postgres_lsp/issues/51.
4038
2. _Implement a robust and scalable data model_
4139
- This is still in a research phase
4240
- A great rationale on the importance of the data model in a language server can be found [here](https://matklad.github.io/2023/05/06/zig-language-server-and-cancellation.html)

crates/codegen/src/get_node_properties.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,18 @@ pub fn get_node_properties_mod(proto_file: &ProtoFile) -> proc_macro2::TokenStre
77
let node_handlers = node_handlers(&proto_file.nodes);
88

99
quote! {
10-
#[derive(Debug, Clone)]
10+
#[derive(Debug, Clone, PartialEq)]
1111
pub struct TokenProperty {
1212
pub value: Option<String>,
1313
pub kind: Option<SyntaxKind>,
1414
}
1515

16+
impl TokenProperty {
17+
pub fn new(value: Option<String>, kind: Option<SyntaxKind>) -> TokenProperty {
18+
TokenProperty { value, kind }
19+
}
20+
}
21+
1622
impl From<i32> for TokenProperty {
1723
fn from(value: i32) -> TokenProperty {
1824
TokenProperty {
@@ -100,6 +106,15 @@ pub fn get_node_properties_mod(proto_file: &ProtoFile) -> proc_macro2::TokenStre
100106
}
101107
}
102108

109+
impl From<SyntaxKind> for TokenProperty {
110+
fn from(kind: SyntaxKind) -> TokenProperty {
111+
TokenProperty {
112+
value: None,
113+
kind: Some(kind),
114+
}
115+
}
116+
}
117+
103118
impl From<Token> for TokenProperty {
104119
fn from(token: Token) -> TokenProperty {
105120
TokenProperty {

crates/parser/src/codegen.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,18 @@ parser_codegen!();
44

55
#[cfg(test)]
66
mod tests {
7-
use crate::codegen::get_nodes;
7+
use log::debug;
8+
9+
use crate::codegen::{get_nodes, SyntaxKind, TokenProperty};
10+
11+
fn init() {
12+
let _ = env_logger::builder().is_test(true).try_init();
13+
}
814

915
#[test]
1016
fn test_get_nodes() {
17+
init();
18+
1119
let input = "with c as (insert into contact (id) values ('id')) select * from c;";
1220

1321
let pg_query_root = match pg_query::parse(input) {
@@ -27,4 +35,56 @@ mod tests {
2735
let node_graph = get_nodes(&pg_query_root.unwrap(), 0);
2836
assert_eq!(node_graph.node_count(), 13);
2937
}
38+
39+
fn test_get_node_properties(input: &str, kind: SyntaxKind, expected: Vec<TokenProperty>) {
40+
init();
41+
42+
let pg_query_root = match pg_query::parse(input) {
43+
Ok(parsed) => Some(
44+
parsed
45+
.protobuf
46+
.nodes()
47+
.iter()
48+
.find(|n| n.1 == 1)
49+
.unwrap()
50+
.0
51+
.to_enum(),
52+
),
53+
Err(_) => None,
54+
};
55+
56+
let node_graph = get_nodes(&pg_query_root.unwrap(), 0);
57+
58+
debug!("node graph: {:#?}", node_graph);
59+
60+
let node_index = node_graph
61+
.node_indices()
62+
.find(|n| node_graph[*n].kind == kind)
63+
.unwrap();
64+
65+
debug!("selected node: {:#?}", node_graph[node_index]);
66+
67+
assert_eq!(node_graph[node_index].properties, expected);
68+
}
69+
70+
#[test]
71+
fn test_simple_select() {
72+
test_get_node_properties(
73+
"select 1;",
74+
SyntaxKind::SelectStmt,
75+
vec![TokenProperty::from(SyntaxKind::Select)],
76+
)
77+
}
78+
79+
#[test]
80+
fn test_select_with_from() {
81+
test_get_node_properties(
82+
"select 1 from contact;",
83+
SyntaxKind::SelectStmt,
84+
vec![
85+
TokenProperty::from(SyntaxKind::Select),
86+
TokenProperty::from(SyntaxKind::From),
87+
],
88+
)
89+
}
3090
}

0 commit comments

Comments
 (0)