Skip to main content

nifty_lsp/index/
build.rs

1//! Builds an [`Index`] in two passes. Top-level declarations may appear in any order and in
2//! any file, so the first pass declares them all and the second resolves the names used in
3//! them.
4
5use std::collections::HashMap;
6
7use nifty_syntax::Span;
8use nifty_syntax::ast::{
9    Arg, Block, ElseBranch, Expr, ExprKind, File, Ident, IfStmt, Item, Iterable, StmtKind,
10    StringPart, TypeExpr, TypeExprKind, TypedName,
11};
12
13use super::{Index, Occurrence, Role, Symbol, SymbolId, SymbolKind, Unresolved, Visibility};
14
15pub(super) fn build(files: &[&File]) -> Index {
16    let mut builder = Builder {
17        symbols: Vec::new(),
18        occurrences: Vec::new(),
19        scopes: vec![HashMap::new()],
20        blocks: Vec::new(),
21    };
22    let items = || files.iter().flat_map(|file| &file.items);
23    let declared: Vec<Declared> = items().map(|item| builder.declare_item(item)).collect();
24    for (item, declared) in items().zip(declared) {
25        builder.resolve_item(item, &declared);
26    }
27    builder
28        .occurrences
29        .sort_by_key(|occurrence| occurrence.span);
30    Index {
31        symbols: builder.symbols,
32        occurrences: builder.occurrences,
33    }
34}
35
36/// The parameters declared for a function or view in the first pass, bound in the second.
37#[derive(Default)]
38struct Declared {
39    params: Vec<SymbolId>,
40}
41
42/// How a bare name is used, which decides what an unresolved one is reported as.
43#[derive(Clone, Copy)]
44enum NameUse {
45    Value,
46    Callee,
47}
48
49struct Builder<'ast> {
50    symbols: Vec<Symbol>,
51    occurrences: Vec<Occurrence>,
52    /// Innermost last. The first scope holds the top-level declarations.
53    scopes: Vec<HashMap<&'ast str, SymbolId>>,
54    /// The blocks enclosing the statement being resolved, innermost last.
55    blocks: Vec<Span>,
56}
57
58impl<'ast> Builder<'ast> {
59    fn declare_item(&mut self, item: &'ast Item) -> Declared {
60        match item {
61            Item::State(decl) => {
62                self.declare_global(&decl.name, SymbolKind::State);
63                Declared::default()
64            }
65            Item::Struct(decl) => {
66                let id = self.declare_global(&decl.name, SymbolKind::Struct);
67                for field in &decl.fields {
68                    self.declare(
69                        &field.name,
70                        SymbolKind::Field,
71                        Some(id),
72                        Visibility::Everywhere,
73                    );
74                }
75                Declared::default()
76            }
77            Item::Fn(decl) => {
78                self.declare_callable(&decl.name, SymbolKind::Function, &decl.params, &decl.body)
79            }
80            Item::View(decl) => {
81                self.declare_callable(&decl.name, SymbolKind::View, &decl.params, &decl.body)
82            }
83            Item::Named(named) => {
84                self.declare_global(&named.name, SymbolKind::Window);
85                Declared::default()
86            }
87            Item::Stmt(_) => Declared::default(),
88        }
89    }
90
91    fn declare_callable(
92        &mut self,
93        name: &'ast Ident,
94        kind: SymbolKind,
95        params: &[TypedName],
96        body: &Block,
97    ) -> Declared {
98        let id = self.declare_global(name, kind);
99        let visibility = Visibility::Within(body.span);
100        let params = params
101            .iter()
102            .map(|param| self.declare(&param.name, SymbolKind::Parameter, Some(id), visibility))
103            .collect();
104        Declared { params }
105    }
106
107    fn resolve_item(&mut self, item: &'ast Item, declared: &Declared) {
108        match item {
109            Item::State(decl) => {
110                self.resolve_type_annotation(decl.ty.as_ref());
111                self.resolve_expr(&decl.value);
112            }
113            Item::Struct(decl) => {
114                for field in &decl.fields {
115                    self.resolve_type(&field.ty);
116                }
117            }
118            Item::Fn(decl) => {
119                self.resolve_type_annotation(decl.return_type.as_ref());
120                self.resolve_callable_body(&decl.params, &declared.params, &decl.body);
121            }
122            Item::View(decl) => {
123                self.resolve_callable_body(&decl.params, &declared.params, &decl.body);
124            }
125            Item::Named(named) => self.resolve_stmt(&named.call.kind),
126            Item::Stmt(stmt) => self.resolve_stmt(&stmt.kind),
127        }
128    }
129
130    fn resolve_callable_body(
131        &mut self,
132        params: &'ast [TypedName],
133        ids: &[SymbolId],
134        body: &'ast Block,
135    ) {
136        self.scopes.push(HashMap::new());
137        for (param, &id) in params.iter().zip(ids) {
138            self.resolve_type(&param.ty);
139            self.bind(&param.name.name, id);
140        }
141        self.resolve_block(body);
142        self.scopes.pop();
143    }
144
145    fn resolve_block(&mut self, block: &'ast Block) {
146        self.scopes.push(HashMap::new());
147        self.blocks.push(block.span);
148        for stmt in &block.stmts {
149            self.resolve_stmt(&stmt.kind);
150        }
151        self.blocks.pop();
152        self.scopes.pop();
153    }
154
155    fn resolve_stmt(&mut self, stmt: &'ast StmtKind) {
156        match stmt {
157            StmtKind::Let { name, ty, value } => {
158                self.resolve_type_annotation(ty.as_ref());
159                self.resolve_expr(value);
160                let visibility = Visibility::After {
161                    file: value.span.file,
162                    start: value.span.end,
163                    end: self.blocks.last().map(|block| block.end),
164                };
165                let id = self.declare(name, SymbolKind::Local, None, visibility);
166                self.bind(&name.name, id);
167            }
168            StmtKind::Assign { target, value, .. } => {
169                self.resolve_expr(target);
170                self.resolve_expr(value);
171            }
172            StmtKind::If(if_stmt) => self.resolve_if(if_stmt),
173            StmtKind::For {
174                index,
175                item,
176                iterable,
177                body,
178            } => {
179                match iterable {
180                    Iterable::List(list) => self.resolve_expr(list),
181                    Iterable::Range { start, end } => {
182                        self.resolve_expr(start);
183                        self.resolve_expr(end);
184                    }
185                }
186                self.scopes.push(HashMap::new());
187                let visibility = Visibility::Within(body.span);
188                for name in index.iter().chain([item]) {
189                    let id = self.declare(name, SymbolKind::Local, None, visibility);
190                    self.bind(&name.name, id);
191                }
192                self.resolve_block(body);
193                self.scopes.pop();
194            }
195            StmtKind::Return(value) => {
196                if let Some(value) = value {
197                    self.resolve_expr(value);
198                }
199            }
200            StmtKind::Expr(expr) => self.resolve_expr(expr),
201        }
202    }
203
204    fn resolve_if(&mut self, if_stmt: &'ast IfStmt) {
205        self.resolve_expr(&if_stmt.condition);
206        self.resolve_block(&if_stmt.then_block);
207        match &if_stmt.else_branch {
208            Some(ElseBranch::If(nested)) => self.resolve_if(nested),
209            Some(ElseBranch::Block(block)) => self.resolve_block(block),
210            None => {}
211        }
212    }
213
214    fn resolve_expr(&mut self, expr: &'ast Expr) {
215        match &expr.kind {
216            ExprKind::Name(name) => {
217                self.resolve_name(name, expr.span, NameUse::Value);
218            }
219            ExprKind::ImplicitMember(member) => {
220                self.unresolved(member.span, Unresolved::ImplicitMember);
221            }
222            ExprKind::String(parts) => {
223                for part in parts {
224                    if let StringPart::Expr(expr) = part {
225                        self.resolve_expr(expr);
226                    }
227                }
228            }
229            ExprKind::List(items) => {
230                for item in items {
231                    self.resolve_expr(item);
232                }
233            }
234            ExprKind::Unary { operand, .. } => self.resolve_expr(operand),
235            ExprKind::Binary { lhs, rhs, .. } => {
236                self.resolve_expr(lhs);
237                self.resolve_expr(rhs);
238            }
239            ExprKind::Call {
240                callee,
241                args,
242                trailing_block,
243            } => {
244                let callee = self.resolve_callee(callee);
245                self.resolve_args(callee, args);
246                if let Some(block) = trailing_block {
247                    self.resolve_block(block);
248                }
249            }
250            ExprKind::Field { base, name } => {
251                self.resolve_expr(base);
252                self.unresolved(name.span, Unresolved::Field);
253            }
254            ExprKind::Index { base, index } => {
255                self.resolve_expr(base);
256                self.resolve_expr(index);
257            }
258            ExprKind::Int(_) | ExprKind::Float(_) | ExprKind::Bool(_) | ExprKind::Error => {}
259        }
260    }
261
262    /// Resolves what is being called, returning its symbol when it is declared in the file.
263    fn resolve_callee(&mut self, callee: &'ast Expr) -> Option<SymbolId> {
264        match &callee.kind {
265            ExprKind::Name(name) => self.resolve_name(name, callee.span, NameUse::Callee),
266            ExprKind::Field { base, name } => {
267                self.resolve_expr(base);
268                self.unresolved(name.span, Unresolved::Method);
269                None
270            }
271            _ => {
272                self.resolve_expr(callee);
273                None
274            }
275        }
276    }
277
278    /// Argument labels of a call to a declared struct, function or view refer to its fields
279    /// or parameters.
280    fn resolve_args(&mut self, callee: Option<SymbolId>, args: &'ast [Arg]) {
281        for arg in args {
282            let member = callee
283                .zip(arg.label.as_ref())
284                .and_then(|(callee, label)| Some((self.member(callee, &label.name)?, label.span)));
285            if let Some((member, span)) = member {
286                self.occur(span, Role::Reference(member));
287            }
288            self.resolve_expr(&arg.value);
289        }
290    }
291
292    fn resolve_name(&mut self, name: &str, span: Span, name_use: NameUse) -> Option<SymbolId> {
293        let found = self.lookup(name);
294        match found {
295            Some(id) => self.occur(span, Role::Reference(id)),
296            None => self.unresolved(
297                span,
298                match name_use {
299                    NameUse::Value => Unresolved::Variable,
300                    NameUse::Callee => Unresolved::Function,
301                },
302            ),
303        }
304        found
305    }
306
307    fn resolve_type_annotation(&mut self, ty: Option<&TypeExpr>) {
308        if let Some(ty) = ty {
309            self.resolve_type(ty);
310        }
311    }
312
313    fn resolve_type(&mut self, ty: &TypeExpr) {
314        match &ty.kind {
315            TypeExprKind::Named(name) => {
316                let declared_struct = self.scopes[0]
317                    .get(name.as_str())
318                    .copied()
319                    .filter(|&id| self.symbols[id.0].kind == SymbolKind::Struct);
320                match declared_struct {
321                    Some(id) => self.occur(ty.span, Role::Reference(id)),
322                    None => self.unresolved(ty.span, Unresolved::Type),
323                }
324            }
325            TypeExprKind::List(element) => self.resolve_type(element),
326        }
327    }
328
329    fn lookup(&self, name: &str) -> Option<SymbolId> {
330        self.scopes
331            .iter()
332            .rev()
333            .find_map(|scope| scope.get(name).copied())
334    }
335
336    fn member(&self, parent: SymbolId, name: &str) -> Option<SymbolId> {
337        self.symbols
338            .iter()
339            .position(|symbol| symbol.parent == Some(parent) && symbol.name == name)
340            .map(SymbolId)
341    }
342
343    /// Declares a top-level name. When a name is declared twice, the first one wins.
344    fn declare_global(&mut self, name: &'ast Ident, kind: SymbolKind) -> SymbolId {
345        let id = self.declare(name, kind, None, Visibility::Everywhere);
346        self.scopes[0].entry(&name.name).or_insert(id);
347        id
348    }
349
350    fn declare(
351        &mut self,
352        name: &Ident,
353        kind: SymbolKind,
354        parent: Option<SymbolId>,
355        visibility: Visibility,
356    ) -> SymbolId {
357        let id = SymbolId(self.symbols.len());
358        self.symbols.push(Symbol {
359            name: name.name.clone(),
360            kind,
361            parent,
362            visibility,
363        });
364        self.occur(name.span, Role::Declaration(id));
365        id
366    }
367
368    fn bind(&mut self, name: &'ast str, id: SymbolId) {
369        if let Some(scope) = self.scopes.last_mut() {
370            scope.insert(name, id);
371        }
372    }
373
374    fn unresolved(&mut self, span: Span, kind: Unresolved) {
375        self.occur(span, Role::Unresolved(kind));
376    }
377
378    fn occur(&mut self, span: Span, role: Role) {
379        self.occurrences.push(Occurrence { span, role });
380    }
381}