Skip to content

Commit 7204fa6

Browse files
committed
make the context have stack-based scoping
1 parent b6d2a5a commit 7204fa6

File tree

1 file changed

+117
-45
lines changed

1 file changed

+117
-45
lines changed

lang/src/eval.rs

Lines changed: 117 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
3978
fn 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)
15711642
fn 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

Comments
 (0)