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