The lambda/function code does not work

I am writing a lisp interpreter in rust. I have experienced a problem with function/lambda code:

fn main() {
    let expr = /* EXPRESSION TO TEST */;
    println!("Ret > {}", eval(expr));
}
#[derive(Clone, Debug, PartialEq)]
struct Token {
    expr: Expr,
    row: usize,
    col: usize,
    file: String
}

/* Expr enum: the lisp expression*/
#[derive(Clone, Debug, PartialEq)]
enum Expr {
    Symbol(String),
    Number(f64),
    String(String),
    List(Vec<Expr>),
    Bool(bool),
    Lambda(Vec<Expr>,Vec<Expr>), // args, body
    Function(Vec<Expr>) 
}

/* Scope struct for holding variables and function */
#[derive(Clone, Debug)]
struct Scope {
    env: HashMap<String, ScopeEntry>,
}

/* Scope entry for holding scopes*/
#[derive(Debug, Clone)]
struct ScopeEntry {
    val: Expr,
    constant: bool,
}

/* Program scope*/
impl Scope {
    fn new() -> Self { // New object
	Scope { env: HashMap::new() }
    }
    fn get(&self, name: &str) -> Option<Expr> { // Get a value
	Some(self
	    .env
	    .get(name)
	    .unwrap()
	    .val
	    .clone() 
	)
    }
    fn set(&mut self, name: String, val: ScopeEntry) {
	if let Some(entry) = self.env.get(&name) {
            if self.constant(entry.clone()) {
		panic!("Cannot override constant!");
            }
	}
	self.env.insert(name, val);
    }
    fn contains(&mut self, name: String) -> bool {
	self.env.contains_key(&name)
    }
    fn constant(&self, s: ScopeEntry) -> bool {
	s.constant
    }
}

/* Implement the disply trait for Expr.*/
impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	write!(f, "{}",
	       match self {
		   Expr::Symbol(s) => s.clone(),
		   Expr::Number(n) => n.to_string(),
		   Expr::String(s) => s.clone(),
		   Expr::Bool(b) => match b {
		       true => String::from("t"),
		       false => String::from("nil"),
		   }
		   Expr::List(items) => {
		       let mut Str = String::from("(");
		       for i in items {
			   Str.push_str(format!("{} ",i).as_str());
		       }
		       let trimmed = Str.trim();
		       Str = trimmed.to_string();
		       Str.push_str(")");
		       Str
		   }
		   Expr::Lambda(_, _) => {
		       let addr = self as *const Self as usize; // Get mem loc 
		       String::from(format!(
			   "#<LAMBDA @{:x}>", addr
		       ))
		   }
		   _ => String::from("todo")
		   
	       }
	)
    }
}

/* lookup: easier way of looking up.*/
fn lookup(name: &str, env_stack: &[Rc<RefCell<Scope>>]) -> Option<Expr> {
    for scope in env_stack.iter().rev() {
        if let Some(val) = scope.borrow().get(name) {
            return Some(val);
        }
    }
    None
}


pub fn eval(expr: Token, env: &mut Vec<Rc<RefCell<Scope>>>,trace: bool) -> Expr {
    let lazy: Vec<Expr> = vec![
	Expr::Symbol("lambda".to_string())
    ];
    if trace {
	println!(">> EVAL: {:?}", expr.expr.clone());
    }
    match expr.expr {
	Expr::Symbol(s) => {
	    lookup(&s,env).expect("Unknown")
	}
	/*Expr::QSymbol(s) => {
	    Expr::Symbol(s)
	}*/
	Expr::Function(ARGS) => {
	    let mut name = ARGS[0].clone();
	    let mut args = vec![];
	    if !(lazy.contains(&name)) {
		for i in &ARGS[1..] {
		    if trace {
			println!("About to evaluate arg: {:?}", i.clone());
		    }
		    args.push(
			eval(
			    Token {
				expr: i.clone(),
				row: expr.row,
				col: expr.col,
				file: expr.file.clone(),
			    },
			    env,
			    trace
			)
		    )
		}
	    } else if trace {
		println!("{} requires lazy evaluation, therefore no arg was evaled",name.clone());
		args = ARGS[1..].to_vec();
	    } else {
		args = ARGS[1..].to_vec();
	    }
	    let mut ret = Expr::Bool(false);
	    env.push(Rc::new(RefCell::new(Scope::new())));
	    // OUT/IN FUNCTIONS
	    if name == Expr::Symbol("print".to_string()) {
		for i in args {
		    print!("{}",i)
		};
		ret = Expr::Bool(false);
            // SYMBOL & LAMBDA FUNCTIONS
            } else if name == Expr::Symbol("set".to_string()) {
                // Manually evaluate args inside set branch
                // First arg must be a quoted symbol as is (not evaluated)
                match &ARGS[1] {
                    Expr::List(S) => {
			match &S[0] {
			    Expr::Symbol(s) => {
				if trace {
				    println!("In set! symbol = {}", s.clone());
                        }

                        // Evaluate second argument now
                        let val = eval(
                            Token {
                                expr: ARGS[2].clone(),
                                row: expr.row,
                                col: expr.col,
                                file: expr.file.clone(),
                            },
                            env,
                            trace);
				env[0].borrow_mut().set(s.clone(), ScopeEntry {
				    val: val.clone(),
				    constant: false,
				});
				ret = val;
			    }
			    _ => panic!("Expected quoted Symbol for set")
			}
                    }
                    _ => panic!("Expected quoted Symbol for set"),
		}
	    } else if name == Expr::Symbol("let".to_string()) {
                // Manually evaluate args inside set branch
                // First arg must be a quoted symbol as is (not evaluated)
                match &ARGS[1] {
                    Expr::List(S) => {
			match &S[0] {
			    Expr::Symbol(s) => {
				if trace {
				    println!("In let! symbol = {}", s.clone());
                        }

                        // Evaluate second argument now
                        let val = eval(
                            Token {
                                expr: ARGS[2].clone(),
                                row: expr.row,
                                col: expr.col,
                                file: expr.file.clone(),
                            },
                            env,
                            trace,
                        );

                        env[env.len()-2].borrow_mut().set(s.clone(), ScopeEntry {
			    val: val.clone(),
			    constant: false,
			});
                        ret = val;
			    }
			    _ => panic!("Expected quoted Symbol for let")
			}
                    }
                    _ => panic!("Expected quoted Symbol for let"),
		}
	    } else if name == Expr::Symbol("defconst".to_string()) {
                // Manually evaluate args inside set branch
                // First arg must be a quoted symbol as is (not evaluated)
                match &ARGS[1] {
                    Expr::List(S) => {
			match &S[0] {
			    Expr::Symbol(s) => {
				if trace {
				    println!("In defconst! symbol = {}", s.clone());
                        }

                        // Evaluate second argument now
                        let val = eval(
                            Token {
                                expr: ARGS[2].clone(),
                                row: expr.row,
                                col: expr.col,
                                file: expr.file.clone(),
                            },
                            env,
                            trace,
                        );

                        env[env.len()-2].borrow_mut().set(s.clone(), ScopeEntry {
				    val: val.clone(),
				    constant: true,
				});
                        ret = val;
			    }
			    _ => panic!("Expected quoted Symbol for defconst")
			}
                    }
                    _ => panic!("Expected quoted Symbol for defconst"),
		}
	    } else if name == Expr::Symbol("lambda".to_string()) {
		let mut lambda_args = vec![];
		let mut lambda_body = vec![];
		match &args[0] {
		    Expr::Function(l) => {
			for i in l {
			    lambda_args.push(i.clone())
			}
		    },
		    _ => panic!("Expected a list of lambda args")
		}
		for i in &args[1..] {
		    lambda_body.push(i.clone())
		};
		ret = Expr::Lambda(lambda_args,lambda_body)
	    } else {
		match &name {
		    Expr::Symbol(s) => {
			
			if env
			    .last()
			    .unwrap()
			    .clone()
			    .borrow_mut()
			    .contains(match name {
				Expr::Symbol(ref s) => s.to_string(),
				_ => panic!("Invalid funcall")
			    }) {
				match env
				    .last()
				    .unwrap()
				    .clone()
				    .borrow_mut()
				    .get(match name {
					Expr::Symbol(ref s) => &s,
					_ => panic!("Invalid funcall")
				    })
				    .unwrap() {
					Expr::Lambda(largs,body) => {
					    let mut lambda_args = vec![];
					    for i in args.clone() {
						lambda_args.push(i)
					    }
					    let mut i = 0;
					    while i <= lambda_args.len() {
						env
						    .last()
						    .unwrap()
						    .borrow_mut()
						    .set(match &largs[0] {
							Expr::Symbol(s) => s.to_string(),
							_ => panic!("Invalid lambda args")
						    },ScopeEntry {
							val: lambda_args[1].clone(),
							constant: false,
						    }		 
						    );
						    i += 1
					    }
					    let mut last = Expr::Bool(false);
					    for i in body {
						last = eval(Token {
						    expr: i,
						    row: expr.row,
						    col: expr.col,
						    file: expr.file.clone(),
						},env,trace);
						ret = last;
					    } 
					}
					_ => panic!("Invalid funcall")
				    }
			    }
		    }
		    _ => panic!("Invalid funcall")
		}
		/*if *env
		    .last()
		    .unwrap()
		    .contains(name) {
		    match name {

			_ => panic!("Invalid funcall")
		    }
		}*/
	    }
	    env.pop();
	    ret
	}
	_ => expr.expr
    }
}

Writing a simple print expr works, whereas invalid functions do not panic (even though they should) and lambda functions do not execute.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.