Skip to content

Commit c03c397

Browse files
committed
[refactoring] Enhance environment to support mutable and non-mutable variables
- Update Environment to differentiate mutable and non-mutable variables: - Add mutable flag to variable storage in Scope - Update lookup to return (bool, Type) tuple indicating mutability - Modify map_variable to require mutability parameter - Add type checking for new statements: - val declaration (non-mutable) - var declaration (mutable) - if-then-else with proper type checking - for loops with type checking - while loops with type checking - Update test suite: - Add tests for mutable/non-mutable variable behavior - Add tests for new statement type checking - Fix existing tests to declare variables before assignment - Clean up source code: - Remove old type checker files (tc/*) - Reorganize type checking logic - Improve error messages
1 parent fbe5981 commit c03c397

File tree

9 files changed

+720
-322
lines changed

9 files changed

+720
-322
lines changed

src/environment/environment.rs

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
use crate::ir::ast::Function;
22
use crate::ir::ast::Name;
3-
use crate::ir::ast::Type;
4-
3+
use crate::ir::ast::ValueConstructor;
54
use std::collections::HashMap;
65
use std::collections::LinkedList;
76

87
#[derive(Clone)]
98
pub struct Scope<A> {
10-
pub variables: HashMap<Name, A>,
9+
pub variables: HashMap<Name, (bool, A)>,
1110
pub functions: HashMap<Name, Function>,
11+
pub adts: HashMap<Name, Vec<ValueConstructor>>,
1212
}
1313

1414
impl<A: Clone> Scope<A> {
1515
fn new() -> Scope<A> {
1616
Scope {
1717
variables: HashMap::new(),
1818
functions: HashMap::new(),
19+
adts: HashMap::new(),
1920
}
2021
}
2122

22-
fn map_variable(&mut self, var: Name, value: A) -> () {
23-
self.variables.insert(var, value);
23+
fn map_variable(&mut self, var: Name, mutable: bool, value: A) -> () {
24+
self.variables.insert(var, (mutable, value));
2425
return ();
2526
}
2627

@@ -29,13 +30,24 @@ impl<A: Clone> Scope<A> {
2930
return ();
3031
}
3132

32-
fn lookup_var(&self, var: &Name) -> Option<&A> {
33-
self.variables.get(var)
33+
fn map_adt(&mut self, name: Name, adt: Vec<ValueConstructor>) -> () {
34+
self.adts.insert(name.clone(), adt);
35+
return ();
36+
}
37+
38+
fn lookup_var(&self, var: &Name) -> Option<(bool, A)> {
39+
self.variables
40+
.get(var)
41+
.map(|(mutable, value)| (*mutable, value.clone()))
3442
}
3543

3644
fn lookup_function(&self, name: &Name) -> Option<&Function> {
3745
self.functions.get(name)
3846
}
47+
48+
fn lookup_adt(&self, name: &Name) -> Option<&Vec<ValueConstructor>> {
49+
self.adts.get(name)
50+
}
3951
}
4052

4153
#[derive(Clone)]
@@ -52,10 +64,10 @@ impl<A: Clone> Environment<A> {
5264
}
5365
}
5466

55-
pub fn map_variable(&mut self, var: Name, value: A) -> () {
67+
pub fn map_variable(&mut self, var: Name, mutable: bool, value: A) -> () {
5668
match self.stack.front_mut() {
57-
None => self.globals.map_variable(var, value),
58-
Some(top) => top.map_variable(var, value),
69+
None => self.globals.map_variable(var, mutable, value),
70+
Some(top) => top.map_variable(var, mutable, value),
5971
}
6072
}
6173

@@ -66,28 +78,40 @@ impl<A: Clone> Environment<A> {
6678
}
6779
}
6880

69-
pub fn lookup(&self, var: &Name) -> Option<&A> {
70-
// First check local scopes in order
81+
pub fn map_adt(&mut self, name: Name, cons: Vec<ValueConstructor>) -> () {
82+
match self.stack.front_mut() {
83+
None => self.globals.map_adt(name, cons),
84+
Some(top) => top.map_adt(name, cons),
85+
}
86+
}
87+
88+
pub fn lookup(&self, var: &Name) -> Option<(bool, A)> {
7189
for scope in self.stack.iter() {
7290
if let Some(value) = scope.lookup_var(var) {
7391
return Some(value);
7492
}
7593
}
76-
// Then check global scope
7794
self.globals.lookup_var(var)
7895
}
7996

8097
pub fn lookup_function(&self, name: &Name) -> Option<&Function> {
81-
// First check local scopes in order
8298
for scope in self.stack.iter() {
8399
if let Some(func) = scope.lookup_function(name) {
84100
return Some(func);
85101
}
86102
}
87-
// Then check global scope
88103
self.globals.lookup_function(name)
89104
}
90105

106+
pub fn lookup_adt(&self, name: &Name) -> Option<&Vec<ValueConstructor>> {
107+
for scope in self.stack.iter() {
108+
if let Some(cons) = scope.lookup_adt(name) {
109+
return Some(cons);
110+
}
111+
}
112+
self.globals.lookup_adt(name)
113+
}
114+
91115
pub fn scoped_function(&self) -> bool {
92116
!self.stack.is_empty()
93117
}
@@ -100,7 +124,7 @@ impl<A: Clone> Environment<A> {
100124
self.stack.pop_front();
101125
}
102126

103-
pub fn get_all_variables(&self) -> Vec<(Name, A)> {
127+
pub fn get_all_variables(&self) -> Vec<(Name, (bool, A))> {
104128
let mut vars = Vec::new();
105129

106130
// First get variables from local scopes (in reverse order to respect shadowing)
@@ -126,37 +150,38 @@ impl<A: Clone> Environment<A> {
126150
#[cfg(test)]
127151
mod tests {
128152
use super::*;
153+
use crate::ir::ast::Type;
129154

130155
#[test]
131156
fn test_variable_scoping() {
132157
let mut env: Environment<i32> = Environment::new();
133158

134159
// Test global scope
135-
env.map_variable("x".to_string(), 32);
136-
assert_eq!(Some(&32), env.lookup(&"x".to_string()));
160+
env.map_variable("x".to_string(), true, 32);
161+
assert_eq!(Some((true, 32)), env.lookup(&"x".to_string()));
137162

138163
// Test nested scopes
139164
env.push(); // scope 1
140-
env.map_variable("y".to_string(), 23);
141-
env.map_variable("x".to_string(), 55); // shadows global x
165+
env.map_variable("y".to_string(), true, 23);
166+
env.map_variable("x".to_string(), true, 55); // shadows global x
142167

143168
env.push(); // scope 2
144-
env.map_variable("z".to_string(), 44);
169+
env.map_variable("z".to_string(), true, 44);
145170

146171
// Variables from all scopes should be accessible
147-
assert_eq!(Some(&55), env.lookup(&"x".to_string())); // from scope 1
148-
assert_eq!(Some(&23), env.lookup(&"y".to_string())); // from scope 1
149-
assert_eq!(Some(&44), env.lookup(&"z".to_string())); // from scope 2
172+
assert_eq!(Some((true, 55)), env.lookup(&"x".to_string())); // from scope 1
173+
assert_eq!(Some((true, 23)), env.lookup(&"y".to_string())); // from scope 1
174+
assert_eq!(Some((true, 44)), env.lookup(&"z".to_string())); // from scope 2
150175

151176
// Pop scope 2
152177
env.pop();
153-
assert_eq!(Some(&55), env.lookup(&"x".to_string())); // still in scope 1
154-
assert_eq!(Some(&23), env.lookup(&"y".to_string())); // still in scope 1
178+
assert_eq!(Some((true, 55)), env.lookup(&"x".to_string())); // still in scope 1
179+
assert_eq!(Some((true, 23)), env.lookup(&"y".to_string())); // still in scope 1
155180
assert_eq!(None, env.lookup(&"z".to_string())); // z is gone
156181

157182
// Pop scope 1
158183
env.pop();
159-
assert_eq!(Some(&32), env.lookup(&"x".to_string())); // back to global x
184+
assert_eq!(Some((true, 32)), env.lookup(&"x".to_string())); // back to global x
160185
assert_eq!(None, env.lookup(&"y".to_string())); // y is gone
161186
}
162187

src/interpreter/interpreter.rs

Lines changed: 91 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ pub fn eval(exp: Expression, env: &Environment<EnvValue>) -> Result<EnvValue, Er
3939
Expression::IsError(e) => eval_iserror_expression(*e, env),
4040
Expression::IsNothing(e) => eval_isnothing_expression(*e, env),
4141
Expression::FuncCall(name, args) => call(name, args, env),
42-
Expression::ADTConstructor(adt_name, constructor_name, args) => {
43-
adtconstructor_eval(adt_name, constructor_name, args, env)
44-
}
42+
// Expression::ADTConstructor(constructor_name, args) => {
43+
// adtconstructor_eval(adt_name, constructor_name, args, env)
44+
// }
4545
_ if is_constant(exp.clone()) => Ok(EnvValue::Exp(exp)),
4646
_ => Err((String::from("Not implemented yet."), None)),
4747
}
@@ -218,7 +218,7 @@ fn execute(stmt: Statement, env: &Environment<EnvValue>) -> Result<ControlFlow,
218218
Ok(ControlFlow::Return(exp_value))
219219
}
220220

221-
Statement::ADTDeclaration(name, constructors) => {
221+
Statement::TypeDeclaration(name, constructors) => {
222222
// Insert the ADT into the new environment
223223
new_env.insert_type(name, constructors);
224224
// Return the new environment along with ControlFlow
@@ -240,95 +240,95 @@ fn execute(stmt: Statement, env: &Environment<EnvValue>) -> Result<ControlFlow,
240240
}
241241
}
242242

243-
fn adtconstructor_eval(
244-
adt_name: Name,
245-
constructor_name: Name,
246-
args: Vec<Box<Expression>>,
247-
env: &Environment<EnvValue>,
248-
) -> Result<EnvValue, (String, Option<Expression>)> {
249-
if let Some(constructors) = env.get_type(&adt_name) {
250-
let value_constructor = constructors.iter().find(|vc| vc.name == constructor_name);
251-
252-
if let Some(vc) = value_constructor {
253-
if vc.types.len() != args.len() {
254-
return Err((
255-
format!(
256-
"Error: Constructor {} expects {} arguments, but received {}",
257-
constructor_name,
258-
vc.types.len(),
259-
args.len()
260-
),
261-
None,
262-
));
263-
}
243+
// fn adtconstructor_eval(
244+
// adt_name: Name,
245+
// constructor_name: Name,
246+
// args: Vec<Box<Expression>>,
247+
// env: &Environment<EnvValue>,
248+
// ) -> Result<EnvValue, (String, Option<Expression>)> {
249+
// if let Some(constructors) = env.get_type(&adt_name) {
250+
// let value_constructor = constructors.iter().find(|vc| vc.name == constructor_name);
251+
252+
// if let Some(vc) = value_constructor {
253+
// if vc.types.len() != args.len() {
254+
// return Err((
255+
// format!(
256+
// "Error: Constructor {} expects {} arguments, but received {}",
257+
// constructor_name,
258+
// vc.types.len(),
259+
// args.len()
260+
// ),
261+
// None,
262+
// ));
263+
// }
264264

265-
let evaluated_args: Result<Vec<Box<Expression>>, (String, Option<Expression>)> = args
266-
.into_iter()
267-
.map(|arg| {
268-
eval(*arg, env).and_then(|res| match res {
269-
EnvValue::Exp(e) => Ok(Box::new(e)),
270-
_ => Err((
271-
String::from("Error: Expected expression in ADT constructor arguments"),
272-
None,
273-
)),
274-
})
275-
})
276-
.collect();
277-
278-
evaluated_args.map(|evaluated| {
279-
EnvValue::Exp(Expression::ADTConstructor(
280-
adt_name,
281-
constructor_name,
282-
evaluated,
283-
))
284-
})
285-
} else {
286-
Err((
287-
format!(
288-
"Error: Constructor {} not found in ADT {}",
289-
constructor_name, adt_name
290-
),
291-
None,
292-
))
293-
}
294-
} else {
295-
Err((format!("Error: ADT {} not found", adt_name), None))
296-
}
297-
}
265+
// let evaluated_args: Result<Vec<Box<Expression>>, (String, Option<Expression>)> = args
266+
// .into_iter()
267+
// .map(|arg| {
268+
// eval(*arg, env).and_then(|res| match res {
269+
// EnvValue::Exp(e) => Ok(Box::new(e)),
270+
// _ => Err((
271+
// String::from("Error: Expected expression in ADT constructor arguments"),
272+
// None,
273+
// )),
274+
// })
275+
// })
276+
// .collect();
277+
278+
// evaluated_args.map(|evaluated| {
279+
// EnvValue::Exp(Expression::ADTConstructor(
280+
// adt_name,
281+
// constructor_name,
282+
// evaluated,
283+
// ))
284+
// })
285+
// } else {
286+
// Err((
287+
// format!(
288+
// "Error: Constructor {} not found in ADT {}",
289+
// constructor_name, adt_name
290+
// ),
291+
// None,
292+
// ))
293+
// }
294+
// } else {
295+
// Err((format!("Error: ADT {} not found", adt_name), None))
296+
// }
297+
// }
298298

299-
fn matches_pattern(
300-
value: &EnvValue,
301-
pattern: &Expression,
302-
env: &Environment<EnvValue>,
303-
) -> Result<bool, ErrorMessage> {
304-
match (value, pattern) {
305-
// Caso o padrão seja um construtor de ADT
306-
(
307-
EnvValue::Exp(Expression::ADTConstructor(adt_name1, constructor_name1, args1)),
308-
Expression::ADTConstructor(adt_name2, constructor_name2, args2),
309-
) => {
310-
// Verifica se o nome do ADT e o construtor correspondem
311-
if adt_name1 == adt_name2 && constructor_name1 == constructor_name2 {
312-
// Verifica se os argumentos correspondem
313-
for (arg1, arg2) in args1.iter().zip(args2.iter()) {
314-
let arg_value = eval(*arg1.clone(), env)?;
315-
if !matches_pattern(&arg_value, arg2, env)? {
316-
return Ok(false);
317-
}
318-
}
319-
Ok(true)
320-
} else {
321-
Ok(false)
322-
}
323-
}
299+
// fn matches_pattern(
300+
// value: &EnvValue,
301+
// pattern: &Expression,
302+
// env: &Environment<EnvValue>,
303+
// ) -> Result<bool, ErrorMessage> {
304+
// match (value, pattern) {
305+
// // Caso o padrão seja um construtor de ADT
306+
// (
307+
// EnvValue::Exp(Expression::ADTConstructor(adt_name1, constructor_name1, args1)),
308+
// Expression::ADTConstructor(adt_name2, constructor_name2, args2),
309+
// ) => {
310+
// // Verifica se o nome do ADT e o construtor correspondem
311+
// if adt_name1 == adt_name2 && constructor_name1 == constructor_name2 {
312+
// // Verifica se os argumentos correspondem
313+
// for (arg1, arg2) in args1.iter().zip(args2.iter()) {
314+
// let arg_value = eval(*arg1.clone(), env)?;
315+
// if !matches_pattern(&arg_value, arg2, env)? {
316+
// return Ok(false);
317+
// }
318+
// }
319+
// Ok(true)
320+
// } else {
321+
// Ok(false)
322+
// }
323+
// }
324324

325-
// Caso o padrão seja uma constante (como um número ou booleano)
326-
(EnvValue::Exp(exp1), exp2) if is_constant(exp2.clone()) => Ok(exp1 == exp2),
325+
// // Caso o padrão seja uma constante (como um número ou booleano)
326+
// (EnvValue::Exp(exp1), exp2) if is_constant(exp2.clone()) => Ok(exp1 == exp2),
327327

328-
// Outros casos podem ser adicionados aqui (como variáveis, etc.)
329-
_ => Err(("Pattern not supported".to_string(), None)),
330-
}
331-
}
328+
// // Outros casos podem ser adicionados aqui (como variáveis, etc.)
329+
// _ => Err(("Pattern not supported".to_string(), None)),
330+
// }
331+
// }
332332

333333
//helper function for executing blocks
334334
fn execute_block(
@@ -378,13 +378,13 @@ fn call(
378378
format!(
379379
"[Runtime Error on '{}()'] missing argument '{}'.",
380380
env.scope_name(),
381-
formal_arg.argumentName
381+
formal_arg.argument_name
382382
),
383383
None,
384384
));
385385
}
386386
let arg_value = eval(args[i].clone(), env)?;
387-
new_env.insert_variable(formal_arg.argumentName.clone(), arg_value);
387+
new_env.insert_variable(formal_arg.argument_name.clone(), arg_value);
388388
}
389389

390390
if args.len() > func.params.len() {

0 commit comments

Comments
 (0)