Add import aliases

This commit is contained in:
LunaAmora 2024-06-10 10:50:36 -03:00
parent dedfe42e38
commit 234ebdbe98
2 changed files with 59 additions and 25 deletions

View File

@ -175,6 +175,7 @@ impl<'a> TermParser<'a> {
// Import declaration // Import declaration
if self.try_parse_keyword("use") { if self.try_parse_keyword("use") {
self.skip_trivia();
let (import, sub_imports) = self.parse_import()?; let (import, sub_imports) = self.parse_import()?;
book.imports.add_import(import, sub_imports); book.imports.add_import(import, sub_imports);
indent = self.advance_newlines()?; indent = self.advance_newlines()?;
@ -260,8 +261,11 @@ impl<'a> TermParser<'a> {
fn parse_import(&mut self) -> Result<(Name, ImportType), String> { fn parse_import(&mut self) -> Result<(Name, ImportType), String> {
// use package // use package
self.skip_trivia(); let (import, alias) = self.parse_name_maybe_alias("Import")?;
let import = self.labelled(|p| p.parse_restricted_name("Top-level"), "import name")?;
if let Some(alias) = alias {
return Ok((import, ImportType::Simple(Some(alias))));
}
if self.try_consume("{") { if self.try_consume("{") {
if self.try_consume("*") { if self.try_consume("*") {
@ -269,13 +273,13 @@ impl<'a> TermParser<'a> {
return Ok((import, ImportType::Glob)); return Ok((import, ImportType::Glob));
} }
let sub = self.list_like(|p| p.parse_bend_name(), "", "}", ",", false, 0)?; let sub = self.list_like(|p| p.parse_name_maybe_alias("Name"), "", "}", ",", false, 0)?;
let imp_type = if sub.is_empty() { ImportType::Simple } else { ImportType::List(sub) }; let imp_type = if sub.is_empty() { ImportType::Simple(None) } else { ImportType::List(sub) };
return Ok((import, imp_type)); return Ok((import, imp_type));
} }
Ok((import, ImportType::Simple)) Ok((import, ImportType::Simple(None)))
} }
fn parse_rule(&mut self) -> ParseResult<(Name, Rule)> { fn parse_rule(&mut self) -> ParseResult<(Name, Rule)> {
// (name pat*) = term // (name pat*) = term
@ -1124,6 +1128,18 @@ pub trait ParserCommons<'a>: Parser<'a> {
self.parse_restricted_name("Variable") self.parse_restricted_name("Variable")
} }
fn parse_name_maybe_alias(&mut self, label: &str) -> ParseResult<(Name, Option<Name>)> {
let name = self.parse_restricted_name(label)?;
if self.try_consume("as") {
self.skip_trivia();
let alias = self.parse_restricted_name("Alias")?;
Ok((name, Some(alias)))
} else {
Ok((name, None))
}
}
/// Consumes exactly the text without skipping. /// Consumes exactly the text without skipping.
fn consume_exactly(&mut self, text: &str) -> ParseResult<()> { fn consume_exactly(&mut self, text: &str) -> ParseResult<()> {
if self.input().get(*self.index()..).unwrap_or_default().starts_with(text) { if self.input().get(*self.index()..).unwrap_or_default().starts_with(text) {

View File

@ -13,7 +13,7 @@ pub struct Imports {
names: Vec<(Name, ImportType)>, names: Vec<(Name, ImportType)>,
/// Map from bound names to source package. /// Map from bound names to source package.
map: IndexMap<Name, Name>, map: ImportsMap,
/// Imported packages to be loaded in the program. /// Imported packages to be loaded in the program.
/// When loaded, the book contents are drained to the parent book, /// When loaded, the book contents are drained to the parent book,
@ -21,10 +21,22 @@ pub struct Imports {
pkgs: IndexMap<Name, ParseBook>, pkgs: IndexMap<Name, ParseBook>,
} }
#[derive(Debug, Clone, Default)]
struct ImportsMap {
binds: IndexMap<Name, usize>,
sources: Vec<Name>,
}
impl ImportsMap {
fn iter(&self) -> impl DoubleEndedIterator<Item = (&Name, &Name)> {
self.binds.iter().map(|(n, u)| (n, &self.sources[*u]))
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ImportType { pub enum ImportType {
Simple, Simple(Option<Name>),
List(Vec<Name>), List(Vec<(Name, Option<Name>)>),
Glob, Glob,
} }
@ -60,15 +72,15 @@ impl Imports {
} }
match imp_type { match imp_type {
ImportType::Simple => { ImportType::Simple(alias) => {
let name = Name::new(src.split('/').last().unwrap()); let name = Name::new(src.split('/').last().unwrap());
let src = format!("{}/{}", src, name); let src = format!("{}/{}", src, name);
add_bind(&mut self.map, name, &src, diag); add_bind(&mut self.map, name, alias.clone(), &src, diag);
} }
ImportType::List(names) => { ImportType::List(names) => {
let book = self.pkgs.get(&src).unwrap(); let book = self.pkgs.get(&src).unwrap();
for sub in names { for (sub, alias) in names {
if !book.top_level_names().contains(sub) { if !book.top_level_names().contains(sub) {
let err = format!("Package `{src}` does not contain the top level name `{sub}`"); let err = format!("Package `{src}` does not contain the top level name `{sub}`");
diag.add_book_error(err); diag.add_book_error(err);
@ -76,7 +88,7 @@ impl Imports {
} }
let src = format!("{}/{}", src, sub); let src = format!("{}/{}", src, sub);
add_bind(&mut self.map, sub.clone(), &src, diag); add_bind(&mut self.map, sub.clone(), alias.clone(), &src, diag);
} }
} }
ImportType::Glob => { ImportType::Glob => {
@ -84,7 +96,7 @@ impl Imports {
for sub in book.top_level_names() { for sub in book.top_level_names() {
let src = format!("{}/{}", src, sub); let src = format!("{}/{}", src, sub);
add_bind(&mut self.map, sub.clone(), &src, diag); add_bind(&mut self.map, sub.clone(), None, &src, diag);
} }
} }
} }
@ -94,11 +106,17 @@ impl Imports {
} }
} }
fn add_bind(map: &mut IndexMap<Name, Name>, name: Name, src: &str, diag: &mut Diagnostics) { fn add_bind(map: &mut ImportsMap, name: Name, alias: Option<Name>, src: &str, diag: &mut Diagnostics) {
if let Some(old) = map.insert(name, Name::new(src)) { let aliased = alias.unwrap_or(name);
if let Some(old) = map.binds.get(&aliased) {
let old = &map.sources[*old];
let warn = format!("The import `{src}` shadows the imported name `{old}`"); let warn = format!("The import `{src}` shadows the imported name `{old}`");
diag.add_book_warning(warn, WarningType::ImportShadow); diag.add_book_warning(warn, WarningType::ImportShadow);
} }
map.binds.insert(aliased, map.sources.len());
map.sources.push(Name::new(src))
} }
impl ParseBook { impl ParseBook {
@ -117,7 +135,7 @@ impl ParseBook {
fn apply_imports_go( fn apply_imports_go(
&mut self, &mut self,
main_imports: Option<&IndexMap<Name, Name>>, main_imports: Option<&ImportsMap>,
diag: &mut Diagnostics, diag: &mut Diagnostics,
) -> Result<(), String> { ) -> Result<(), String> {
self.load_packages(main_imports, diag)?; self.load_packages(main_imports, diag)?;
@ -129,7 +147,7 @@ impl ParseBook {
/// applying the imports recursively of every nested book. /// applying the imports recursively of every nested book.
fn load_packages( fn load_packages(
&mut self, &mut self,
main_imports: Option<&IndexMap<Name, Name>>, main_imports: Option<&ImportsMap>,
diag: &mut Diagnostics, diag: &mut Diagnostics,
) -> Result<(), String> { ) -> Result<(), String> {
for (src, mut package) in std::mem::take(&mut self.imports.pkgs) { for (src, mut package) in std::mem::take(&mut self.imports.pkgs) {
@ -164,7 +182,7 @@ impl ParseBook {
/// Applies a chain of `use bind = src` to every local definition. /// Applies a chain of `use bind = src` to every local definition.
/// ///
/// Must be used after `load_packages` /// Must be used after `load_packages`
fn apply_import_binds(&mut self, main_imports: Option<&IndexMap<Name, Name>>, diag: &mut Diagnostics) { fn apply_import_binds(&mut self, main_imports: Option<&ImportsMap>, diag: &mut Diagnostics) {
// Can not be done outside the function because of the borrow checker. // Can not be done outside the function because of the borrow checker.
// Just serves to pass only the import map of the first call to `apply_imports_go`. // Just serves to pass only the import map of the first call to `apply_imports_go`.
let main_imports = main_imports.unwrap_or(&self.imports.map); let main_imports = main_imports.unwrap_or(&self.imports.map);
@ -192,7 +210,7 @@ impl ParseBook {
} }
let nam = let nam =
if main_imports.values().contains(&src) { src.clone() } else { Name::new(format!("__{}__", src)) }; if main_imports.sources.contains(src) { src.clone() } else { Name::new(format!("__{}__", src)) };
if let Some(adt) = &self.adts.get(&nam) { if let Some(adt) = &self.adts.get(&nam) {
for (ctr, _) in adt.ctrs.iter().rev() { for (ctr, _) in adt.ctrs.iter().rev() {
@ -221,7 +239,7 @@ impl ParseBook {
/// Consumes the book adts, applying the necessary naming transformations /// Consumes the book adts, applying the necessary naming transformations
/// adding `use ctr = ctr_src` chains to every local definition. /// adding `use ctr = ctr_src` chains to every local definition.
fn apply_adts(&mut self, src: &Name, main_imp: &IndexMap<Name, Name>) -> IndexMap<Name, Adt> { fn apply_adts(&mut self, src: &Name, main_imp: &ImportsMap) -> IndexMap<Name, Adt> {
let adts = std::mem::take(&mut self.adts); let adts = std::mem::take(&mut self.adts);
let mut new_adts = IndexMap::new(); let mut new_adts = IndexMap::new();
let mut ctrs_map = IndexMap::new(); let mut ctrs_map = IndexMap::new();
@ -232,13 +250,13 @@ impl ParseBook {
adt.source = Source::Imported; adt.source = Source::Imported;
name = Name::new(format!("{}/{}", src, name)); name = Name::new(format!("{}/{}", src, name));
let mangle_name = !main_imp.values().contains(&name); let mangle_name = !main_imp.sources.contains(&name);
let mut mangle_adt_name = mangle_name; let mut mangle_adt_name = mangle_name;
for (ctr, f) in std::mem::take(&mut adt.ctrs) { for (ctr, f) in std::mem::take(&mut adt.ctrs) {
let mut ctr_name = Name::new(format!("{}/{}", src, ctr)); let mut ctr_name = Name::new(format!("{}/{}", src, ctr));
let mangle_ctr = mangle_name && !main_imp.values().contains(&ctr_name); let mangle_ctr = mangle_name && !main_imp.sources.contains(&ctr_name);
if mangle_ctr { if mangle_ctr {
mangle_adt_name = true; mangle_adt_name = true;
@ -279,7 +297,7 @@ impl ParseBook {
/// Apply the necessary naming transformations to the book definitions, /// Apply the necessary naming transformations to the book definitions,
/// adding `use def = def_src` chains to every local definition. /// adding `use def = def_src` chains to every local definition.
fn apply_defs(&mut self, src: &Name, main_imp: &IndexMap<Name, Name>) { fn apply_defs(&mut self, src: &Name, main_imp: &ImportsMap) {
let mut def_map: IndexMap<_, _> = IndexMap::new(); let mut def_map: IndexMap<_, _> = IndexMap::new();
// Rename the definitions to their source name // Rename the definitions to their source name
@ -341,14 +359,14 @@ fn update_name(
def_name: &mut Name, def_name: &mut Name,
def_source: Source, def_source: Source,
src: &Name, src: &Name,
main_imp: &IndexMap<Name, Name>, main_imp: &ImportsMap,
def_map: &mut IndexMap<Name, Name>, def_map: &mut IndexMap<Name, Name>,
) { ) {
match def_source { match def_source {
Source::Local(..) => { Source::Local(..) => {
let mut new_name = Name::new(format!("{}/{}", src, def_name)); let mut new_name = Name::new(format!("{}/{}", src, def_name));
if !main_imp.values().contains(&new_name) { if !main_imp.sources.contains(&new_name) {
new_name = Name::new(format!("__{}__", new_name)); new_name = Name::new(format!("__{}__", new_name));
} }