Add return to functions
This commit is contained in:
parent
7236b204b9
commit
506b406146
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 = { "!=" }
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue