From 74c770edcc088b7f4d0ff7089d54c47fd2194439 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 18 Jan 2024 17:27:40 -0800 Subject: [PATCH] Add exposing renaming --- .../tests/module/test_factorial_renamed.clsp | 4 + src/compiler/comptypes.rs | 77 ++++++++++++++++++- src/compiler/frontend.rs | 45 ++--------- src/compiler/resolve.rs | 14 +++- src/tests/compiler/modules.rs | 17 ++++ 5 files changed, 113 insertions(+), 44 deletions(-) create mode 100644 resources/tests/module/test_factorial_renamed.clsp diff --git a/resources/tests/module/test_factorial_renamed.clsp b/resources/tests/module/test_factorial_renamed.clsp new file mode 100644 index 00000000..a881bc67 --- /dev/null +++ b/resources/tests/module/test_factorial_renamed.clsp @@ -0,0 +1,4 @@ +(include *standard-cl-23*) +(import std.factorial exposing (! as factorial)) + +(export (X) (factorial X)) diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 8aea65d0..5942d2a6 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -465,6 +465,31 @@ pub struct QualifiedModuleInfo { pub struct ModuleImportListedName { pub nl: Srcloc, pub name: Vec, + pub alias: Option>, +} + +impl ModuleImportListedName { + pub fn to_sexp(&self) -> Rc { + let as_atom = Rc::new(SExp::Atom(self.nl.clone(), b"as".to_vec())); + let name_atom = Rc::new(SExp::Atom(self.nl.clone(), self.name.clone())); + if let Some(alias) = self.alias.as_ref() { + Rc::new(SExp::Cons( + self.nl.clone(), + name_atom, + Rc::new(SExp::Cons( + self.nl.clone(), + as_atom.clone(), + Rc::new(SExp::Cons( + self.nl.clone(), + Rc::new(SExp::Atom(self.nl.clone(), alias.clone())), + Rc::new(SExp::Nil(self.nl.clone())), + )), + )), + )) + } else { + name_atom + } + } } /// Specification of how to name imported items from the target namespace. @@ -478,6 +503,45 @@ pub enum ModuleImportSpec { Hiding(Srcloc, Vec), } +pub fn match_as_named(lst: &[SExp], offset: usize) -> Option<(Srcloc, Vec, Option>)> { + let name_offset = offset; + let small = 1 + offset; + let as_kw = 1 + offset; + let as_name_offset = 2 + offset; + let large = 3 + offset; + + if lst.len() != small && lst.len() != large { + return None; + } + + let export_name = if lst.len() == large { + if let SExp::Atom(_, as_atom) = lst[as_kw].borrow() { + // Not 'as' + if as_atom != b"as" { + return None; + } + } else { + return None; + } + + if let SExp::Atom(_, as_name) = lst[as_name_offset].borrow() { + Some(as_name.clone()) + } else { + return None; + } + } else { + None + }; + + let from_name = if let SExp::Atom(_, from_name) = lst[name_offset].borrow() { + from_name.clone() + } else { + return None; + }; + + Some((lst[name_offset].loc(), from_name, export_name)) +} + impl ModuleImportSpec { pub fn name_loc(&self) -> Srcloc { match self { @@ -571,10 +635,19 @@ impl ModuleImportSpec { if let SExp::Atom(kw_loc, kw) = &forms[skip] { let mut words = vec![]; for atom in forms.iter().skip(skip + 1) { - if let SExp::Atom(name_loc, name) = atom { + if let Some((import_name_loc, import_name, export_name)) = + atom.proper_list().and_then(|lst| match_as_named(&lst, 0)) + { + words.push(ModuleImportListedName { + nl: import_name_loc, + name: import_name, + alias: export_name, + }); + } else if let SExp::Atom(name_loc, name) = atom { words.push(ModuleImportListedName { nl: name_loc.clone(), name: name.clone(), + alias: None, }); } else { return Err(CompileErr( @@ -620,7 +693,7 @@ impl ModuleImportSpec { result_vec.extend( exposed_names .iter() - .map(|e| Rc::new(SExp::Atom(e.nl.clone(), e.name.clone()))) + .map(|e| e.to_sexp()) .collect::>>(), ); Rc::new(enlist(kl.clone(), &result_vec)) diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index 679bd103..d2bc5968 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -8,11 +8,11 @@ use num_bigint::ToBigInt; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::compiler::comptypes::{ - list_to_cons, ArgsAndTail, Binding, BindingPattern, BodyForm, ChiaType, CompileErr, - CompileForm, CompilerOpts, ConstantKind, DefconstData, DefmacData, DeftypeData, DefunData, - Export, FrontendOutput, HelperForm, ImportLongName, IncludeDesc, LetData, LetFormInlineHint, - LetFormKind, LongNameTranslation, ModAccum, ModuleImportSpec, NamespaceData, NamespaceRefData, - StructDef, StructMember, SyntheticType, TypeAnnoKind, + list_to_cons, match_as_named, ArgsAndTail, Binding, BindingPattern, BodyForm, ChiaType, + CompileErr, CompileForm, CompilerOpts, ConstantKind, DefconstData, DefmacData, DeftypeData, + DefunData, Export, FrontendOutput, HelperForm, ImportLongName, IncludeDesc, LetData, + LetFormInlineHint, LetFormKind, LongNameTranslation, ModAccum, ModuleImportSpec, NamespaceData, + NamespaceRefData, StructDef, StructMember, SyntheticType, TypeAnnoKind, }; use crate::compiler::lambda::handle_lambda; use crate::compiler::preprocessor::{ @@ -1147,39 +1147,6 @@ fn parse_chia_type(v: Vec) -> Result { )) } -pub fn match_export_named(lst: &[SExp]) -> Option<(Vec, Option>)> { - if lst.len() != 2 && lst.len() != 4 { - return None; - } - - let export_name = if lst.len() == 4 { - if let SExp::Atom(_, as_atom) = lst[2].borrow() { - // Not 'as' - if as_atom != b"as" { - return None; - } - } else { - return None; - } - - if let SExp::Atom(_, as_name) = lst[3].borrow() { - Some(as_name.clone()) - } else { - return None; - } - } else { - None - }; - - let from_name = if let SExp::Atom(_, from_name) = lst[1].borrow() { - from_name.clone() - } else { - return None; - }; - - Some((from_name, export_name)) -} - pub fn match_export_form( opts: Rc, form: Rc, @@ -1200,7 +1167,7 @@ pub fn match_export_form( return Ok(None); } - if let Some((fun_name, export_name)) = match_export_named(&lst) { + if let Some((_, fun_name, export_name)) = match_as_named(&lst, 1) { return Ok(Some(Export::Function(fun_name, export_name))); } diff --git a/src/compiler/resolve.rs b/src/compiler/resolve.rs index 9b9e08be..ec0206f8 100644 --- a/src/compiler/resolve.rs +++ b/src/compiler/resolve.rs @@ -8,7 +8,7 @@ use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ map_m, Binding, BindingPattern, BodyForm, CompileErr, CompileForm, CompilerOpts, DefconstData, DefmacData, DefunData, HelperForm, ImportLongName, LambdaData, LetData, LetFormKind, - LongNameTranslation, ModuleImportSpec, NamespaceData, + LongNameTranslation, ModuleImportListedName, ModuleImportSpec, NamespaceData, }; use crate::compiler::frontend::{generate_type_helpers, HelperFormResult}; use crate::compiler::rename::rename_args_helperform; @@ -150,6 +150,14 @@ pub fn rename_args_named_helper( Ok((pair.0.clone(), rename_args_helperform(&pair.1)?)) } +fn exposed_name_matches(exposed: &ModuleImportListedName, orig_name: &[u8]) -> bool { + if let Some(alias) = exposed.alias.as_ref() { + orig_name == alias + } else { + orig_name == &exposed.name + } +} + pub fn find_helper_target( opts: Rc, helpers: &[HelperForm], @@ -252,8 +260,8 @@ pub fn find_helper_target( } for exposed in x.iter() { - if exposed.name == orig_name { - let target_name = ns_spec.longname.with_child(&child); + if exposed_name_matches(exposed, orig_name) { + let target_name = ns_spec.longname.with_child(exposed.name); if let Some(helper) = find_helper_target( opts.clone(), helpers, diff --git a/src/tests/compiler/modules.rs b/src/tests/compiler/modules.rs index 201a9bd9..6affb5e2 100644 --- a/src/tests/compiler/modules.rs +++ b/src/tests/compiler/modules.rs @@ -540,3 +540,20 @@ fn test_export_foreign_constant() { }], ); } + +#[test] +fn test_import_renamed() { + let filename = "resources/tests/module/test_factorial_renamed.clsp"; + let content = fs::read_to_string(filename).expect("file should exist"); + let hex_filename = "resources/tests/module/test_factorial_renamed.hex"; + + test_compile_and_run_program_with_modules( + filename, + &content, + &[HexArgumentOutcome { + hexfile: hex_filename, + argument: "(5)", + outcome: Some("120"), + }], + ); +}