Line data Source code
1 : //! The state shared between the analysis passes.
2 :
3 : use super::types::*;
4 : use super::AnalyzedScript;
5 : use crate::catalog::*;
6 : use dashql_buffers::analyzer::{AnalyzerErrorSeverity, AnalyzerErrorType, NameTag, SemanticNodeMarkerType};
7 : use dashql_buffers::parser::{Node, NodeType, SymbolSpan};
8 : use dashql_parser::names::NameId;
9 : use dashql_parser::parser::context::resolve_text_span;
10 : use dashql_parser::parser::ParsedScript;
11 : use dashql_parser::scanner::ScannedScript;
12 : use dashql_parser::span::TextSpan;
13 : use crate::hash::HashMap;
14 : use std::sync::Arc;
15 :
16 : /// The state shared between the analysis passes of a script
17 : pub(super) struct AnalysisState<'a> {
18 : /// The parsed script
19 : pub parsed: &'a ParsedScript,
20 : /// The AST
21 : pub ast: &'a [Node],
22 : /// The catalog
23 : pub catalog: &'a Catalog,
24 : /// The catalog entry id of the script
25 : pub entry_id: CatalogEntryId,
26 : /// The texts of the names
27 : pub name_texts: Vec<Arc<str>>,
28 : /// The output
29 : pub out: AnalyzedScript,
30 : /// The expression of every AST node, if it was translated
31 : pub expression_index: Vec<Option<ExprId>>,
32 : /// How often each qualified name was declared by a table so far
33 : table_name_occurrences: HashMap<QualifiedKey, u32>,
34 : /// How often each qualified name was declared by a function so far
35 : function_name_occurrences: HashMap<QualifiedKey, u32>,
36 : }
37 :
38 : impl<'a> AnalysisState<'a> {
39 4003 : pub fn new(parsed: &'a Arc<ParsedScript>, catalog: &'a Catalog) -> Self {
40 4003 : let scanned = parsed.scanned.clone();
41 4003 : let entry_id = scanned.external_id;
42 4003 : let mut names = scanned.names.clone();
43 4003 : let empty_name = names.register("", TextSpan::default());
44 4003 : let mut name_tags = vec![NameTag::NONE; names.len()];
45 4003 : name_tags[empty_name as usize] = NameTag(NameTag::DATABASE_NAME.0 | NameTag::SCHEMA_NAME.0);
46 17810 : let name_texts = names.iter().map(|n| Arc::<str>::from(n.text.as_str())).collect();
47 4003 : let node_count = parsed.nodes.len();
48 4003 : let out = AnalyzedScript {
49 4003 : parsed: parsed.clone(),
50 4003 : snapshot: catalog.snapshot().clone(),
51 4003 : entry: Arc::new(CatalogEntryData::new(entry_id, catalog.version())),
52 4003 : names,
53 4003 : name_tags,
54 4003 : name_objects: Vec::new(),
55 4003 : empty_name,
56 4003 : errors: Vec::new(),
57 4003 : node_markers: vec![SemanticNodeMarkerType::NONE; node_count],
58 4003 : table_references: Vec::new(),
59 4003 : insert_statements: Vec::new(),
60 4003 : expressions: Vec::new(),
61 4003 : function_arguments: Vec::new(),
62 4003 : name_scopes: Vec::new(),
63 4003 : name_scopes_by_root_node: Default::default(),
64 4003 : constant_expressions: Vec::new(),
65 4003 : parameters: Vec::new(),
66 4003 : client_function_calls: Vec::new(),
67 4003 : visualization_specs: Vec::new(),
68 4003 : board: None,
69 4003 : flow: None,
70 4003 : param_values: Vec::new(),
71 4003 : manual: false,
72 4003 : inference_constraints: Vec::new(),
73 4003 : inferred_table_schemas: Vec::new(),
74 4003 : inferred_table_schemas_by_name: Default::default(),
75 4003 : name_search_index: Default::default(),
76 4003 : table_parameters: None,
77 4003 : };
78 4003 : Self {
79 4003 : parsed,
80 4003 : ast: &parsed.nodes,
81 4003 : catalog,
82 4003 : entry_id,
83 4003 : name_texts,
84 4003 : out,
85 4003 : expression_index: vec![None; node_count],
86 4003 : table_name_occurrences: HashMap::default(),
87 4003 : function_name_occurrences: HashMap::default(),
88 4003 : }
89 4003 : }
90 :
91 : /// Reserve the id of the next table that the script declares, keyed by its name and the
92 : /// occurrence of the name among the tables of the script
93 1943 : pub fn reserve_table_id(&mut self, name: &QualifiedTableName) -> CatalogTableId {
94 1943 : let key = name.key();
95 1943 : let occurrence = self.table_name_occurrences.entry(key.clone()).or_insert(0);
96 1943 : let id = self.catalog.reserve_table_id(self.entry_id, &key, *occurrence);
97 1943 : *occurrence += 1;
98 1943 : id
99 1943 : }
100 :
101 : /// Reserve the id of the next function that the script declares, like `reserve_table_id`
102 36 : pub fn reserve_function_id(&mut self, name: &QualifiedFunctionName) -> CatalogFunctionId {
103 36 : let key = name.key();
104 36 : let occurrence = self.function_name_occurrences.entry(key.clone()).or_insert(0);
105 36 : let id = self.catalog.reserve_function_id(self.entry_id, &key, *occurrence);
106 36 : *occurrence += 1;
107 36 : id
108 36 : }
109 :
110 : /// Reserve the ids of the columns of a table, keyed by their names and their occurrences
111 1957 : pub fn reserve_column_ids<'n>(&self, table: CatalogTableId, names: impl Iterator<Item = &'n Arc<str>>) -> Vec<u32> {
112 1957 : let mut occurrences: HashMap<&Arc<str>, u32> = HashMap::default();
113 1957 : names
114 4507 : .map(|name| {
115 4507 : let occurrence = occurrences.entry(name).or_insert(0);
116 4507 : let id = self.catalog.reserve_column_id(table, name, *occurrence);
117 4507 : *occurrence += 1;
118 4507 : id
119 4507 : })
120 1957 : .collect()
121 1957 : }
122 :
123 : /// Finish the analysis: collect the names of the script for completion
124 4003 : pub fn into_script(mut self) -> AnalyzedScript {
125 4003 : let out = &mut self.out;
126 4003 : let entry_id = out.entry.catalog_entry_id;
127 4003 : let mut names: Vec<IndexedName> = out
128 4003 : .names
129 4003 : .iter()
130 4003 : .map(|n| IndexedName {
131 17810 : text: self.name_texts[n.name_id as usize].clone(),
132 17810 : occurrences: n.occurrences,
133 17810 : location: n.location,
134 17810 : tags: out.name_tags[n.name_id as usize],
135 17810 : objects: Vec::new(),
136 17810 : })
137 4003 : .collect();
138 9320 : for &(entry, name, object) in &out.name_objects {
139 9091 : if entry == entry_id {
140 9013 : names[name as usize].objects.push(object);
141 9013 : }
142 : }
143 4003 : out.name_search_index = Arc::new(NameSearchIndex::new(names));
144 4003 : self.out
145 4003 : }
146 :
147 : /// The declarations of the script, unshared while the analysis runs
148 15371 : pub fn entry_mut(&mut self) -> &mut CatalogEntryData {
149 15371 : Arc::make_mut(&mut self.out.entry)
150 15371 : }
151 :
152 9659 : pub fn scanned(&self) -> &ScannedScript {
153 9659 : &self.parsed.scanned
154 9659 : }
155 :
156 : /// The children of a node
157 45737 : pub fn children(&self, node: &Node) -> &'a [Node] {
158 45737 : let count = node.children_count() as usize;
159 45737 : if count == 0 {
160 0 : return &[];
161 45737 : }
162 45737 : let begin = node.children_begin_or_value() as usize;
163 45737 : &self.ast[begin..begin + count]
164 45737 : }
165 :
166 : /// The id of a node of the AST
167 16256 : pub fn node_id(&self, node: &Node) -> u32 {
168 16256 : ((node as *const Node as usize - self.ast.as_ptr() as usize) / std::mem::size_of::<Node>()) as u32
169 16256 : }
170 :
171 : /// A name of the script
172 25141 : pub fn name(&self, id: NameId) -> Name {
173 25141 : Name {
174 25141 : entry: self.entry_id,
175 25141 : id,
176 25141 : text: self.name_texts[id as usize].clone(),
177 25141 : }
178 25141 : }
179 :
180 : /// The location of an object of this script
181 2651 : pub fn loc(&self, index: usize) -> ObjectLoc {
182 2651 : ObjectLoc {
183 2651 : entry: self.entry_id,
184 2651 : index: index as u32,
185 2651 : }
186 2651 : }
187 :
188 : /// The empty name
189 10310 : pub fn empty_name(&self) -> Name {
190 10310 : self.name(self.out.empty_name)
191 10310 : }
192 :
193 : /// The name of a NAME node
194 5368 : pub fn node_name(&self, node: &Node) -> Name {
195 5368 : self.name(node.children_begin_or_value())
196 5368 : }
197 :
198 : /// Add analyzer tags to a name of the script
199 13285 : pub fn tag(&mut self, name: &Name, tag: NameTag) {
200 13285 : if name.entry == self.entry_id {
201 13285 : let tags = &mut self.out.name_tags[name.id as usize];
202 13285 : *tags = NameTag(tags.0 | tag.0);
203 13285 : }
204 13285 : }
205 :
206 : /// Remember an object a name resolves to
207 9101 : pub fn resolve_name(&mut self, name: &Name, object: CatalogObjectRef) {
208 9101 : self.out.name_objects.push((name.entry, name.id, object));
209 9101 : }
210 :
211 : /// Resolve a symbol span to a text span
212 9659 : pub fn text_span(&self, span: SymbolSpan) -> TextSpan {
213 9659 : let scanned = self.scanned();
214 9659 : resolve_text_span(&scanned.text, &scanned.symbols, span)
215 9659 : }
216 :
217 : /// The text at a symbol span
218 70 : pub fn text_at(&self, span: SymbolSpan) -> &str {
219 70 : let text = &self.parsed.scanned.text;
220 70 : let ts = self.text_span(span);
221 70 : let begin = (ts.offset as usize).min(text.len());
222 70 : let end = (begin + ts.length as usize).min(text.len());
223 70 : &text[begin..end]
224 70 : }
225 :
226 : /// Mark a node
227 8619 : pub fn mark(&mut self, node_id: u32, marker: SemanticNodeMarkerType) {
228 8619 : self.out.node_markers[node_id as usize] = marker;
229 8619 : }
230 :
231 : /// Add an expression
232 6332 : pub fn add_expression(&mut self, node_id: u32, location: SymbolSpan, inner: ExpressionInner) -> ExprId {
233 6332 : let id = self.out.expressions.len() as ExprId;
234 6332 : self.out.expressions.push(Expression {
235 6332 : expression_id: id,
236 6332 : ast_node_id: node_id,
237 6332 : location: Some(location),
238 6332 : ast_statement_id: None,
239 6332 : inner,
240 6332 : is_constant_expression: false,
241 6332 : });
242 6332 : id
243 6332 : }
244 :
245 : /// The expression of a node
246 8876 : pub fn expression_of(&self, node_id: u32) -> Option<ExprId> {
247 8876 : self.expression_index.get(node_id as usize).copied().flatten()
248 8876 : }
249 :
250 : /// Add an error at an AST node
251 89 : pub fn add_error(&mut self, error_type: AnalyzerErrorType, severity: AnalyzerErrorSeverity, node_id: u32, message: String) {
252 89 : let span = *self.ast[node_id as usize].symbol_span();
253 89 : let text_span = self.text_span(span);
254 89 : self.out.errors.push(AnalyzerError {
255 89 : error_type,
256 89 : severity,
257 89 : ast_node_id: Some(node_id),
258 89 : symbol_span: Some(span),
259 89 : text_span: Some(text_span),
260 89 : message,
261 89 : });
262 89 : }
263 :
264 : /// Read a name path
265 8585 : pub fn read_name_path(&self, node: &Node) -> Vec<NameId> {
266 8585 : let mut path = Vec::new();
267 8585 : if node.node_type() != NodeType::ARRAY {
268 0 : return path;
269 8585 : }
270 9500 : for child in self.children(node) {
271 9500 : match child.node_type() {
272 : // Skip over trailing dots
273 35 : NodeType::OBJECT_EXT_TRAILING_DOT => continue,
274 9465 : NodeType::NAME => path.push(child.children_begin_or_value()),
275 : // Not a plain name path
276 : _ => {
277 0 : path.clear();
278 0 : break;
279 : }
280 : }
281 : }
282 8585 : path
283 8585 : }
284 :
285 : /// Read a qualified table name
286 5410 : pub fn read_qualified_table_name(&mut self, node: Option<&Node>) -> Option<QualifiedTableName> {
287 5410 : let node = node?;
288 4540 : let path = self.read_name_path(node);
289 4540 : let ast_node_id = Some(self.node_id(node));
290 4540 : let (db, schema, table) = match path.len() {
291 213 : 3 => (self.name(path[0]), self.name(path[1]), self.name(path[2])),
292 104 : 2 => (self.empty_name(), self.name(path[0]), self.name(path[1])),
293 4223 : 1 => (self.empty_name(), self.empty_name(), self.name(path[0])),
294 0 : _ => return None,
295 : };
296 4540 : if path.len() == 3 {
297 213 : self.tag(&db, NameTag::DATABASE_NAME);
298 4328 : }
299 4540 : if path.len() >= 2 {
300 317 : self.tag(&schema, NameTag::SCHEMA_NAME);
301 4228 : }
302 4540 : self.tag(&table, NameTag::TABLE_NAME);
303 4540 : Some(QualifiedTableName {
304 4540 : ast_node_id,
305 4540 : database_name: db,
306 4540 : schema_name: schema,
307 4540 : table_name: table,
308 4540 : })
309 5410 : }
310 :
311 : /// Read a qualified column name.
312 : /// Paths with more than two names access fields of a row-typed column.
313 2715 : pub fn read_qualified_column_name(&mut self, node: Option<&Node>) -> Option<QualifiedColumnName> {
314 2715 : let node = node?;
315 2715 : let path = self.read_name_path(node);
316 2715 : let ast_node_id = Some(self.node_id(node));
317 2715 : match path.len() {
318 0 : 0 => None,
319 : 1 => {
320 2381 : let column = self.name(path[0]);
321 2381 : self.tag(&column, NameTag::COLUMN_NAME);
322 2381 : Some(QualifiedColumnName {
323 2381 : ast_node_id,
324 2381 : table_alias: None,
325 2381 : column_name: column,
326 2381 : })
327 : }
328 : _ => {
329 334 : let alias = self.name(path[0]);
330 334 : let column = self.name(path[1]);
331 334 : self.tag(&alias, NameTag::TABLE_ALIAS);
332 334 : self.tag(&column, NameTag::COLUMN_NAME);
333 334 : Some(QualifiedColumnName {
334 334 : ast_node_id,
335 334 : table_alias: Some(alias),
336 334 : column_name: column,
337 334 : })
338 : }
339 : }
340 2715 : }
341 :
342 : /// Read a qualified function name
343 381 : pub fn read_qualified_function_name(&mut self, node: Option<&Node>) -> Option<QualifiedFunctionName> {
344 381 : let node = node?;
345 381 : let path = self.read_name_path(node);
346 381 : let ast_node_id = Some(self.node_id(node));
347 381 : let (db, schema, function) = match path.len() {
348 5 : 3 => (self.name(path[0]), self.name(path[1]), self.name(path[2])),
349 4 : 2 => (self.empty_name(), self.name(path[0]), self.name(path[1])),
350 372 : 1 => (self.empty_name(), self.empty_name(), self.name(path[0])),
351 0 : _ => return None,
352 : };
353 381 : if path.len() == 3 {
354 5 : self.tag(&db, NameTag::DATABASE_NAME);
355 376 : }
356 381 : if path.len() >= 2 {
357 9 : self.tag(&schema, NameTag::SCHEMA_NAME);
358 372 : }
359 381 : self.tag(&function, NameTag::FUNCTION_NAME);
360 381 : Some(QualifiedFunctionName {
361 381 : ast_node_id,
362 381 : database_name: db,
363 381 : schema_name: schema,
364 381 : function_name: function,
365 381 : })
366 381 : }
367 :
368 : /// A table of this script or of the catalog
369 8122 : pub fn table(&self, loc: TableLoc) -> Option<&TableDeclaration> {
370 8122 : if loc.entry == self.entry_id {
371 512 : self.out.entry.table_declarations.get(loc.index as usize)
372 7610 : } else if loc.entry == crate::table_parameters::TABLE_PARAMETERS_ENTRY_ID {
373 34 : self.out.table_parameters.as_ref()?.table(loc)
374 : } else {
375 7576 : self.catalog.table(loc)
376 : }
377 8122 : }
378 :
379 : /// The statement that contains an AST node, None outside of statements
380 10902 : pub fn find_statement_id(&self, ast_node_id: u32) -> Option<u32> {
381 10902 : let mut root = ast_node_id;
382 : // Statement roots are their own parents
383 10902 : for _ in 0..self.ast.len() {
384 16592 : let parent = self.ast[root as usize].parent();
385 16592 : if parent as usize >= self.ast.len() || parent == root {
386 10902 : break;
387 5690 : }
388 5690 : root = parent;
389 : }
390 10902 : let statements = &self.parsed.statements;
391 18036 : if let Some(i) = statements.iter().position(|s| s.root == root) {
392 10893 : return Some(i as u32);
393 9 : }
394 9 : statements
395 9 : .iter()
396 9 : .position(|s| ast_node_id >= s.nodes_begin && ast_node_id < s.nodes_begin + s.node_count)
397 9 : .map(|i| i as u32)
398 10902 : }
399 : }
400 :
401 : /// The literal type of a literal node type
402 3178 : pub(super) fn literal_type(node_type: NodeType) -> dashql_buffers::algebra::LiteralType {
403 3178 : dashql_buffers::algebra::LiteralType((node_type.0 - 5) as u8)
404 3178 : }
405 :
406 : pub(super) use crate::utils::quote_identifier;
|