Skip to main content

blues_lsp/project/
syntax.rs

1use std::{collections::HashMap, sync::Arc};
2
3use arcstr::Substr;
4use tracing::trace;
5
6use crate::{
7    symbols::name::SymName,
8    syntax::{
9        buildctx::BuildCtx,
10        cst::{
11            tree::{Cst, NodeHandle},
12            view::{self, ExportItemKind, StmtKind, TypedefKind, View},
13        },
14        lexer::{bsv::BsvLexer, token::Token},
15        location::ROOT_ORIGIN,
16        parser::{self, state::Parser},
17        preprocessor::{
18            Preprocessor,
19            vpp::{VppPreprocessor, VppSpan},
20        },
21        streams::TextCharStream,
22    },
23    util::data::either::Either,
24};
25
26use super::{PkgHandle, Project, file::FileContents, querry::Queryable};
27
28/// Results of parsing package source
29pub struct Syntax {
30    pub ctx: BuildCtx,
31    pub vpp: SyntaxVpp,
32    pub tokens: Vec<Token>, // TODO: Temp
33    pub cst: Cst,
34    pub top: PkgTop,
35}
36
37pub struct SyntaxVpp {
38    pub spans: Vec<VppSpan>,
39}
40
41pub struct PkgTop {
42    pub defs: HashMap<SymName, NodeHandle>,
43    pub imports: Vec<PkgHandle>,
44    pub exports: Vec<Either<Substr, PkgHandle>>,
45}
46
47impl Queryable for Syntax {
48    type Input = PkgHandle;
49    type Ctx = ();
50    type Backref = ();
51
52    fn compute(input: Self::Input, _ctx: &Self::Ctx, proj: &Project) -> Arc<Self> {
53        let pkg = proj.get_pkg(input);
54        let file = proj.file_contents(pkg.file, input);
55        trace!("compiling syntax for {}", pkg);
56        Arc::new(Syntax::parse(proj, input, file))
57    }
58
59    fn invalidate(&self, input: &Self::Input, _ctx: &Self::Ctx, proj: &Project) {
60        proj.exports.invalidate(proj, input);
61        proj.bindings.invalidate(proj, input);
62    }
63
64    fn invalidate_backref(&self, _backref: Self::Backref, _proj: &Project) {}
65}
66
67impl Syntax {
68    pub fn parse(proj: &Project, pkg: PkgHandle, file: Arc<FileContents>) -> Self {
69        let mut ctx = BuildCtx::new(pkg, file.clone());
70
71        let source = file.chunks(ROOT_ORIGIN);
72        let source = TextCharStream::new(source.iter());
73
74        let mut preprocessed = Vec::new();
75        let mut vpp = VppPreprocessor::new(proj, &mut ctx);
76        vpp.process(source, &mut preprocessed);
77        let preprocessed = TextCharStream::new(preprocessed.iter());
78
79        let vpp = SyntaxVpp { spans: vpp.spans };
80
81        let mut tokens = Vec::new();
82        let mut lexer = BsvLexer::new(&mut ctx);
83        lexer.run(preprocessed, &mut tokens);
84
85        let tokens = tokens.clone(); // Temp
86
87        let mut parser = Parser::new(&mut ctx, tokens.clone());
88        parser::bsv::package(&mut parser);
89        let nodes = parser.make_tree();
90        let cst = Cst::new(nodes);
91
92        let top = Self::compute_top(proj, pkg, &cst);
93
94        Syntax {
95            ctx,
96            vpp,
97            tokens,
98            cst,
99            top,
100        }
101    }
102
103    fn compute_top(proj: &Project, pkg: PkgHandle, cst: &Cst) -> PkgTop {
104        let mut top = PkgTop {
105            defs: HashMap::new(),
106            imports: Vec::new(),
107            exports: Vec::new(),
108        };
109
110        let root = view::Package::cast(cst.root());
111
112        let Some(body) = root.body() else {
113            return top;
114        };
115
116        for stmt in body.stmts() {
117            let Some(stmt) = stmt.kind() else {
118                continue;
119            };
120            match stmt {
121                StmtKind::Function(stmt_function) => {
122                    let Some(name) = stmt_function.typed_name().and_then(|n| n.name()) else {
123                        continue;
124                    };
125                    top.defs
126                        .insert(SymName::Value(name.str()), stmt_function.syntax().handle());
127                }
128                StmtKind::Interface(intf) => {
129                    intf.name().map(|n| {
130                        top.defs
131                            .insert(SymName::Type(n.str()), intf.syntax().handle())
132                    });
133                }
134                StmtKind::Module(modl) => {
135                    modl.name().map(|n| {
136                        top.defs
137                            .insert(SymName::Value(n.str()), modl.syntax().handle())
138                    });
139                }
140                StmtKind::Import(stmt_import) => {
141                    for import in stmt_import.items() {
142                        let Some(name) = import.name() else { continue };
143                        let Some(imported) = proj.get_pkg(pkg).resolve_import(proj, &name.str())
144                        else {
145                            continue;
146                        };
147                        top.imports.push(imported);
148                    }
149                }
150                StmtKind::Export(stmt_export) => {
151                    for export in stmt_export.items() {
152                        let Some(kind) = export.kind() else { continue };
153                        match kind {
154                            ExportItemKind::Def(name) | ExportItemKind::Struct(name) => {
155                                top.exports.push(Either::Left(name.str()));
156                            }
157                            ExportItemKind::Package(name) => {
158                                // TODO: check for matching import
159                                let Some(exported) =
160                                    proj.get_pkg(pkg).resolve_import(proj, &name.str())
161                                else {
162                                    continue;
163                                };
164                                top.exports.push(Either::Right(exported));
165                            }
166                        }
167                    }
168                }
169                StmtKind::Typedef(tydef) => {
170                    tydef.kind().map(|kind| match kind {
171                        TypedefKind::Enum(tydef) => tydef.name().map(|n| {
172                            top.defs
173                                .insert(SymName::Type(n.str()), tydef.syntax().handle())
174                        }),
175                        TypedefKind::Struct(tydef) => tydef.name().map(|n| {
176                            top.defs
177                                .insert(SymName::Type(n.str()), tydef.syntax().handle())
178                        }),
179                        TypedefKind::Union(tydef) => tydef.name().map(|n| {
180                            top.defs
181                                .insert(SymName::Type(n.str()), tydef.syntax().handle())
182                        }),
183                        TypedefKind::Alias(tydef) => tydef.name().map(|n| {
184                            top.defs
185                                .insert(SymName::Type(n.str()), tydef.syntax().handle())
186                        }),
187                    });
188                }
189                StmtKind::Typeclass(tyclass) => {
190                    if let Some(name) = tyclass.name() {
191                        top.defs
192                            .insert(SymName::Type(name.str()), tyclass.syntax().handle());
193                    };
194                }
195                StmtKind::ExprOrBind(_) => (),
196                StmtKind::Instance(_) => (),
197                StmtKind::Method(_) => (),
198            }
199        }
200
201        top
202    }
203
204    pub fn root(&self) -> view::Package<'_> {
205        view::Package::try_cast(self.cst.root()).expect("CST root node is not 'Package'")
206    }
207
208    pub fn compute_globals(&self, proj: &Project) -> HashMap<SymName, (PkgHandle, NodeHandle)> {
209        let pkg = self.ctx.pkg;
210        let mut defs: HashMap<SymName, (PkgHandle, NodeHandle)> = HashMap::new();
211
212        for imported in &self.top.imports {
213            let exports = proj.exports.get_as(proj, *imported, pkg);
214            defs.extend(exports.defs.iter().map(|(k, v)| (k.clone(), *v)));
215        }
216
217        defs.extend(self.top.defs.iter().map(|(k, v)| (k.clone(), (pkg, *v))));
218        proj.get_pkg(pkg)
219            .name
220            .clone()
221            .map(|name| defs.insert(SymName::Pkg(name), (pkg, self.root().syntax().handle())));
222
223        defs
224    }
225}