Implement return values

This commit is contained in:
Daniel M 2022-02-03 14:50:55 +01:00
parent 638610d310
commit e0c72003f9
5 changed files with 45 additions and 9 deletions

View File

@ -119,6 +119,7 @@ pub enum Statement {
If(If), If(If),
Print(Expression), Print(Expression),
FunDecl(String, Vec<String>, Ast), FunDecl(String, Vec<String>, Ast),
Return(Expression),
} }
#[derive(Debug, PartialEq, Eq, Clone, Default)] #[derive(Debug, PartialEq, Eq, Clone, Default)]

View File

@ -8,6 +8,11 @@ pub enum Value {
String(Rc<String>), String(Rc<String>),
} }
pub enum RunEnd {
Return(Value),
End,
}
pub struct Interpreter { pub struct Interpreter {
// Variable table stores the runtime values of variables // Variable table stores the runtime values of variables
vartable: HashMap<String, Value>, vartable: HashMap<String, Value>,
@ -36,13 +41,17 @@ impl Interpreter {
self.run(&ast); self.run(&ast);
} }
pub fn run(&mut self, prog: &Ast) { pub fn run(&mut self, prog: &Ast) -> RunEnd {
for stmt in &prog.prog { for stmt in &prog.prog {
match stmt { match stmt {
Statement::Expr(expr) => { Statement::Expr(expr) => {
self.resolve_expr(expr); self.resolve_expr(expr);
} }
Statement::Return(expr) => {
return RunEnd::Return(self.resolve_expr(expr));
}
Statement::Loop(looop) => { Statement::Loop(looop) => {
// loop runs as long condition != 0 // loop runs as long condition != 0
loop { loop {
@ -50,7 +59,10 @@ impl Interpreter {
break; break;
} }
self.run(&looop.body); match self.run(&looop.body) {
RunEnd::Return(val) => return RunEnd::Return(val),
RunEnd::End => (),
}
if let Some(adv) = &looop.advancement { if let Some(adv) = &looop.advancement {
self.resolve_expr(&adv); self.resolve_expr(&adv);
@ -64,18 +76,23 @@ impl Interpreter {
} }
Statement::If(If {condition, body_true, body_false}) => { Statement::If(If {condition, body_true, body_false}) => {
if matches!(self.resolve_expr(condition), Value::I64(0)) { let end = if matches!(self.resolve_expr(condition), Value::I64(0)) {
self.run(body_false); self.run(body_false)
} else { } else {
self.run(body_true); self.run(body_true)
};
match end {
RunEnd::Return(val) => return RunEnd::Return(val),
RunEnd::End => (),
} }
} }
Statement::FunDecl(name, args, body) => { Statement::FunDecl(name, args, body) => {
self.funtable.insert(name.clone(), (args.clone(), body.clone()).into()); self.funtable.insert(name.clone(), (args.clone(), body.clone()).into());
} }
} }
} }
RunEnd::End
} }
fn resolve_expr(&mut self, expr: &Expression) -> Value { fn resolve_expr(&mut self, expr: &Expression) -> Value {
@ -96,9 +113,11 @@ impl Interpreter {
panic!("Invalid number of arguments for function"); panic!("Invalid number of arguments for function");
} }
self.run(&fun.borrow().1); let end = self.run(&fun.borrow().1);
match end {
Value::I64(0) RunEnd::Return(val) => val,
RunEnd::End => Value::I64(0),
}
} }
} }
} }

View File

@ -191,6 +191,7 @@ impl<'a> Lexer<'a> {
"if" => Token::If, "if" => Token::If,
"else" => Token::Else, "else" => Token::Else,
"fun" => Token::Fun, "fun" => Token::Fun,
"return" => Token::Return,
// If it doesn't match a keyword, it is a normal identifier // If it doesn't match a keyword, it is a normal identifier
_ => Token::Ident(ident), _ => Token::Ident(ident),

View File

@ -52,6 +52,19 @@ impl<T: Iterator<Item = Token>> Parser<T> {
Statement::Print(expr) Statement::Print(expr)
} }
Token::Return => {
self.next();
let expr = self.parse_expr();
// After a statement, there must be a semicolon
if !matches!(self.next(), Token::Semicolon) {
panic!("Expected semicolon after statement");
}
Statement::Return(expr)
}
Token::If => Statement::If(self.parse_if()), Token::If => Statement::If(self.parse_if()),
Token::Fun => { Token::Fun => {

View File

@ -27,6 +27,8 @@ pub enum Token {
Comma, Comma,
Return,
/// Left Parenthesis ('(') /// Left Parenthesis ('(')
LParen, LParen,