Info
This post is auto-generated from RSS feed The Rust Programming Language Forum - Latest topics. Source: 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.
1 post - 1 participant
🏷️ Rust_feed