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.
|
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)
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = { "!=" }
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue