1use crate::core::{
4 clean::ast as ca,
5 compile::builtin::*,
6 compile::check::*,
7 preprocess::{self as pre, Module},
8 util::*,
9};
10use crate::match1;
11use std::collections::{BTreeMap, VecDeque};
12
13enum Error {
14 ImportNotFound(Vec<String>),
15 CircularImport(Vec<String>),
16 SymbolNotFound(String),
17 AutomaticImportsNotExported(Vec<String>),
18 NotDefType(Vec<String>),
19 NoSuchSymbol(Vec<String>),
20}
21
22impl Error {
23 fn core(self) -> CoreError {
24 match self {
25 Self::ImportNotFound(ext) => {
26 CoreError::make_raw(format!("module \"{}\" not found", path_to_string(&ext)), "")
27 }
28 Self::CircularImport(path) => CoreError::make_raw(
29 "circular import",
30 format!(
31 "Path: \"{}\".",
32 path_to_string(&path.into_iter().skip(1).collect::<Vec<_>>())
33 ),
34 ),
35 Self::SymbolNotFound(symbol) => {
36 CoreError::make_raw(format!("symbol \"{}\" not found", symbol), "")
37 }
38 Self::AutomaticImportsNotExported(path) => {
39 CoreError::make_raw(
40 "automatic import are not exported",
41 format!(
42 concat!(
43 "Help: this is an automatic import, which does not get exported from other modules.\n",
44 "You still have access to this object, just use its name: {}"
45 ),
46 path.last().unwrap()
47 )
48 )
49 }
50 Self::NotDefType(path) => {
51 CoreError::make_raw(format!("\"{}\" is not a class", path_to_string(&path)), "")
52 }
53 Self::NoSuchSymbol(rel) => {
54 CoreError::make_raw(format!("symbol \"{}\" not found", path_to_string(&rel)), "")
55 }
56 }
57 }
58}
59
60pub fn path_to_string(path: &Vec<String>) -> String {
61 if path.len() == 0 {
62 return "".to_string();
63 }
64
65 let mut path_string = path[0].clone();
66 for part in path.iter().skip(1) {
67 path_string.push('.');
68 path_string.push_str(part.as_str());
69 }
70
71 return path_string;
72}
73
74#[derive(Clone, Debug)]
79pub struct NamespaceOutput {
80 pub preprocessed: pre::ModuleRegistry,
81 pub tree: Tree<Namespace>,
82}
83
84pub type Namespace = BTreeMap<String, NamespacedObject>;
86
87impl Tree<Namespace> {
88 pub fn advance_path(
116 &self,
117 rel: &Vec<String>,
118 abs: &Vec<String>,
119 ) -> Option<(Vec<String>, Vec<String>)> {
120 self._advance_path(rel.clone().into(), abs)
121 }
122
123 fn _advance_path(
124 &self,
125 mut rel: VecDeque<String>,
126 abs: &Vec<String>,
127 ) -> Option<(Vec<String>, Vec<String>)> {
128 let next = match rel.pop_front() {
129 Some(next) => next,
130 None => {
131 return Some((abs.clone(), vec![]));
132 }
133 };
134
135 match self.get(abs) {
136 Some(Tree::Leaf(namespace)) => match namespace.get(&next) {
137 Some(NamespacedObject::Automatic(..) | NamespacedObject::Item(..)) => {
138 let mut abs = abs.clone();
139 abs.push(next);
140 Some((abs, rel.into()))
141 }
142 Some(NamespacedObject::Import(Located(_, import))) => match import.import_type {
143 ImportType::Symbol => {
144 let mut abs = import.path.clone();
145 rel.push_front(abs.pop().unwrap());
146 self._advance_path(rel, &abs)
147 }
148 ImportType::Module | ImportType::Package => match self.get(&import.path) {
149 Some(..) => self._advance_path(rel, &import.path),
150 None => None,
151 },
152 },
153 None => None,
154 },
155 Some(Tree::Node(package)) => match package.get(&next) {
156 Some(..) => {
157 let mut abs = abs.clone();
158 abs.push(next);
159 self._advance_path(rel, &abs)
160 }
161 None => None,
162 },
163 None => None,
164 }
165 }
166}
167
168#[derive(Clone, Debug)]
170pub enum NamespacedObject {
171 Automatic(Builtin),
172 Import(Import),
173 Item(Item),
174}
175
176pub type Import = Located<ImportObj>;
179#[derive(Clone, Debug)]
180pub struct ImportObj {
181 pub path: Vec<String>,
182 pub import_type: ImportType,
183 pub is_builtin: bool,
184}
185
186#[derive(Clone, Debug)]
187pub enum ImportType {
188 Symbol,
189 Module,
190 Package,
191}
192
193#[derive(Clone, Debug)]
194pub enum Item {
195 Defined(ca::TopLevelStatement),
196 Builtin(Builtin),
197}
198
199enum Wip {
201 Empty,
202 Pending,
203 Done(Namespace),
204}
205
206impl TryFrom<pre::ModuleRegistry> for NamespaceOutput {
207 type Error = CoreError;
208
209 fn try_from(registry: pre::ModuleRegistry) -> CResult<NamespaceOutput> {
210 let mut wip = registry.tree.clone().map(|module| match module {
211 Module::Python(..) => Wip::Empty,
212 Module::SeahorsePrelude => Wip::Done(prelude::namespace()),
213 Module::SeahorsePyth => Wip::Done(pyth::namespace()),
214 });
215
216 build_namespace(&mut wip, ®istry, ®istry.origin)?;
217
218 let tree = wip.map(|namespace| match namespace {
219 Wip::Done(namespace) => namespace,
220 _ => panic!(),
221 });
222
223 let registry = NamespaceOutput {
224 preprocessed: registry,
225 tree,
226 };
227
228 return Ok(registry);
229 }
230}
231
232impl Tree<Namespace> {
233 pub fn build_ty(&self, ty_expr: &ca::TyExpression, abs: &Vec<String>) -> CResult<Ty> {
234 let Located(loc, obj) = ty_expr;
235
236 match obj {
237 ca::TyExpressionObj::Generic { base, params } => {
238 let params = params
239 .iter()
240 .map(|param| self.build_ty(param, abs))
241 .collect::<Result<Vec<_>, _>>()?;
242
243 let base = match self.advance_path(base, abs) {
244 Some((path, rem)) => {
245 if rem.len() == 0 {
246 match self.get_leaf_ext(&path).unwrap() {
247 NamespacedObject::Automatic(builtin) => {
248 if !path.starts_with(&abs) {
249 Err(Error::AutomaticImportsNotExported(path)
250 .core()
251 .located(loc.clone()))
252 } else {
253 Ok(TyName::Builtin(builtin.clone()))
254 }
255 }
256 NamespacedObject::Item(Item::Defined(def)) => {
257 let Located(_, obj) = def;
258 match obj {
259 ca::TopLevelStatementObj::ClassDef { .. } => {
260 Ok(TyName::Defined(path, DefinedType::Struct))
261 }
262 _ => {
263 Err(Error::NotDefType(path).core().located(loc.clone()))
264 }
265 }
266 }
267 NamespacedObject::Item(Item::Builtin(builtin)) => {
268 builtin
269 .as_instance(¶ms)
270 .map_err(|err| err.located(loc.clone()))?;
271
272 Ok(TyName::Builtin(builtin.clone()))
273 }
274 _ => panic!(),
275 }
276 } else {
277 Err(Error::NoSuchSymbol(base.clone())
278 .core()
279 .located(loc.clone()))
280 }
281 }
282 _ => Err(Error::NoSuchSymbol(base.clone())
283 .core()
284 .located(loc.clone())),
285 }?;
286
287 Ok(Ty::Generic(base, params))
288 }
289 ca::TyExpressionObj::Const(n) => Ok(Ty::Const(*n)),
290 }
291 .map_err(|err: Error| err.core().located(loc.clone()))
292 }
293}
294
295fn build_namespace(
300 wip: &mut Tree<Wip>,
301 registry: &pre::ModuleRegistry,
302 path: &Vec<String>,
303) -> CResult<()> {
304 let node = wip.get(path).unwrap();
305 match &node {
306 &Tree::Leaf(Wip::Pending) => return Err(Error::CircularImport(path.clone()).core()),
307 &Tree::Leaf(Wip::Done(..)) => return Ok(()),
308 &Tree::Leaf(Wip::Empty) => {
309 *wip.get_mut(path).unwrap() = Tree::Leaf(Wip::Pending);
310
311 let module = match1!(registry.tree.get(path).unwrap(), Tree::Leaf(module) => module);
312 let namespace = match module {
313 pre::Module::Python(module) => build_python_namespace(wip, registry, path, module)?,
314 _ => panic!(),
315 };
316
317 *wip.get_mut(path).unwrap() = Tree::Leaf(Wip::Done(namespace));
318 }
319 &Tree::Node(package) => {
322 let keys = package.keys().map(|key| key.clone()).collect::<Vec<_>>();
324 for key in keys.iter() {
325 let mut path_ = path.clone();
326 path_.push(key.clone());
327 build_namespace(wip, registry, &path_)?;
328 }
329
330 return Ok(());
331 }
332 }
333
334 Ok(())
335}
336
337fn build_python_namespace(
339 wip: &mut Tree<Wip>,
340 registry: &pre::ModuleRegistry,
341 path: &Vec<String>,
342 module: &ca::Module,
343) -> CResult<Namespace> {
344 let mut namespace = BTreeMap::new();
345
346 namespace.append(&mut prelude::namespace());
348 namespace.append(&mut python::namespace());
349
350 for statement in module.statements.iter() {
351 let Located(loc, obj) = statement;
352 match obj {
353 ca::TopLevelStatementObj::Import { symbols } => {
354 for ca::ImportSymbol { symbol, alias } in symbols.iter() {
355 let ext = vec![symbol.clone()];
358 let abs = registry.get_abs_path(path, &ext).ok_or(
360 Error::ImportNotFound(ext.clone())
361 .core()
362 .located(loc.clone()),
363 )?;
364
365 build_namespace(wip, registry, &abs)?;
366
367 let obj =
368 get_import_obj(wip, &abs, None).map_err(|err| err.located(loc.clone()))?;
369 let name = alias.clone().unwrap_or(symbol.clone());
370 namespace.insert(name, NamespacedObject::Import(Located(loc.clone(), obj)));
371 }
372 }
373 ca::TopLevelStatementObj::ImportFrom {
374 path: ext,
376 symbols,
377 ..
378 } => {
379 let abs = registry.get_abs_path(path, ext).ok_or(
380 Error::ImportNotFound(ext.clone())
381 .core()
382 .located(loc.clone()),
383 )?;
384
385 build_namespace(wip, registry, &abs)?;
386
387 for ca::ImportSymbol { symbol, alias } in symbols.iter() {
388 if symbol.as_str() == "*" {
389 let glob = match wip.get(&abs).unwrap() {
390 Tree::Leaf(Wip::Done(namespace)) => {
391 namespace
392 .iter()
393 .filter_map(|(name, object)| {
394 if let NamespacedObject::Automatic(..) = object {
396 None
397 } else {
398 Some(name)
399 }
400 })
401 .collect::<Vec<_>>()
402 }
403 Tree::Node(package) => package.keys().collect::<Vec<_>>(),
404 _ => panic!(),
405 };
406
407 for symbol in glob.into_iter() {
408 let obj = get_import_obj(wip, &abs, Some(symbol))
409 .map_err(|err| err.located(loc.clone()))?;
410 namespace.insert(
411 symbol.clone(),
412 NamespacedObject::Import(Located(loc.clone(), obj)),
413 );
414 }
415 } else {
416 let obj = get_import_obj(wip, &abs, Some(symbol))
417 .map_err(|err| err.located(loc.clone()))?;
418 let name = alias.clone().unwrap_or(symbol.clone());
419 namespace.insert(name, NamespacedObject::Import(Located(loc.clone(), obj)));
420 }
421 }
422 }
423 ca::TopLevelStatementObj::Constant { name, .. }
424 | ca::TopLevelStatementObj::ClassDef { name, .. }
425 | ca::TopLevelStatementObj::FunctionDef(ca::FunctionDef { name, .. }) => {
426 let export =
427 NamespacedObject::Item(Item::Defined(Located(loc.clone(), obj.clone())));
428 namespace.insert(name.clone(), export);
429 }
430 ca::TopLevelStatementObj::Expression(..) => {}
431 }
432 }
433
434 return Ok(namespace);
435}
436
437fn get_import_obj(
441 wip: &Tree<Wip>,
442 path: &Vec<String>,
443 symbol: Option<&String>,
444) -> CResult<ImportObj> {
445 match wip.get(path).unwrap() {
446 Tree::Leaf(Wip::Done(namespace)) => match symbol {
447 Some(symbol) => {
448 if let Some(object) = namespace.get(symbol) {
449 let is_builtin = match object {
450 NamespacedObject::Item(Item::Defined(..)) => false,
451 NamespacedObject::Import(Located(
452 _,
453 ImportObj {
454 is_builtin: false, ..
455 },
456 )) => false,
457 _ => true,
458 };
459
460 let mut path = path.clone();
461 path.push(symbol.clone());
462 Ok(ImportObj {
463 path,
464 import_type: ImportType::Symbol,
465 is_builtin,
466 })
467 } else {
468 Err(Error::SymbolNotFound(symbol.clone()).core())
469 }
470 }
471 None => Ok(ImportObj {
472 path: path.clone(),
473 import_type: ImportType::Module,
474 is_builtin: path.starts_with(&["sh".to_string()]),
475 }),
476 },
477 Tree::Node(package) => match symbol {
478 Some(symbol) => match package.get(symbol) {
479 Some(Tree::Leaf(..)) => {
480 let mut path = path.clone();
481 path.push(symbol.clone());
482 let is_builtin = path.starts_with(&["sh".to_string()]);
483 Ok(ImportObj {
484 path: path,
485 import_type: ImportType::Module,
486 is_builtin,
487 })
488 }
489 Some(Tree::Node(..)) => {
490 let mut path = path.clone();
491 path.push(symbol.clone());
492 let is_builtin = path.starts_with(&["sh".to_string()]);
493 Ok(ImportObj {
494 path: path,
495 import_type: ImportType::Package,
496 is_builtin,
497 })
498 }
499 None => Err(Error::SymbolNotFound(symbol.clone()).core()),
500 },
501 None => Ok(ImportObj {
502 path: path.clone(),
503 import_type: ImportType::Package,
504 is_builtin: path.starts_with(&["sh".to_string()]),
505 }),
506 },
507 _ => panic!(),
508 }
509}
510
511pub fn namespace(registry: pre::ModuleRegistry) -> CResult<NamespaceOutput> {
513 registry.try_into()
514}