Add return to functions

This commit is contained in:
Julius 2022-07-04 15:36:03 +02:00
parent 7236b204b9
commit 506b406146
Signed by: j00lz
GPG key ID: AF241B0AA237BBA2
6 changed files with 75 additions and 12 deletions

View file

@ -21,7 +21,8 @@ Some control flow: `while` and `if/else if/else`
Functions: can be defined in both the language and in Rust. Functions: can be defined in both the language and in Rust.
The functions defined in the language currently do not allow returning values. The functions support a return in the form of `return x;` and `x` as the last element.
The `return` keyword does already exist however, it just doesn't do anything yet.
As long as the final element is an expression of some kind, it will be seen as a return value in a function.
For some sample code, check `test.foo` (extension also TBD) For some sample code, check `test.foo` (extension also TBD)

View file

@ -108,7 +108,9 @@ impl Function for InterpreterFunction {
sub_env.set_here(name, value.clone()); sub_env.set_here(name, value.clone());
} }
for stmt in &self.body { for stmt in &self.body {
stmt.eval(&sub_env, map); if let Some(v) = stmt.eval(&sub_env, map){
return Ok(v);
}
} }
Ok(Value::Nothing) Ok(Value::Nothing)
} }

View file

@ -56,10 +56,12 @@ statement = { ( ret | assignment | assignment_let | expression ) ~ ";" | def | w
block = { "{" ~ statement* ~ "}" } block = { "{" ~ statement* ~ "}" }
func_block = { "{" ~ statement* ~ expression? ~ "}" }
assignment_let = { "let" ~ identifier ~ "=" ~ expression } assignment_let = { "let" ~ identifier ~ "=" ~ expression }
assignment = { identifier ~ "=" ~ expression } assignment = { identifier ~ "=" ~ expression }
ret = { "return" ~ expression } ret = { "return" ~ expression? }
while_block = { "while" ~ expression ~ block } while_block = { "while" ~ expression ~ block }
@ -67,7 +69,7 @@ if_block = { "if" ~ expression ~ block ~ ("else if" ~ expression ~ block)* ~ ("e
def_params = { "(" ~ (identifier ~ ","?)* ~ ")" } def_params = { "(" ~ (identifier ~ ","?)* ~ ")" }
def = { "def" ~ identifier ~ def_params ~ block } def = { "def" ~ identifier ~ def_params ~ func_block }
equals = { "==" } equals = { "==" }
not_equals = { "!=" } not_equals = { "!=" }

View file

@ -116,6 +116,21 @@ fn parse_statement(pair: Pair<Rule>) -> (Statement, FuncHolder) {
let (z, _): (_, FuncHolder) = pair.into_inner().map(parse_statement).unzip(); let (z, _): (_, FuncHolder) = pair.into_inner().map(parse_statement).unzip();
(Statement::Body(z), FuncHolder::default()) (Statement::Body(z), FuncHolder::default())
} }
Rule::func_block => {
let (statements, expression): (Vec<_>, Vec<_>) = pair
.into_inner()
.partition(|x| x.as_rule() != Rule::expression);
// Only functions defined at the root are supported for now, so we drop the ones
// defined in a block.
let (mut v, _): (Vec<Statement>, FuncHolder) =
statements.into_iter().map(parse_statement).unzip();
if let Some(expr) = expression.into_iter().next() {
let ret = parse_expression(expr);
v.push(Statement::Return(Some(ret)));
}
(Statement::Body(v), FuncHolder::default())
}
Rule::def => { Rule::def => {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
let name = inner.next().unwrap(); let name = inner.next().unwrap();
@ -133,6 +148,17 @@ fn parse_statement(pair: Pair<Rule>) -> (Statement, FuncHolder) {
FuncHolder::default().insert(name.as_str().to_string(), args, vec![body.0]), FuncHolder::default().insert(name.as_str().to_string(), args, vec![body.0]),
) )
} }
Rule::ret => {
let mut inner = pair.into_inner();
if let Some(expr) = inner.next() {
(
Statement::Return(Some(parse_expression(expr))),
FuncHolder::default(),
)
} else {
(Statement::Return(None), FuncHolder::default())
}
}
Rule::EOI => (Statement::Body(vec![]), FuncHolder::default()), Rule::EOI => (Statement::Body(vec![]), FuncHolder::default()),
x => unreachable!("How did we get to {:?}", x), x => unreachable!("How did we get to {:?}", x),
} }

View file

@ -1,4 +1,4 @@
use crate::{env::Env, expression::Expression, function::FunctionMap}; use crate::{env::Env, expression::Expression, function::FunctionMap, value::Value};
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Statement { pub enum Statement {
@ -7,10 +7,11 @@ pub enum Statement {
While(Expression, Box<Statement>), While(Expression, Box<Statement>),
If(Vec<(Expression, Statement)>, Option<Box<Statement>>), If(Vec<(Expression, Statement)>, Option<Box<Statement>>),
Body(Vec<Statement>), Body(Vec<Statement>),
Return(Option<Expression>),
} }
impl Statement { impl Statement {
pub fn eval(&self, env: &Env, f: &FunctionMap) { pub fn eval(&self, env: &Env, f: &FunctionMap) -> Option<Value> {
match self { match self {
Statement::Assignment(name, expr, explicit_let) => { Statement::Assignment(name, expr, explicit_let) => {
let value = expr.eval(env, f); let value = expr.eval(env, f);
@ -19,36 +20,56 @@ impl Statement {
} else { } else {
env.set(name, value); env.set(name, value);
} }
None
} }
Statement::Expression(expr) => { Statement::Expression(expr) => {
expr.eval(env, f); expr.eval(env, f);
None
} }
Statement::While(expr, body) => { Statement::While(expr, body) => {
while expr.eval(env, f).is_truthy() { while expr.eval(env, f).is_truthy() {
let body_env = Env::new_with_parent(env); let body_env = Env::new_with_parent(env);
body.eval(&body_env, f); if let Some(value) = body.eval(&body_env, f) {
return Some(value);
}
} }
None
} }
Statement::If(if_side, else_side) => { Statement::If(if_side, else_side) => {
let mut did_if = false; let mut did_if = false;
for (expr, body) in if_side { for (expr, body) in if_side {
if expr.eval(env, f).is_truthy() { if expr.eval(env, f).is_truthy() {
body.eval(env, f); if let Some(value) = body.eval(env, f) {
return Some(value);
}
did_if = true; did_if = true;
break; break;
} }
} }
if !did_if { if !did_if {
if let Some(else_side) = else_side { if let Some(else_side) = else_side {
else_side.eval(env, f); if let Some(value) = else_side.eval(env, f) {
return Some(value);
}
} }
} }
None
} }
Statement::Body(body) => { Statement::Body(body) => {
let body_env = Env::new_with_parent(env); let body_env = Env::new_with_parent(env);
for stmt in body.iter() { for stmt in body.iter() {
stmt.eval(&body_env, f); if let Some(value) = stmt.eval(&body_env, f) {
return Some(value);
}
}
None
}
Statement::Return(expr) => {
if let Some(expr) = expr {
Some(expr.eval(env, f))
} else {
Some(Value::Nothing)
} }
} }
} }

View file

@ -9,8 +9,19 @@ def test_func(x) {
while x < 100 { while x < 100 {
print(x); print(x);
x = x + 1; x = x + 1;
if x > 10 {
return "bar";
}
} }
return "foo";
} }
test_func(y); def add_one(x) {
x + 1
}
let x = test_func(y);
print(x);
print(add_one(41));