@@ -18,6 +18,7 @@ use std::{
1818use ecow:: { eco_vec, EcoString , EcoVec } ;
1919use indexmap:: IndexMap ;
2020use instant:: Duration ;
21+ use serde:: { Deserialize , Serialize } ;
2122
2223use crate :: {
2324 algorithm:: invert:: { invert_instrs, under_instrs} ,
@@ -55,7 +56,7 @@ pub struct Compiler {
5556 /// The paths of files currently being imported (used to detect import cycles)
5657 current_imports : Vec < PathBuf > ,
5758 /// The bindings of imported files
58- imports : HashMap < PathBuf , Import > ,
59+ imports : HashMap < PathBuf , Module > ,
5960 /// Unexpanded stack macros
6061 stack_macros : HashMap < usize , StackMacro > ,
6162 /// Unexpanded array macros
@@ -108,14 +109,14 @@ impl Default for Compiler {
108109 }
109110}
110111
111- /// An imported module
112- #[ derive( Clone ) ]
113- pub struct Import {
112+ /// A Uiua module
113+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
114+ pub struct Module {
114115 /// The top level comment
115116 pub comment : Option < EcoString > ,
116117 /// Map module-local names to global indices
117118 names : IndexMap < Ident , LocalName > ,
118- /// Whether the import uses experimental features
119+ /// Whether the module uses experimental features
119120 experimental : bool ,
120121}
121122
@@ -173,7 +174,9 @@ pub(crate) struct Scope {
173174
174175#[ derive( Clone , Copy , PartialEq , Eq ) ]
175176enum ScopeKind {
176- /// A scope at the top level of a file or in a named module
177+ /// A scope at the top level of a file
178+ File ,
179+ /// A scope in a named module
177180 Module ,
178181 /// A temporary scope, probably for a macro
179182 Temp ,
@@ -184,7 +187,7 @@ enum ScopeKind {
184187impl Default for Scope {
185188 fn default ( ) -> Self {
186189 Self {
187- kind : ScopeKind :: Module ,
190+ kind : ScopeKind :: File ,
188191 file_path : None ,
189192 comment : None ,
190193 names : IndexMap :: new ( ) ,
@@ -197,7 +200,7 @@ impl Default for Scope {
197200}
198201
199202/// The index of a named local in the bindings, and whether it is public
200- #[ derive( Clone , Copy ) ]
203+ #[ derive( Debug , Clone , Copy , Serialize , Deserialize ) ]
201204pub ( crate ) struct LocalName {
202205 pub index : usize ,
203206 pub public : bool ,
@@ -351,15 +354,15 @@ impl Compiler {
351354 & mut self ,
352355 kind : ScopeKind ,
353356 f : impl FnOnce ( & mut Self ) -> UiuaResult < T > ,
354- ) -> UiuaResult < Import > {
357+ ) -> UiuaResult < Module > {
355358 let experimental = self . scope . experimental ;
356359 self . higher_scopes . push ( take ( & mut self . scope ) ) ;
357360 self . scope . kind = kind;
358361 self . scope . experimental = experimental;
359362 let res = f ( self ) ;
360363 let scope = replace ( & mut self . scope , self . higher_scopes . pop ( ) . unwrap ( ) ) ;
361364 res?;
362- Ok ( Import {
365+ Ok ( Module {
363366 comment : scope. comment ,
364367 names : scope. names ,
365368 experimental : scope. experimental ,
@@ -493,17 +496,9 @@ code:
493496 ( words. iter ( ) ) . any ( |w| matches ! ( & w. value, Word :: SemanticComment ( _) ) )
494497 }
495498 let mut lines = match item {
496- Item :: Module ( module) => {
497- prev_comment. take ( ) ;
498- let is_test =
499- ( module. value . name . as_ref ( ) ) . map_or ( true , |name| name. value == "test" ) ;
500- let scope_kind = if is_test {
501- ScopeKind :: Test
502- } else {
503- ScopeKind :: Module
504- } ;
505- self . in_scope ( scope_kind, |env| env. items ( module. value . items , true ) ) ?;
506- return Ok ( ( ) ) ;
499+ Item :: Module ( m) => {
500+ let prev_com = prev_comment. take ( ) ;
501+ return self . module ( m, prev_com) ;
507502 }
508503 Item :: Words ( lines) => lines,
509504 Item :: Binding ( binding) => {
@@ -777,13 +772,13 @@ code:
777772 format ! ( "Cycle detected importing {}" , path. to_string_lossy( ) ) ,
778773 ) ) ;
779774 }
780- let import = self . in_scope ( ScopeKind :: Module , |env| {
775+ let import = self . in_scope ( ScopeKind :: File , |env| {
781776 env. load_str_src ( & input, & path) . map ( drop)
782777 } ) ?;
783778 self . imports . insert ( path. clone ( ) , import) ;
784779 }
785- let import = self . imports . get ( & path) . unwrap ( ) ;
786- if import . experimental {
780+ let module = self . imports . get ( & path) . unwrap ( ) ;
781+ if module . experimental {
787782 self . experimental_error ( span, || {
788783 format ! (
789784 "Module `{path_str}` is experimental. \
@@ -811,6 +806,37 @@ code:
811806 pathdiff:: diff_paths ( & target, base) . unwrap_or ( target)
812807 }
813808 }
809+ fn module ( & mut self , m : Sp < ScopedModule > , prev_com : Option < EcoString > ) -> UiuaResult {
810+ let m = m. value ;
811+ let scope_kind = match m. kind {
812+ ModuleKind :: Named ( _) => ScopeKind :: Module ,
813+ ModuleKind :: Test => ScopeKind :: Test ,
814+ } ;
815+ let in_test = matches ! ( m. kind, ModuleKind :: Test ) ;
816+ let module = self . in_scope ( scope_kind, |env| env. items ( m. items , in_test) ) ?;
817+ match m. kind {
818+ ModuleKind :: Named ( name) => {
819+ let global_index = self . next_global ;
820+ self . next_global += 1 ;
821+ let local = LocalName {
822+ index : global_index,
823+ public : true ,
824+ } ;
825+ let comment = prev_com
826+ . or_else ( || module. comment . clone ( ) )
827+ . map ( |text| DocComment :: from ( text. as_str ( ) ) ) ;
828+ self . asm . add_global_at (
829+ local,
830+ BindingKind :: Module ( module) ,
831+ Some ( name. span . clone ( ) ) ,
832+ comment,
833+ ) ;
834+ self . scope . names . insert ( name. value . clone ( ) , local) ;
835+ }
836+ ModuleKind :: Test => { }
837+ }
838+ Ok ( ( ) )
839+ }
814840 fn compile_words ( & mut self , words : Vec < Sp < Word > > , call : bool ) -> UiuaResult < EcoVec < Instr > > {
815841 let words = unsplit_words ( split_words ( words) )
816842 . into_iter ( )
@@ -1482,16 +1508,12 @@ code:
14821508 }
14831509 fn ref_local ( & self , r : & Ref ) -> UiuaResult < ( Vec < LocalName > , LocalName ) > {
14841510 if let Some ( ( module, path_locals) ) = self . ref_path ( & r. path , r. in_macro_arg ) ? {
1485- if let Some ( local) = self . imports [ & module] . names . get ( & r. name . value ) . copied ( ) {
1511+ if let Some ( local) = module. names . get ( & r. name . value ) . copied ( ) {
14861512 Ok ( ( path_locals, local) )
14871513 } else {
14881514 Err ( self . fatal_error (
14891515 r. name . span . clone ( ) ,
1490- format ! (
1491- "Item `{}` not found in module `{}`" ,
1492- r. name. value,
1493- module. display( )
1494- ) ,
1516+ format ! ( "Item `{}` not found" , r. name. value, ) ,
14951517 ) )
14961518 }
14971519 } else if let Some ( local) = self . find_name ( & r. name . value , r. in_macro_arg ) {
@@ -1511,8 +1533,8 @@ code:
15111533 }
15121534 let mut hit_file = false ;
15131535 for scope in self . higher_scopes . iter ( ) . rev ( ) {
1514- if scope. kind == ScopeKind :: Module {
1515- if hit_file || self . scope . kind == ScopeKind :: Module {
1536+ if scope. kind == ScopeKind :: File {
1537+ if hit_file || self . scope . kind == ScopeKind :: File {
15161538 break ;
15171539 }
15181540 hit_file = true ;
@@ -1527,7 +1549,7 @@ code:
15271549 & self ,
15281550 path : & [ RefComponent ] ,
15291551 skip_local : bool ,
1530- ) -> UiuaResult < Option < ( PathBuf , Vec < LocalName > ) > > {
1552+ ) -> UiuaResult < Option < ( & Module , Vec < LocalName > ) > > {
15311553 let Some ( first) = path. first ( ) else {
15321554 return Ok ( None ) ;
15331555 } ;
@@ -1543,6 +1565,7 @@ code:
15431565 path_locals. push ( module_local) ;
15441566 let global = & self . asm . bindings [ module_local. index ] . kind ;
15451567 let mut module = match global {
1568+ BindingKind :: Import ( path) => & self . imports [ path] ,
15461569 BindingKind :: Module ( module) => module,
15471570 BindingKind :: Func ( _) => {
15481571 return Err ( self . fatal_error (
@@ -1564,23 +1587,20 @@ code:
15641587 }
15651588 } ;
15661589 for comp in path. iter ( ) . skip ( 1 ) {
1567- let submod_local = self . imports [ module]
1590+ let submod_local = module
15681591 . names
15691592 . get ( & comp. module . value )
15701593 . copied ( )
15711594 . ok_or_else ( || {
15721595 self . fatal_error (
15731596 comp. module . span . clone ( ) ,
1574- format ! (
1575- "Module `{}` not found in module `{}`" ,
1576- comp. module. value,
1577- module. display( )
1578- ) ,
1597+ format ! ( "Module `{}` not found" , comp. module. value) ,
15791598 )
15801599 } ) ?;
15811600 path_locals. push ( submod_local) ;
15821601 let global = & self . asm . bindings [ submod_local. index ] . kind ;
15831602 module = match global {
1603+ BindingKind :: Import ( path) => & self . imports [ path] ,
15841604 BindingKind :: Module ( module) => module,
15851605 BindingKind :: Func ( _) => {
15861606 return Err ( self . fatal_error (
@@ -1603,7 +1623,7 @@ code:
16031623 } ;
16041624 }
16051625
1606- Ok ( Some ( ( module. clone ( ) , path_locals) ) )
1626+ Ok ( Some ( ( module, path_locals) ) )
16071627 }
16081628 fn reference ( & mut self , r : Ref , call : bool ) -> UiuaResult {
16091629 if r. path . is_empty ( ) {
@@ -1708,7 +1728,9 @@ code:
17081728 self . push_instr ( Instr :: Call ( span) ) ;
17091729 }
17101730 }
1711- BindingKind :: Module { .. } => self . add_error ( span, "Cannot import module item here." ) ,
1731+ BindingKind :: Import { .. } | BindingKind :: Module ( _) => {
1732+ self . add_error ( span, "Cannot import module item here." )
1733+ }
17121734 BindingKind :: Macro => {
17131735 // We could error here, but it's easier to handle it higher up
17141736 }
0 commit comments