@@ -36,6 +36,45 @@ impl std::fmt::Display for EvalError {
3636 }
3737}
3838
39+ fn ctx_get < ' a > ( context : & ' a Context , name : & str ) -> Option < & ' a Expr > {
40+ for scope in context. iter ( ) . rev ( ) {
41+ if let Some ( v) = scope. get ( name) {
42+ return Some ( v) ;
43+ }
44+ }
45+
46+ None
47+ }
48+
49+ fn ctx_def ( context : & mut Context , name : String , value : Expr ) {
50+ if let Some ( scope) = context. last_mut ( ) {
51+ scope. insert ( name, value) ;
52+ }
53+ }
54+
55+ fn ctx_set ( context : & mut Context , name : & str , value : Expr ) {
56+ for scope in context. iter_mut ( ) . rev ( ) {
57+ if scope. contains_key ( name) {
58+ scope. insert ( name. to_string ( ) , value) ;
59+ return ;
60+ }
61+ }
62+ }
63+
64+ fn ctx_contains ( context : & Context , name : & str ) -> bool {
65+ for scope in context. iter ( ) . rev ( ) {
66+ if scope. contains_key ( name) {
67+ return true ;
68+ }
69+ }
70+
71+ false
72+ }
73+
74+ fn ctx_keys_iter ( context : & Context ) -> impl Iterator < Item = & String > {
75+ context. iter ( ) . flat_map ( |scope| scope. keys ( ) )
76+ }
77+
3978fn find_closest < ' a > ( name : & str , options : impl Iterator < Item = & ' a String > ) -> Option < String > {
4079 let options: Vec < & String > = options. collect ( ) ;
4180
@@ -100,7 +139,11 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
100139 None => Err ( EvalError {
101140 message : format ! ( "object has no method named '{}'" , property) ,
102141 message_short : "no such property" . to_string ( ) ,
103- help_message : find_closest ( property, properties. keys ( ) ) . map ( |s| format ! ( "did you mean '{}'?" , s) ) ,
142+ help_message : {
143+ let mut names = crate :: builtins:: object:: list_fns ( ) ;
144+ names. extend ( properties. keys ( ) . cloned ( ) ) ;
145+ find_closest ( property, names. iter ( ) ) . map ( |s| format ! ( "did you mean '{}'?" , s) )
146+ } ,
104147 span : expr. span ,
105148 } ) ,
106149 }
@@ -354,12 +397,12 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
354397 }
355398
356399 Expr :: Identifier ( name) => {
357- match context . get ( name) {
400+ match ctx_get ( context , name) {
358401 Some ( value) => Ok ( Flow :: Continue ( value. clone ( ) ) ) ,
359402 None => Err ( EvalError {
360403 message : format ! ( "undefined variable '{}'" , name) ,
361404 message_short : "not defined" . to_string ( ) ,
362- help_message : find_closest ( name, context . keys ( ) ) . map ( |s| format ! ( "did you mean '{}'?" , s) ) ,
405+ help_message : find_closest ( name, ctx_keys_iter ( context ) ) . map ( |s| format ! ( "did you mean '{}'?" , s) ) ,
363406 span : expr. span ,
364407 } ) ,
365408 }
@@ -441,7 +484,7 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
441484 match & callee. node {
442485 Expr :: PropertyAccess { object, property : _ } => {
443486 if let Expr :: Identifier ( obj_name) = & object. node {
444- context . insert ( obj_name. clone ( ) , replace_self) ;
487+ ctx_set ( context , obj_name, replace_self) ;
445488 }
446489 }
447490
@@ -488,11 +531,14 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
488531 }
489532
490533 let mut new_context = context. clone ( ) ;
534+ let mut scope = HashMap :: new ( ) ;
491535
492536 for ( i, arg_name) in args. iter ( ) . enumerate ( ) {
493- new_context . insert ( arg_name. clone ( ) , evaluated_args[ i] . node . clone ( ) ) ;
537+ scope . insert ( arg_name. clone ( ) , evaluated_args[ i] . node . clone ( ) ) ;
494538 }
495539
540+ new_context. push ( scope) ;
541+
496542 match eval ( & * body, & mut new_context, depth) ? {
497543 Flow :: Continue ( v) => Ok ( Flow :: Continue ( v) ) ,
498544 Flow :: Return ( v) => Ok ( Flow :: Continue ( v) ) ,
@@ -544,7 +590,7 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
544590
545591 Expr :: Let { name, value } => {
546592 let value = eval ( value, context, depth) ?. unwrap ( ) ;
547- context . insert ( name. clone ( ) , value) ;
593+ ctx_def ( context , name. clone ( ) , value) ;
548594
549595 Ok ( Flow :: Continue ( Expr :: Null ) )
550596 }
@@ -556,7 +602,7 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
556602 None => {
557603 match & target. node {
558604 Expr :: Identifier ( name) => {
559- if !context . contains_key ( name) {
605+ if !ctx_contains ( context , name) {
560606 return Err ( EvalError {
561607 message : format ! ( "undefined variable '{}'" , name) ,
562608 message_short : "undefined" . to_string ( ) ,
@@ -696,7 +742,7 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
696742 }
697743
698744 Expr :: Function { name, args, body } => {
699- context . insert ( name. clone ( ) , Expr :: Function {
745+ ctx_def ( context , name. clone ( ) , Expr :: Function {
700746 name : name. clone ( ) ,
701747 args : args. clone ( ) ,
702748 body : body. clone ( ) ,
@@ -706,7 +752,7 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
706752 }
707753
708754 Expr :: Block ( exprs) => {
709- let preexisting_keys = context. keys ( ) . cloned ( ) . collect :: < Vec < String > > ( ) ;
755+ context. push ( HashMap :: new ( ) ) ;
710756
711757 for e in exprs {
712758 match eval ( e, context, depth) ? {
@@ -717,11 +763,7 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
717763 }
718764 }
719765
720- for key in context. keys ( ) . cloned ( ) . collect :: < Vec < String > > ( ) {
721- if !preexisting_keys. contains ( & key) {
722- context. remove ( & key) ;
723- }
724- }
766+ context. pop ( ) ;
725767
726768 Ok ( Flow :: Continue ( Expr :: Null ) )
727769 }
@@ -769,7 +811,7 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
769811 } ;
770812
771813 for i in start..end {
772- context . insert ( iterator_name. clone ( ) , Expr :: Int ( i) ) ;
814+ ctx_def ( context , iterator_name. clone ( ) , Expr :: Int ( i) ) ;
773815
774816 match eval ( body, context, depth) ? {
775817 Flow :: Continue ( _) => { } ,
@@ -810,7 +852,7 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
810852 } ;
811853
812854 for i in start..=end {
813- context . insert ( iterator_name. clone ( ) , Expr :: Int ( i) ) ;
855+ ctx_def ( context , iterator_name. clone ( ) , Expr :: Int ( i) ) ;
814856
815857 match eval ( body, context, depth) ? {
816858 Flow :: Continue ( _) => { } ,
@@ -826,7 +868,7 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
826868 Expr :: Array ( elements) => {
827869 for element in elements {
828870 let value = eval ( & element, context, depth) ?. unwrap ( ) ;
829- context . insert ( iterator_name. clone ( ) , value) ;
871+ ctx_def ( context , iterator_name. clone ( ) , value) ;
830872
831873 match eval ( body, context, depth) ? {
832874 Flow :: Continue ( _) => { } ,
@@ -1087,16 +1129,16 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
10871129 path. pop ( ) ;
10881130 }
10891131
1090- if context . contains_key ( "CURRENTLY_PARSING_MODULE_PATH" ) {
1091- if let Expr :: String ( current_module_path) = context . get ( "CURRENTLY_PARSING_MODULE_PATH" ) . unwrap ( ) {
1132+ if ctx_contains ( context , "CURRENTLY_PARSING_MODULE_PATH" ) {
1133+ if let Expr :: String ( current_module_path) = ctx_get ( context , "CURRENTLY_PARSING_MODULE_PATH" ) . unwrap ( ) {
10921134 let mut module_path = std:: path:: PathBuf :: from ( current_module_path) ;
10931135 module_path. pop ( ) ;
10941136 path = module_path;
10951137 }
10961138 }
10971139
1098- if context . contains_key ( "CURRENTLY_PARSING_PACKAGE_NAME" ) {
1099- if let Expr :: String ( current_package_name) = context . get ( "CURRENTLY_PARSING_PACKAGE_NAME" ) . unwrap ( ) {
1140+ if ctx_contains ( context , "CURRENTLY_PARSING_PACKAGE_NAME" ) {
1141+ if let Expr :: String ( current_package_name) = ctx_get ( context , "CURRENTLY_PARSING_PACKAGE_NAME" ) . unwrap ( ) {
11001142 path. push ( ".modu" ) ;
11011143 path. push ( "packages" ) ;
11021144 path. push ( current_package_name) ;
@@ -1125,29 +1167,43 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
11251167 } ) ?;
11261168
11271169 let mut new_context = crate :: utils:: create_context ( ) ;
1128- new_context. insert (
1170+
1171+ new_context[ 0 ] . insert (
11291172 "CURRENTLY_PARSING_MODULE_PATH" . to_string ( ) ,
11301173 Expr :: String ( path. to_str ( ) . unwrap ( ) . to_string ( ) )
11311174 ) ;
11321175
1176+ new_context. push ( HashMap :: new ( ) ) ;
1177+
11331178 crate :: parser:: parse ( & source, path. to_str ( ) . unwrap ( ) , & mut new_context) ;
11341179
11351180 if import_as == "*" {
1136- for ( k, v) in new_context {
1137- context. insert ( k, v) ;
1181+ let base_scope = & new_context[ 0 ] ;
1182+
1183+ for scope in & new_context {
1184+ for ( k, v) in scope {
1185+ if !base_scope. contains_key ( k) {
1186+ ctx_def ( context, k. clone ( ) , v. clone ( ) ) ;
1187+ }
1188+ }
11381189 }
11391190 } else {
11401191 let mut symbols = HashMap :: new ( ) ;
1192+ let base_scope = & new_context[ 0 ] ;
11411193
1142- for ( k, v) in new_context. iter ( ) . filter ( |( k, _) | !crate :: utils:: create_context ( ) . contains_key ( * k) ) {
1143- symbols. insert ( k. clone ( ) , SpannedExpr {
1144- node : v. clone ( ) ,
1145- span : expr. span ,
1146- } ) ;
1194+ for scope in & new_context {
1195+ for ( k, v) in scope {
1196+ if !base_scope. contains_key ( k) {
1197+ symbols. insert ( k. clone ( ) , SpannedExpr {
1198+ node : v. clone ( ) ,
1199+ span : expr. span ,
1200+ } ) ;
1201+ }
1202+ }
11471203 }
11481204
1149- context . insert ( import_as. clone ( ) . replace ( ".modu" , "" ) , Expr :: Module {
1150- symbols,
1205+ ctx_def ( context , import_as. clone ( ) . replace ( ".modu" , "" ) , Expr :: Module {
1206+ symbols
11511207 } ) ;
11521208 }
11531209 } else {
@@ -1156,7 +1212,7 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
11561212 if import_as == "*" {
11571213 if let Expr :: Module { symbols } = module {
11581214 for ( k, v) in symbols {
1159- context. insert ( k , v. node ) ;
1215+ ctx_def ( context, k . clone ( ) , v. node . clone ( ) ) ;
11601216 }
11611217 } else {
11621218 return Err ( EvalError {
@@ -1167,7 +1223,7 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
11671223 } ) ;
11681224 }
11691225 } else {
1170- context . insert ( import_as. clone ( ) , module) ;
1226+ ctx_def ( context , import_as. clone ( ) , module) ;
11711227 }
11721228 }
11731229
@@ -1195,32 +1251,47 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
11951251 } ) ?;
11961252
11971253 let mut new_context = crate :: utils:: create_context ( ) ;
1198- new_context. insert (
1254+ let mut pkg_scope = HashMap :: new ( ) ;
1255+
1256+ pkg_scope. insert (
11991257 "CURRENTLY_PARSING_PACKAGE_PATH" . to_string ( ) ,
12001258 Expr :: String ( path. to_str ( ) . unwrap ( ) . to_string ( ) )
12011259 ) ;
1202- new_context . insert (
1260+ pkg_scope . insert (
12031261 "CURRENTLY_PARSING_PACKAGE_NAME" . to_string ( ) ,
12041262 Expr :: String ( name. clone ( ) ) ,
12051263 ) ;
12061264
1265+ new_context. push ( pkg_scope) ;
1266+
12071267 crate :: parser:: parse ( & source, path. to_str ( ) . unwrap ( ) , & mut new_context) ;
12081268
12091269 if import_as == "*" {
1210- for ( k, v) in new_context {
1211- context. insert ( k, v) ;
1270+ let base_scope = & new_context[ 0 ] ;
1271+
1272+ for scope in & new_context {
1273+ for ( k, v) in scope {
1274+ if !base_scope. contains_key ( k) {
1275+ ctx_def ( context, k. clone ( ) , v. clone ( ) ) ;
1276+ }
1277+ }
12121278 }
12131279 } else {
12141280 let mut symbols = HashMap :: new ( ) ;
1215-
1216- for ( k, v) in new_context. iter ( ) . filter ( |( k, _) | !crate :: utils:: create_context ( ) . contains_key ( * k) ) {
1217- symbols. insert ( k. clone ( ) , SpannedExpr {
1218- node : v. clone ( ) ,
1219- span : expr. span ,
1220- } ) ;
1281+ let base_scope = & new_context[ 0 ] ;
1282+
1283+ for scope in & new_context {
1284+ for ( k, v) in scope {
1285+ if !base_scope. contains_key ( k) {
1286+ symbols. insert ( k. clone ( ) , SpannedExpr {
1287+ node : v. clone ( ) ,
1288+ span : expr. span ,
1289+ } ) ;
1290+ }
1291+ }
12211292 }
12221293
1223- context . insert ( import_as. clone ( ) . replace ( ".modu" , "" ) , Expr :: Module {
1294+ ctx_def ( context , import_as. clone ( ) . replace ( ".modu" , "" ) , Expr :: Module {
12241295 symbols,
12251296 } ) ;
12261297 }
@@ -1571,7 +1642,8 @@ pub fn eval<'src>(expr: &'src SpannedExpr, context: &mut Context, depth: usize)
15711642fn eval_assign_target ( target : & SpannedExpr , new_value : SpannedExpr , context : & mut Context , span : & Span ) -> Result < ( ) , EvalError > {
15721643 match & target. node {
15731644 Expr :: Identifier ( name) => {
1574- context. insert ( name. clone ( ) , new_value. node ) ;
1645+ ctx_set ( context, & name, new_value. node ) ;
1646+
15751647 Ok ( ( ) )
15761648 }
15771649
0 commit comments