mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-10-05 15:57:08 +03:00
Add more import system documentation
This commit is contained in:
parent
74e53eb3e1
commit
66796e8225
@ -22,6 +22,7 @@ impl Book {
|
||||
}
|
||||
}
|
||||
|
||||
/// Inline copies of the declared bind in `Fold`, `Mat` and `Open` inside `use` expressions.
|
||||
pub fn desugar_ctr_use(&mut self) {
|
||||
for def in self.defs.values_mut() {
|
||||
for rule in def.rules.iter_mut() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::{ImportsMap, PackageLoader};
|
||||
use crate::{
|
||||
diagnostics::{Diagnostics, DiagnosticsConfig},
|
||||
fun::{parser::ParseBook, Adt, Book, Definition, Name, Rule, Source, Term},
|
||||
fun::{parser::ParseBook, Adt, Book, Definition, HvmDefinition, Name, Rule, Source, Term},
|
||||
imp::{Expr, Stmt},
|
||||
imports::packages::Packages,
|
||||
};
|
||||
@ -9,6 +9,19 @@ use indexmap::{map::Entry, IndexMap};
|
||||
use itertools::Itertools;
|
||||
|
||||
impl ParseBook {
|
||||
/// Loads and applies imports recursively to a ParseBook,
|
||||
/// transforming definitions and ADTs to a canonical name,
|
||||
/// and adding `use` binds so that names are accessible by their alias.
|
||||
///
|
||||
/// # Details
|
||||
///
|
||||
/// The process involves:
|
||||
///
|
||||
/// 1. Loading imports recursively using the provided `loader`.
|
||||
/// 2. Transforming definitions and ADTs with naming transformations.
|
||||
/// 3. Adding binds for aliases and old names in their respective definitions.
|
||||
/// 4. Converting the ParseBook into its functional form.
|
||||
/// 5. Perform any necessary post-processing.
|
||||
pub fn load_imports(
|
||||
self,
|
||||
mut loader: impl PackageLoader,
|
||||
@ -22,10 +35,15 @@ impl ParseBook {
|
||||
eprint!("{}", diag);
|
||||
|
||||
let mut book = book.to_fun()?;
|
||||
|
||||
// Process terms that contains constructors names and can't be updated by `desugar_use`.
|
||||
book.desugar_ctr_use();
|
||||
|
||||
Ok(book)
|
||||
}
|
||||
|
||||
/// Loads the imported books recursively into the importing book,
|
||||
/// then apply imported names or aliases binds to its definitions.
|
||||
fn apply_imports(
|
||||
&mut self,
|
||||
main_imports: Option<&ImportsMap>,
|
||||
@ -56,21 +74,27 @@ impl ParseBook {
|
||||
// Just serves to pass only the import map of the first call to `apply_imports_go`.
|
||||
let main_imports = main_imports.unwrap_or(&self.import_ctx.map);
|
||||
|
||||
package.apply_imports(Some(main_imports), diag, pkgs)?;
|
||||
let new_adts = package.apply_adts(&src, main_imports);
|
||||
// Rename ADTs and defs, applying binds from old names to new names
|
||||
package.apply_adts(&src, main_imports);
|
||||
package.apply_defs(&src, main_imports);
|
||||
|
||||
let book = package.to_fun()?;
|
||||
package.apply_imports(Some(main_imports), diag, pkgs)?; // TODO: Should this be after the apply_adts/defs functions?
|
||||
|
||||
for (name, adt) in new_adts {
|
||||
let Book { defs, hvm_defs, adts, .. } = package.to_fun()?;
|
||||
|
||||
// Add the ADTs to the importing book,
|
||||
// saving the constructors names to be used when applying ADTs binds.
|
||||
for (name, adt) in adts {
|
||||
let adts = pkgs.loaded_adts.entry(src.clone()).or_default();
|
||||
adts.insert(name.clone(), adt.ctrs.keys().cloned().collect_vec());
|
||||
self.add_imported_adt(name, adt, diag);
|
||||
}
|
||||
|
||||
for def in book.defs.into_values() {
|
||||
for def in defs.into_values() {
|
||||
self.add_imported_def(def, diag);
|
||||
}
|
||||
|
||||
// TODO: Need to add hvm_defs too
|
||||
}
|
||||
|
||||
diag.fatal(())
|
||||
@ -87,7 +111,7 @@ impl ParseBook {
|
||||
let mut local_imports: IndexMap<Name, Name> = IndexMap::new();
|
||||
|
||||
// Collect local imports binds, starting with `__` if not imported by the main book.
|
||||
'outer: for (bind, src) in self.import_ctx.map.iter().rev() {
|
||||
'outer: for (bind, src) in self.import_ctx.map.binds.iter().rev() {
|
||||
if self.contains_def(bind) | self.ctrs.contains_key(bind) | self.adts.contains_key(bind) {
|
||||
// TODO: Here we should show warnings for shadowing of imported names by local def/ctr/adt
|
||||
// It can be done, but when importing with `ImportType::Simple` files in the same folder,
|
||||
@ -95,8 +119,7 @@ impl ParseBook {
|
||||
continue;
|
||||
}
|
||||
|
||||
let nam =
|
||||
if main_imports.sources.contains(src) { src.clone() } else { Name::new(format!("__{}", src)) };
|
||||
let nam = if main_imports.contains_source(src) { src.clone() } else { Name::new(format!("__{}", src)) };
|
||||
|
||||
if let Some(adt) = self.adts.get(&nam) {
|
||||
for (ctr, _) in adt.ctrs.iter().rev() {
|
||||
@ -131,9 +154,9 @@ impl ParseBook {
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the book adts, applying the necessary naming transformations
|
||||
/// Applying the necessary naming transformations to the book ADTs,
|
||||
/// adding `use ctr = ctr_src` chains to every local definition.
|
||||
fn apply_adts(&mut self, src: &Name, main_imp: &ImportsMap) -> IndexMap<Name, Adt> {
|
||||
fn apply_adts(&mut self, src: &Name, main_imp: &ImportsMap) {
|
||||
let adts = std::mem::take(&mut self.adts);
|
||||
let mut new_adts = IndexMap::new();
|
||||
let mut ctrs_map = IndexMap::new();
|
||||
@ -144,13 +167,13 @@ impl ParseBook {
|
||||
adt.source = Source::Imported;
|
||||
name = Name::new(format!("{}/{}", src, name));
|
||||
|
||||
let mangle_name = !main_imp.sources.contains(&name);
|
||||
let mangle_name = !main_imp.contains_source(&name);
|
||||
let mut mangle_adt_name = mangle_name;
|
||||
|
||||
for (ctr, f) in std::mem::take(&mut adt.ctrs) {
|
||||
let mut ctr_name = Name::new(format!("{}/{}", src, ctr));
|
||||
|
||||
let mangle_ctr = mangle_name && !main_imp.sources.contains(&ctr_name);
|
||||
let mangle_ctr = mangle_name && !main_imp.contains_source(&ctr_name);
|
||||
|
||||
if mangle_ctr {
|
||||
mangle_adt_name = true;
|
||||
@ -187,7 +210,7 @@ impl ParseBook {
|
||||
def.body = std::mem::take(&mut def.body).fold_uses(ctrs_map.iter().rev());
|
||||
}
|
||||
|
||||
new_adts
|
||||
self.adts = new_adts;
|
||||
}
|
||||
|
||||
/// Apply the necessary naming transformations to the book definitions,
|
||||
@ -223,6 +246,18 @@ impl ParseBook {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper functions
|
||||
impl ParseBook {
|
||||
pub fn top_level_names(&self) -> impl Iterator<Item = &Name> {
|
||||
let imp_defs = self.imp_defs.keys();
|
||||
let fun_defs = self.fun_defs.keys();
|
||||
let adts = self.adts.keys();
|
||||
let ctrs = self.ctrs.keys();
|
||||
|
||||
imp_defs.chain(fun_defs).chain(adts).chain(ctrs)
|
||||
}
|
||||
|
||||
fn add_imported_adt(&mut self, nam: Name, adt: Adt, diag: &mut Diagnostics) {
|
||||
if self.adts.get(&nam).is_some() {
|
||||
@ -259,15 +294,6 @@ impl ParseBook {
|
||||
|
||||
self.fun_defs.insert(name.clone(), def);
|
||||
}
|
||||
|
||||
pub fn top_level_names(&self) -> impl Iterator<Item = &Name> {
|
||||
let imp_defs = self.imp_defs.keys();
|
||||
let fun_defs = self.fun_defs.keys();
|
||||
let adts = self.adts.keys();
|
||||
let ctrs = self.ctrs.keys();
|
||||
|
||||
imp_defs.chain(fun_defs).chain(adts).chain(ctrs)
|
||||
}
|
||||
}
|
||||
|
||||
fn rename_ctr_patterns(rule: &mut Rule, map: &IndexMap<Name, Name>) {
|
||||
@ -298,7 +324,7 @@ fn update_name(
|
||||
Source::Local(..) => {
|
||||
let mut new_name = Name::new(format!("{}/{}", src, def_name));
|
||||
|
||||
if !main_imp.sources.contains(&new_name) {
|
||||
if !main_imp.contains_source(&new_name) {
|
||||
new_name = Name::new(format!("__{}", new_name));
|
||||
}
|
||||
|
||||
|
@ -83,23 +83,20 @@ pub enum BoundSource {
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct ImportsMap {
|
||||
binds: IndexMap<Name, usize>,
|
||||
sources: Vec<Name>,
|
||||
binds: IndexMap<Name, Name>,
|
||||
}
|
||||
|
||||
impl ImportsMap {
|
||||
fn iter(&self) -> impl DoubleEndedIterator<Item = (&Name, &Name)> {
|
||||
self.binds.iter().map(|(n, u)| (n, &self.sources[*u]))
|
||||
pub fn contains_source(&self, s: &Name) -> bool {
|
||||
self.binds.values().contains(s)
|
||||
}
|
||||
|
||||
fn add_bind(&mut self, bind: Name, src: &str, diag: &mut Diagnostics) {
|
||||
if let Some(old) = self.binds.get(&bind) {
|
||||
let old = &self.sources[*old];
|
||||
let warn = format!("The import '{src}' shadows the imported name '{old}'");
|
||||
diag.add_book_warning(warn, WarningType::ImportShadow);
|
||||
}
|
||||
|
||||
self.binds.insert(bind, self.sources.len());
|
||||
self.sources.push(Name::new(src));
|
||||
self.binds.insert(bind, Name::new(src));
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
diagnostics::Diagnostics,
|
||||
fun::{load_book::do_parse_book, parser::ParseBook, Name},
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use itertools::Itertools;
|
||||
use std::{
|
||||
collections::{HashSet, VecDeque},
|
||||
@ -12,9 +12,12 @@ use std::{
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Packages {
|
||||
/// Map from source name to parsed book.
|
||||
pub books: IndexMap<Name, ParseBook>,
|
||||
/// Already loaded ADTs information to be used when applying ADT binds.
|
||||
pub loaded_adts: IndexMap<Name, IndexMap<Name, Vec<Name>>>,
|
||||
pub load_queue: VecDeque<usize>,
|
||||
/// Queue of books indexes that still needs to load its imports
|
||||
load_queue: VecDeque<usize>,
|
||||
}
|
||||
|
||||
impl Packages {
|
||||
@ -26,14 +29,8 @@ impl Packages {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_book(&self, idx: usize) -> &ParseBook {
|
||||
self.books.get_index(idx).unwrap().1
|
||||
}
|
||||
|
||||
fn get_book_mut(&mut self, idx: usize) -> &mut ParseBook {
|
||||
self.books.get_index_mut(idx).unwrap().1
|
||||
}
|
||||
|
||||
/// Loads each import statement recursively into a Source -> ParseBook map.
|
||||
/// Inserts into the ImportsMap of each book all the imported names.
|
||||
pub fn load_imports(
|
||||
&mut self,
|
||||
loader: &mut impl PackageLoader,
|
||||
@ -89,6 +86,8 @@ impl Packages {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Maps the `ImportType` of each import to the top level names it relates,
|
||||
/// checks if it is valid, and adds to the book ImportMap.
|
||||
fn load_binds(&mut self, idx: usize, diag: &mut Diagnostics) {
|
||||
let book = self.get_book(idx);
|
||||
let imports = book.import_ctx.imports.clone();
|
||||
@ -164,9 +163,11 @@ impl Packages {
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds all top level names of the book to the ImportMap in the form `alias/name`.
|
||||
/// If one of the names is equal to the name of the book, adds as `alias` instead.
|
||||
fn add_book_bind(&mut self, idx: usize, src: Name, nam: Name, alias: Option<Name>, diag: &mut Diagnostics) {
|
||||
let bound_book = self.books.get(&src).unwrap();
|
||||
let names: HashSet<_> = bound_book.top_level_names().cloned().collect();
|
||||
let names: IndexSet<_> = bound_book.top_level_names().cloned().collect();
|
||||
|
||||
let aliased = alias.as_ref().unwrap_or(&nam);
|
||||
|
||||
@ -185,6 +186,14 @@ impl Packages {
|
||||
book.import_ctx.map.add_bind(aliased.clone(), &src, diag);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_book(&self, idx: usize) -> &ParseBook {
|
||||
self.books.get_index(idx).unwrap().1
|
||||
}
|
||||
|
||||
fn get_book_mut(&mut self, idx: usize) -> &mut ParseBook {
|
||||
self.books.get_index_mut(idx).unwrap().1
|
||||
}
|
||||
}
|
||||
|
||||
// Taken from 'cargo/util/paths.rs'
|
||||
|
Loading…
Reference in New Issue
Block a user