Skip to content

Commit c889b6f

Browse files
authored
ide: refactor resolve into classify (#809)
1 parent 87bf03c commit c889b6f

File tree

4 files changed

+432
-642
lines changed

4 files changed

+432
-642
lines changed

crates/squawk_ide/src/classify.rs

Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
use squawk_syntax::ast::{self, AstNode};
2+
3+
#[derive(Debug)]
4+
pub(crate) enum NameRefClass {
5+
DropTable,
6+
Table,
7+
DropIndex,
8+
DropType,
9+
DropView,
10+
DropFunction,
11+
DropAggregate,
12+
DropProcedure,
13+
DropRoutine,
14+
CallProcedure,
15+
DropSchema,
16+
CreateIndex,
17+
CreateIndexColumn,
18+
SelectFunctionCall,
19+
SelectFromTable,
20+
SelectColumn,
21+
SelectQualifiedColumnTable,
22+
SelectQualifiedColumn,
23+
InsertTable,
24+
InsertColumn,
25+
DeleteTable,
26+
DeleteWhereColumn,
27+
UpdateTable,
28+
UpdateWhereColumn,
29+
UpdateSetColumn,
30+
UpdateFromTable,
31+
SchemaQualifier,
32+
TypeReference,
33+
}
34+
35+
pub(crate) fn classify_name_ref(name_ref: &ast::NameRef) -> Option<NameRefClass> {
36+
let mut in_partition_item = false;
37+
let mut in_call_expr = false;
38+
let mut in_arg_list = false;
39+
let mut in_column_list = false;
40+
let mut in_where_clause = false;
41+
let mut in_from_clause = false;
42+
let mut in_set_clause = false;
43+
44+
// TODO: can we combine this if and the one that follows?
45+
if let Some(parent) = name_ref.syntax().parent()
46+
&& let Some(field_expr) = ast::FieldExpr::cast(parent.clone())
47+
&& let Some(base) = field_expr.base()
48+
&& let ast::Expr::NameRef(base_name_ref) = base
49+
// check that the name_ref we're looking at in the field expr is the
50+
// base name_ref, i.e., the schema, rather than the item
51+
&& base_name_ref.syntax() == name_ref.syntax()
52+
{
53+
let is_function_call = field_expr
54+
.syntax()
55+
.parent()
56+
.and_then(ast::CallExpr::cast)
57+
.is_some();
58+
let is_schema_table_col = field_expr
59+
.syntax()
60+
.parent()
61+
.and_then(ast::FieldExpr::cast)
62+
.is_some();
63+
64+
let mut in_from_clause = false;
65+
for ancestor in parent.ancestors() {
66+
if ast::FromClause::can_cast(ancestor.kind()) {
67+
in_from_clause = true;
68+
}
69+
if ast::Select::can_cast(ancestor.kind()) && !in_from_clause {
70+
if is_function_call || is_schema_table_col {
71+
return Some(NameRefClass::SchemaQualifier);
72+
} else {
73+
return Some(NameRefClass::SelectQualifiedColumnTable);
74+
}
75+
}
76+
}
77+
return Some(NameRefClass::SchemaQualifier);
78+
}
79+
80+
if let Some(parent) = name_ref.syntax().parent()
81+
&& let Some(field_expr) = ast::FieldExpr::cast(parent.clone())
82+
&& field_expr
83+
.field()
84+
// we're at the field in a FieldExpr, i.e., foo.bar
85+
// ^^^
86+
.is_some_and(|field_name_ref| field_name_ref.syntax() == name_ref.syntax())
87+
// we're not inside a call expr
88+
&& field_expr
89+
.syntax()
90+
.parent()
91+
.and_then(ast::CallExpr::cast)
92+
.is_none()
93+
{
94+
let is_base_of_outer_field_expr = field_expr
95+
.syntax()
96+
.parent()
97+
.and_then(ast::FieldExpr::cast)
98+
.is_some();
99+
100+
let mut in_from_clause = false;
101+
let mut in_cast_expr = false;
102+
for ancestor in parent.ancestors() {
103+
if ast::CastExpr::can_cast(ancestor.kind()) {
104+
in_cast_expr = true;
105+
}
106+
if ast::FromClause::can_cast(ancestor.kind()) {
107+
in_from_clause = true;
108+
}
109+
if ast::Select::can_cast(ancestor.kind()) && !in_from_clause {
110+
if in_cast_expr {
111+
return Some(NameRefClass::TypeReference);
112+
}
113+
if is_base_of_outer_field_expr {
114+
return Some(NameRefClass::SelectQualifiedColumnTable);
115+
} else if let Some(base) = field_expr.base()
116+
&& matches!(base, ast::Expr::NameRef(_) | ast::Expr::FieldExpr(_))
117+
{
118+
return Some(NameRefClass::SelectQualifiedColumn);
119+
} else {
120+
return Some(NameRefClass::SelectQualifiedColumnTable);
121+
}
122+
}
123+
}
124+
}
125+
126+
if let Some(parent) = name_ref.syntax().parent()
127+
&& let Some(inner_path) = ast::PathSegment::cast(parent)
128+
.and_then(|p| p.syntax().parent().and_then(ast::Path::cast))
129+
&& let Some(outer_path) = inner_path
130+
.syntax()
131+
.parent()
132+
.and_then(|p| ast::Path::cast(p).and_then(|p| p.qualifier()))
133+
&& outer_path.syntax() == inner_path.syntax()
134+
{
135+
return Some(NameRefClass::SchemaQualifier);
136+
}
137+
138+
let mut in_type = false;
139+
for ancestor in name_ref.syntax().ancestors() {
140+
if ast::PathType::can_cast(ancestor.kind()) || ast::ExprType::can_cast(ancestor.kind()) {
141+
in_type = true;
142+
}
143+
if ast::DropTable::can_cast(ancestor.kind()) {
144+
return Some(NameRefClass::DropTable);
145+
}
146+
if ast::Table::can_cast(ancestor.kind()) {
147+
return Some(NameRefClass::Table);
148+
}
149+
if ast::DropIndex::can_cast(ancestor.kind()) {
150+
return Some(NameRefClass::DropIndex);
151+
}
152+
if ast::DropType::can_cast(ancestor.kind()) {
153+
return Some(NameRefClass::DropType);
154+
}
155+
if ast::DropView::can_cast(ancestor.kind()) {
156+
return Some(NameRefClass::DropView);
157+
}
158+
if ast::CastExpr::can_cast(ancestor.kind()) && in_type {
159+
return Some(NameRefClass::TypeReference);
160+
}
161+
if ast::DropFunction::can_cast(ancestor.kind()) {
162+
return Some(NameRefClass::DropFunction);
163+
}
164+
if ast::DropAggregate::can_cast(ancestor.kind()) {
165+
return Some(NameRefClass::DropAggregate);
166+
}
167+
if ast::DropProcedure::can_cast(ancestor.kind()) {
168+
return Some(NameRefClass::DropProcedure);
169+
}
170+
if ast::DropRoutine::can_cast(ancestor.kind()) {
171+
return Some(NameRefClass::DropRoutine);
172+
}
173+
if ast::Call::can_cast(ancestor.kind()) {
174+
return Some(NameRefClass::CallProcedure);
175+
}
176+
if ast::DropSchema::can_cast(ancestor.kind()) {
177+
return Some(NameRefClass::DropSchema);
178+
}
179+
if ast::PartitionItem::can_cast(ancestor.kind()) {
180+
in_partition_item = true;
181+
}
182+
if ast::CreateIndex::can_cast(ancestor.kind()) {
183+
if in_partition_item {
184+
return Some(NameRefClass::CreateIndexColumn);
185+
}
186+
return Some(NameRefClass::CreateIndex);
187+
}
188+
if ast::ArgList::can_cast(ancestor.kind()) {
189+
in_arg_list = true;
190+
}
191+
if ast::CallExpr::can_cast(ancestor.kind()) {
192+
in_call_expr = true;
193+
}
194+
if ast::FromClause::can_cast(ancestor.kind()) {
195+
in_from_clause = true;
196+
}
197+
if ast::Select::can_cast(ancestor.kind()) {
198+
if in_call_expr && !in_arg_list {
199+
return Some(NameRefClass::SelectFunctionCall);
200+
}
201+
if in_from_clause {
202+
return Some(NameRefClass::SelectFromTable);
203+
}
204+
// Classify as SelectColumn for target list, WHERE, ORDER BY, GROUP BY, etc.
205+
// (anything in SELECT except FROM clause)
206+
return Some(NameRefClass::SelectColumn);
207+
}
208+
if ast::ColumnList::can_cast(ancestor.kind()) {
209+
in_column_list = true;
210+
}
211+
if ast::Insert::can_cast(ancestor.kind()) {
212+
if in_column_list {
213+
return Some(NameRefClass::InsertColumn);
214+
}
215+
return Some(NameRefClass::InsertTable);
216+
}
217+
if ast::WhereClause::can_cast(ancestor.kind()) {
218+
in_where_clause = true;
219+
}
220+
if ast::SetClause::can_cast(ancestor.kind()) {
221+
in_set_clause = true;
222+
}
223+
if ast::Delete::can_cast(ancestor.kind()) {
224+
if in_where_clause {
225+
return Some(NameRefClass::DeleteWhereColumn);
226+
}
227+
return Some(NameRefClass::DeleteTable);
228+
}
229+
if ast::Update::can_cast(ancestor.kind()) {
230+
if in_where_clause {
231+
return Some(NameRefClass::UpdateWhereColumn);
232+
}
233+
if in_set_clause {
234+
return Some(NameRefClass::UpdateSetColumn);
235+
}
236+
if in_from_clause {
237+
return Some(NameRefClass::UpdateFromTable);
238+
}
239+
return Some(NameRefClass::UpdateTable);
240+
}
241+
}
242+
243+
None
244+
}
245+
246+
#[derive(Debug)]
247+
pub(crate) enum NameClass {
248+
ColumnDefinition {
249+
create_table: ast::CreateTable,
250+
column: ast::Column,
251+
},
252+
CreateTable(ast::CreateTable),
253+
WithTable(ast::WithTable),
254+
CreateIndex(ast::CreateIndex),
255+
CreateType(ast::CreateType),
256+
CreateFunction(ast::CreateFunction),
257+
CreateAggregate(ast::CreateAggregate),
258+
CreateProcedure(ast::CreateProcedure),
259+
CreateSchema(ast::CreateSchema),
260+
ViewColumnList {
261+
create_view: ast::CreateView,
262+
name: ast::Name,
263+
},
264+
CreateView(ast::CreateView),
265+
}
266+
267+
pub(crate) fn classify_name(name: &ast::Name) -> Option<NameClass> {
268+
let parent = name.syntax().parent();
269+
let column_parent = parent.clone().and_then(ast::Column::cast);
270+
let with_table_parent = parent.and_then(ast::WithTable::cast);
271+
let mut has_column_list = false;
272+
273+
for ancestor in name.syntax().ancestors() {
274+
if !has_column_list && ast::ColumnList::can_cast(ancestor.kind()) {
275+
has_column_list = true;
276+
}
277+
if let Some(create_table) = ast::CreateTable::cast(ancestor.clone()) {
278+
if let Some(column) = column_parent {
279+
return Some(NameClass::ColumnDefinition {
280+
create_table,
281+
column,
282+
});
283+
}
284+
return Some(NameClass::CreateTable(create_table));
285+
}
286+
if let Some(create_index) = ast::CreateIndex::cast(ancestor.clone()) {
287+
return Some(NameClass::CreateIndex(create_index));
288+
}
289+
if let Some(create_type) = ast::CreateType::cast(ancestor.clone()) {
290+
return Some(NameClass::CreateType(create_type));
291+
}
292+
if let Some(create_function) = ast::CreateFunction::cast(ancestor.clone()) {
293+
return Some(NameClass::CreateFunction(create_function));
294+
}
295+
if let Some(create_aggregate) = ast::CreateAggregate::cast(ancestor.clone()) {
296+
return Some(NameClass::CreateAggregate(create_aggregate));
297+
}
298+
if let Some(create_procedure) = ast::CreateProcedure::cast(ancestor.clone()) {
299+
return Some(NameClass::CreateProcedure(create_procedure));
300+
}
301+
if let Some(create_schema) = ast::CreateSchema::cast(ancestor.clone()) {
302+
return Some(NameClass::CreateSchema(create_schema));
303+
}
304+
if let Some(create_view) = ast::CreateView::cast(ancestor.clone()) {
305+
if has_column_list {
306+
return Some(NameClass::ViewColumnList {
307+
create_view,
308+
name: name.clone(),
309+
});
310+
}
311+
return Some(NameClass::CreateView(create_view));
312+
}
313+
}
314+
315+
if let Some(with_table) = with_table_parent {
316+
return Some(NameClass::WithTable(with_table));
317+
}
318+
319+
None
320+
}

0 commit comments

Comments
 (0)