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.
The functions defined in the language currently do not allow returning values.
The `return` keyword does already exist however, it just doesn't do anything yet.
The functions support a return in the form of `return x;` and `x` as the last element.
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)

View file

@ -108,7 +108,9 @@ impl Function for InterpreterFunction {
sub_env.set_here(name, value.clone());
}
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)
}

View file

@ -56,10 +56,12 @@ statement = { ( ret | assignment | assignment_let | expression ) ~ ";" | def | w
block = { "{" ~ statement* ~ "}" }
func_block = { "{" ~ statement* ~ expression? ~ "}" }
assignment_let = { "let" ~ identifier ~ "=" ~ expression }
assignment = { identifier ~ "=" ~ expression }
ret = { "return" ~ expression }
ret = { "return" ~ expression? }
while_block = { "while" ~ expression ~ block }
@ -67,7 +69,7 @@ if_block = { "if" ~ expression ~ block ~ ("else if" ~ expression ~ block)* ~ ("e
def_params = { "(" ~ (identifier ~ ","?)* ~ ")" }
def = { "def" ~ identifier ~ def_params ~ block }
def = { "def" ~ identifier ~ def_params ~ func_block }
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();
(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 => {
let mut inner = pair.into_inner();
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]),
)
}
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()),
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)]
pub enum Statement {
@ -7,10 +7,11 @@ pub enum Statement {
While(Expression, Box<Statement>),
If(Vec<(Expression, Statement)>, Option<Box<Statement>>),
Body(Vec<Statement>),
Return(Option<Expression>),
}
impl Statement {
pub fn eval(&self, env: &Env, f: &FunctionMap) {
pub fn eval(&self, env: &Env, f: &FunctionMap) -> Option<Value> {
match self {
Statement::Assignment(name, expr, explicit_let) => {
let value = expr.eval(env, f);
@ -19,36 +20,56 @@ impl Statement {
} else {
env.set(name, value);
}
None
}
Statement::Expression(expr) => {
expr.eval(env, f);
None
}
Statement::While(expr, body) => {
while expr.eval(env, f).is_truthy() {
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) => {
let mut did_if = false;
for (expr, body) in if_side {
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;
break;
}
}
if !did_if {
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) => {
let body_env = Env::new_with_parent(env);
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 {
print(x);
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));