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#[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 }
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 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}