erg_compiler/
build_hir.rs

1use erg_common::config::ErgConfig;
2use erg_common::dict::Dict;
3use erg_common::error::{ErrorDisplay, ErrorKind, MultiErrorDisplay};
4use erg_common::traits::BlockKind;
5use erg_common::traits::{ExitStatus, New, Runnable, Stream};
6use erg_common::Str;
7
8use erg_parser::ast::{VarName, AST};
9use erg_parser::build_ast::{ASTBuildable, ASTBuilder as DefaultASTBuilder};
10use erg_parser::ParserRunner;
11
12use crate::artifact::{BuildRunnable, Buildable, CompleteArtifact, IncompleteArtifact};
13use crate::context::{Context, ContextKind, ContextProvider, ModuleContext};
14use crate::effectcheck::SideEffectChecker;
15use crate::error::{CompileError, CompileErrors, LowerWarnings};
16use crate::link_hir::HIRLinker;
17use crate::lower::GenericASTLowerer;
18use crate::module::SharedCompilerResource;
19use crate::ownercheck::OwnershipChecker;
20use crate::ty::VisibilityModifier;
21use crate::varinfo::VarInfo;
22
23/// Summarize lowering, side-effect checking, and ownership checking
24///
25/// NOTE: This does not perform dependency resolution, use `PackageBuilder` to build a package
26#[derive(Debug)]
27pub struct GenericHIRBuilder<ASTBuilder: ASTBuildable = DefaultASTBuilder> {
28    pub(crate) lowerer: GenericASTLowerer<ASTBuilder>,
29    ownership_checker: OwnershipChecker,
30}
31
32pub type HIRBuilder = GenericHIRBuilder<DefaultASTBuilder>;
33
34impl<ASTBuilder: ASTBuildable> Default for GenericHIRBuilder<ASTBuilder> {
35    fn default() -> Self {
36        GenericHIRBuilder::new(ErgConfig::default())
37    }
38}
39
40impl<A: ASTBuildable> New for GenericHIRBuilder<A> {
41    fn new(cfg: ErgConfig) -> Self {
42        GenericHIRBuilder::new_with_cache(
43            cfg.copy(),
44            Str::ever("<module>"),
45            SharedCompilerResource::new(cfg),
46        )
47    }
48}
49
50impl<ASTBuilder: ASTBuildable> Runnable for GenericHIRBuilder<ASTBuilder> {
51    type Err = CompileError;
52    type Errs = CompileErrors;
53    const NAME: &'static str = "Erg HIR builder";
54
55    #[inline]
56    fn cfg(&self) -> &ErgConfig {
57        self.lowerer.cfg()
58    }
59    #[inline]
60    fn cfg_mut(&mut self) -> &mut ErgConfig {
61        self.lowerer.cfg_mut()
62    }
63
64    #[inline]
65    fn finish(&mut self) {}
66
67    fn initialize(&mut self) {
68        self.lowerer.initialize();
69        self.ownership_checker = OwnershipChecker::new(self.cfg().copy());
70    }
71
72    fn clear(&mut self) {
73        self.lowerer.clear();
74        // don't initialize the ownership checker
75    }
76
77    fn set_input(&mut self, input: erg_common::io::Input) {
78        self.lowerer.set_input(input);
79    }
80
81    fn exec(&mut self) -> Result<ExitStatus, Self::Errs> {
82        let mut builder = ASTBuilder::new(self.cfg().copy());
83        let artifact = builder
84            .build_ast(self.cfg_mut().input.read())
85            .map_err(|arti| arti.errors)?;
86        artifact.warns.write_all_stderr();
87        let artifact = self
88            .check(artifact.ast, "exec")
89            .map_err(|arti| arti.errors)?;
90        artifact.warns.write_all_stderr();
91        println!("{}", artifact.object);
92        Ok(ExitStatus::compile_passed(artifact.warns.len()))
93    }
94
95    fn eval(&mut self, src: String) -> Result<String, Self::Errs> {
96        let mut builder = ASTBuilder::new(self.cfg().copy());
97        let artifact = builder.build_ast(src).map_err(|arti| arti.errors)?;
98        artifact.warns.write_all_stderr();
99        let artifact = self
100            .check(artifact.ast, "eval")
101            .map_err(|arti| arti.errors)?;
102        artifact.warns.write_all_stderr();
103        Ok(artifact.object.to_string())
104    }
105
106    fn expect_block(&self, src: &str) -> BlockKind {
107        let mut parser = ParserRunner::new(self.cfg().clone());
108        match parser.eval(src.to_string()) {
109            Err(errs) => {
110                let kind = errs
111                    .iter()
112                    .filter(|e| e.core().kind == ErrorKind::ExpectNextLine)
113                    .map(|e| {
114                        let msg = e.core().sub_messages.last().unwrap();
115                        // ExpectNextLine error must have msg otherwise it's a bug
116                        msg.get_msg().first().unwrap().to_owned()
117                    })
118                    .next();
119                if let Some(kind) = kind {
120                    return BlockKind::from(kind.as_str());
121                }
122                if errs
123                    .iter()
124                    .any(|err| err.core.main_message.contains("\"\"\""))
125                {
126                    return BlockKind::MultiLineStr;
127                }
128                BlockKind::Error
129            }
130            Ok(_) => {
131                if src.contains("Class") {
132                    return BlockKind::ClassDef;
133                }
134                BlockKind::None
135            }
136        }
137    }
138}
139
140impl<ASTBuilder: ASTBuildable> Buildable for GenericHIRBuilder<ASTBuilder> {
141    fn inherit(cfg: ErgConfig, shared: SharedCompilerResource) -> Self {
142        let mod_name = Str::from(cfg.input.file_stem());
143        Self::new_with_cache(cfg, mod_name, shared)
144    }
145    fn inherit_with_name(cfg: ErgConfig, mod_name: Str, shared: SharedCompilerResource) -> Self {
146        Self::new_with_cache(cfg, mod_name, shared)
147    }
148    fn build(&mut self, src: String, mode: &str) -> Result<CompleteArtifact, IncompleteArtifact> {
149        self.build(src, mode)
150    }
151    fn build_from_ast(
152        &mut self,
153        ast: AST,
154        mode: &str,
155    ) -> Result<CompleteArtifact<crate::hir::HIR>, IncompleteArtifact<crate::hir::HIR>> {
156        self.check(ast, mode)
157    }
158    fn pop_context(&mut self) -> Option<ModuleContext> {
159        self.pop_mod_ctx()
160    }
161    fn get_context(&self) -> Option<&ModuleContext> {
162        Some(&self.lowerer.module)
163    }
164}
165
166impl<ASTBuilder: ASTBuildable + 'static> BuildRunnable for GenericHIRBuilder<ASTBuilder> {}
167
168impl<ASTBuilder: ASTBuildable> ContextProvider for GenericHIRBuilder<ASTBuilder> {
169    fn dir(&self) -> Dict<&VarName, &VarInfo> {
170        self.lowerer.dir()
171    }
172
173    fn get_receiver_ctx(&self, receiver_name: &str) -> Option<&Context> {
174        self.lowerer.get_receiver_ctx(receiver_name)
175    }
176
177    fn get_var_info(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
178        self.lowerer.get_var_info(name)
179    }
180}
181
182impl<ASTBuilder: ASTBuildable> GenericHIRBuilder<ASTBuilder> {
183    pub fn new(cfg: ErgConfig) -> Self {
184        New::new(cfg)
185    }
186
187    pub fn new_with_cache<S: Into<Str>>(
188        cfg: ErgConfig,
189        mod_name: S,
190        shared: SharedCompilerResource,
191    ) -> Self {
192        Self {
193            lowerer: GenericASTLowerer::new_with_cache(cfg.copy(), mod_name, shared),
194            ownership_checker: OwnershipChecker::new(cfg),
195        }
196    }
197
198    pub fn new_with_ctx(mut mod_ctx: ModuleContext) -> Self {
199        mod_ctx.context.grow(
200            "<module>",
201            ContextKind::Module,
202            VisibilityModifier::Private,
203            None,
204        );
205        Self {
206            ownership_checker: OwnershipChecker::new(mod_ctx.get_top_cfg()),
207            lowerer: GenericASTLowerer::new_with_ctx(mod_ctx),
208        }
209    }
210
211    pub fn new_submodule(mut mod_ctx: ModuleContext, name: &str) -> Self {
212        mod_ctx
213            .context
214            .grow(name, ContextKind::Module, VisibilityModifier::Private, None);
215        Self {
216            ownership_checker: OwnershipChecker::new(mod_ctx.get_top_cfg()),
217            lowerer: GenericASTLowerer::new_with_ctx(mod_ctx),
218        }
219    }
220
221    pub fn check(&mut self, ast: AST, mode: &str) -> Result<CompleteArtifact, IncompleteArtifact> {
222        let mut artifact = self.lowerer.lower(ast, mode)?;
223        let ctx = &self.lowerer.get_context().unwrap().context;
224        let effect_checker = SideEffectChecker::new(self.cfg().clone(), ctx);
225        let hir = if self.cfg().effect_check {
226            effect_checker
227                .check(artifact.object, self.lowerer.module.context.name.clone())
228                .map_err(|(hir, errs)| {
229                    self.lowerer.module.context.clear_invalid_vars();
230                    IncompleteArtifact::new(Some(hir), errs, artifact.warns.take_all().into())
231                })?
232        } else {
233            artifact.object
234        };
235        let hir = if self.cfg().ownership_check {
236            self.ownership_checker.check(hir).map_err(|(hir, errs)| {
237                self.lowerer.module.context.clear_invalid_vars();
238                IncompleteArtifact::new(Some(hir), errs, artifact.warns.take_all().into())
239            })?
240        } else {
241            hir
242        };
243        Ok(CompleteArtifact::new(hir, artifact.warns))
244    }
245
246    pub fn build(
247        &mut self,
248        src: String,
249        mode: &str,
250    ) -> Result<CompleteArtifact, IncompleteArtifact> {
251        let mut ast_builder = ASTBuilder::new(self.cfg().copy());
252        let artifact = ast_builder
253            .build_ast(src)
254            .map_err(|iart| IncompleteArtifact::new(None, iart.errors.into(), iart.warns.into()))?;
255        self.lowerer
256            .warns
257            .extend(LowerWarnings::from(artifact.warns));
258        self.check(artifact.ast, mode)
259    }
260
261    pub fn build_module(&mut self) -> Result<CompleteArtifact, IncompleteArtifact> {
262        let src = self.cfg_mut().input.read();
263        self.build(src, "exec")
264    }
265
266    pub fn build_linked_module(&mut self) -> Result<CompleteArtifact, IncompleteArtifact> {
267        let artifact = self.build_module()?;
268        let linker = HIRLinker::new(self.cfg(), self.lowerer.module.context.mod_cache());
269        let hir = linker.link(artifact.object);
270        Ok(CompleteArtifact::new(hir, artifact.warns))
271    }
272
273    pub fn pop_mod_ctx(&mut self) -> Option<ModuleContext> {
274        self.lowerer.pop_mod_ctx()
275    }
276
277    pub fn dir(&mut self) -> Dict<&VarName, &VarInfo> {
278        ContextProvider::dir(self)
279    }
280
281    pub fn get_receiver_ctx(&self, receiver_name: &str) -> Option<&Context> {
282        ContextProvider::get_receiver_ctx(self, receiver_name)
283    }
284
285    pub fn get_var_info(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
286        ContextProvider::get_var_info(self, name)
287    }
288
289    pub fn current_ctx(&self) -> &Context {
290        &self.lowerer.module.context
291    }
292
293    pub fn clear(&mut self) {
294        Runnable::clear(self);
295    }
296}