pub fn execute_block(&mut self, stmts: &Vec<Stmt>, environment: Rc<RefCell<Environment>>) -> Result<(), Option<Literal>> {
let previous = self.environment.clone();
self.environment = environment;
for statement in stmts {
println!("{:?}", self.execute(statement)?);
}
self.environment = previous;
Ok(())
}```
Result: ```()
()
()
()
()
...```
#`?` doesn't propagate the error
16 messages · Page 1 of 1 (latest)
? doesn't propagate the error
Code without ?: ```rust
pub fn execute_block(&mut self, stmts: &Vec<Stmt>, environment: Rc<RefCell<Environment>>) -> Result<(), Option<Literal>> {
let previous = self.environment.clone();
self.environment = environment;
for statement in stmts {
println!("{:?}", self.execute(statement));
}
self.environment = previous;
Ok(())
}```
Result:
Ok(())
Err(Some(Float(1.0)))
Ok(())
Err(Some(Float(-1.0)))
Ok(())
Err(Some(Float(-3.0)))
...```
Are you sure you're not just calling this function repeatedly?
Try adding a dbg around the relevant call: dbg!(self.execute(statement))?. It should print the return value just before ? deals with it
Some(
Float(
-3613.0,
),
),
)
[src/interpreter.rs:138] self.execute(statement) = Ok(
(),
)```
These are the only two places where I am calling it rust Stmt::Block(statements) => { self.execute_block(statements, Environment::from_existing(Rc::clone(&self.environment)))?; Ok(()) }
fn call(&self, interpreter: &mut Interpreter, arguments: &[Option<Literal>]) -> Option<Literal> {
let environment = &interpreter.globals;
if let Stmt::Function(name, params, body) = &self.declaration {
for i in 0..params.len() {
environment.borrow_mut().define(params.get(i)?.lexeme.clone(), arguments.get(i).unwrap().clone());
}
if let Err(value) = interpreter.execute_block(body, environment.clone()) {
return value;
}
}
None
}```
If I return a fake value, it works fine fn execute(&mut self, stmt: &Stmt) -> Result<(), Option<Literal>> { self.accept_statement(stmt); Err(Some(Literal::Float(3.0))) }
fatal runtime error: stack overflow``` I get this error if I don't
Idk, that ? is somehow failing to do its one job in a trivial case seems extremely unlikely. I'd add some printlns around the code (say, at the start of execute_block) to make sure you're not calling it again
I tried to return it manually by using if let but ended up with the same error. So maybe it's not ?
I am basically trying to implement return statements in my programming language. I am following crafting interpreters and the author throws an error if it encounters a return statement to unwind the stack. I am not sure if Rust does the same
The Java call stack currently looks roughly like this:
Interpreter.visitReturnStmt()
Interpreter.visitIfStmt()
Interpreter.executeBlock()
Interpreter.visitBlockStmt()
Interpreter.visitWhileStmt()
Interpreter.executeBlock()
LoxFunction.call()
Interpreter.visitCallExpr()We need to get from the top of the stack all the way back to call(). I don’t know about you, but to me that sounds like exceptions. When we execute a return statement, we’ll use an exception to unwind the interpreter past the visit methods of all of the containing statements back to the code that began executing the body.
btw you should definitely use something other than Result, like https://doc.rust-lang.org/std/ops/enum.ControlFlow.html
putting your function's result in Err is very confusing