Skip to content

Commit

Permalink
Fun fun functions (#57)
Browse files Browse the repository at this point in the history
i should write tests, but am lazy at the moment.

closes #18
  • Loading branch information
ahdinosaur committed Sep 18, 2023
1 parent 021664d commit 22726d2
Show file tree
Hide file tree
Showing 16 changed files with 9,401 additions and 8,532 deletions.
4 changes: 4 additions & 0 deletions ast/src/block.rs
Expand Up @@ -8,6 +8,10 @@ pub enum Block {
List(Vec<SpannedBlock>),
Expression(Expression),
Operation(Box<BlockOperation>),
Function {
args: Vec<Spanned<String>>,
body: Box<SpannedBlock>,
},
}

pub type SpannedBlock = Spanned<Block>;
16 changes: 15 additions & 1 deletion ast/src/expression.rs
Expand Up @@ -25,6 +25,12 @@ pub enum Expression {
/// Literal key-value object.
Object(Vec<(Spanned<String>, SpannedExpression)>),

/// Function
Function {
args: Vec<Spanned<String>>,
body: Box<SpannedExpression>,
},

/// A named local variable.
Identifier(String),

Expand Down Expand Up @@ -86,10 +92,18 @@ impl fmt::Display for Expression {
.join(", ");
write!(f, "[{}]", keys)
}
Expression::Function { args, body } => {
let args = args
.iter()
.map(ToString::to_string)
.collect::<Vec<String>>()
.join(", ");
write!(f, "({}) => {}", args, body)
}
Expression::Object(object) => {
let entries = object
.iter()
.map(|(key, value)| format!("\"{}\": {}", key, value.to_string()))
.map(|(key, value)| format!("\"{}\": {}", key, value))
.collect::<Vec<String>>()
.join(", ");
write!(f, "{{{}}}", entries)
Expand Down
13 changes: 13 additions & 0 deletions docs/pages/language/blocks.mdx
Expand Up @@ -72,6 +72,19 @@ bottles_of_beer_on_the_wall: 99
cat: "Charlie"
```

### Function

```yaml
add: (a, b) => a + b
```

Or

```yaml
add: (a, b) =>
a + b
```

## Multi-line values

TODO
4 changes: 3 additions & 1 deletion docs/pages/language/values.mdx
Expand Up @@ -69,4 +69,6 @@ All numbers are ["Big" Decimals](https://crates.io/crates/rust_decimal), not flo

### Function

TODO
```
(a, b) => a + b
```
2 changes: 1 addition & 1 deletion docs/pages/roadmap.mdx
Expand Up @@ -15,7 +15,7 @@
- [x] String
- [x] List
- [x] Object
- [ ] Function : [issue#18](https://github.com/ahdinosaur/rimu/issues/18)
- [x] Function : [pull#57](https://github.com/ahdinosaur/rimu/pull/57)

- Identifier

Expand Down
14 changes: 13 additions & 1 deletion eval/src/block.rs
Expand Up @@ -4,7 +4,7 @@
use crate::Environment;
use rimu_ast::{Block, BlockOperation, Expression, SpannedBlock};
use rimu_meta::{Span, Spanned};
use rimu_value::{List, Object, Value};
use rimu_value::{Function, FunctionBody, List, Object, Value};

use crate::{expression::evaluate as evaluate_expression, EvalError};

Expand Down Expand Up @@ -33,6 +33,7 @@ impl<'a> Evaluator<'a> {
let value = match block.inner() {
Block::Object(object) => self.object(span, object)?,
Block::List(list) => self.list(span, list)?,
Block::Function { args, body } => self.function(span, args, body)?,
Block::Expression(expr) => self.expression(span, expr)?,
Block::Operation(op) => self.operation(span, op)?,
};
Expand Down Expand Up @@ -65,6 +66,17 @@ impl<'a> Evaluator<'a> {
Ok(Value::List(list))
}

fn function(
&self,
_span: Span,
args: &[Spanned<String>],
body: &SpannedBlock,
) -> Result<Value> {
let args: Vec<String> = args.iter().map(|a| a.inner()).cloned().collect();
let body = FunctionBody::Block(body.clone());
Ok(Value::Function(Function { args, body }))
}

fn expression(&self, span: Span, expr: &Expression) -> Result<Value> {
evaluate_expression(&Spanned::new(expr.clone(), span), self.env)
}
Expand Down
29 changes: 22 additions & 7 deletions eval/src/expression.rs
Expand Up @@ -3,11 +3,11 @@

use rimu_ast::{BinaryOperator, Expression, SpannedExpression, UnaryOperator};
use rimu_meta::{Span, Spanned};
use rimu_value::{Number, Object, Value};
use rimu_value::{Function, FunctionBody, Number, Object, Value};
use rust_decimal::prelude::ToPrimitive;
use std::ops::Deref;

use crate::{Environment, EvalError};
use crate::{evaluate_block, Environment, EvalError};

pub fn evaluate<'a>(
expression: &SpannedExpression,
Expand Down Expand Up @@ -45,6 +45,8 @@ impl<'a> Evaluator<'a> {

Expression::Object(ref entries) => self.object(span, entries)?,

Expression::Function { ref args, ref body } => self.function(span, args, body)?,

Expression::Identifier(var) => self.variable(span, var)?,

Expression::Unary {
Expand Down Expand Up @@ -89,6 +91,17 @@ impl<'a> Evaluator<'a> {
Ok(Value::String(string.to_string()))
}

fn function(
&self,
_span: Span,
args: &Vec<Spanned<String>>,
body: &SpannedExpression,
) -> Result<Value, EvalError> {
let args: Vec<String> = args.into_iter().map(|a| a.inner()).cloned().collect();
let body = FunctionBody::Expression(body.clone());
Ok(Value::Function(Function { args, body }))
}

fn unary(
&self,
_span: Span,
Expand Down Expand Up @@ -386,7 +399,10 @@ impl<'a> Evaluator<'a> {
function_env.insert(arg_name, arg_value);
}

evaluate(&function.body, &function_env)
match &function.body {
FunctionBody::Expression(expression) => evaluate(expression, &function_env),
FunctionBody::Block(block) => evaluate_block(block, &function_env),
}
}

fn get_index(
Expand Down Expand Up @@ -601,7 +617,7 @@ mod tests {
use rimu_ast::{BinaryOperator, Expression, SpannedExpression};
use rimu_meta::{SourceId, Span, Spanned};
use rimu_parse::parse_expression;
use rimu_value::{Function, Value};
use rimu_value::{Function, FunctionBody, Value};
use rust_decimal_macros::dec;

use super::{evaluate, EvalError};
Expand Down Expand Up @@ -716,9 +732,8 @@ mod tests {
fn simple_function_call() {
let env = indexmap! {
"add".into() => Value::Function(Function {
name: "add".into(),
args: vec!["a".into(), "b".into()],
body: Spanned::new(
body: FunctionBody::Expression(Spanned::new(
Expression::Binary {
left: Box::new(Spanned::new(
Expression::Identifier("a".into()),
Expand All @@ -732,7 +747,7 @@ mod tests {
},
span(0..3),
),
}),
)}),
"one".into() => Value::Number(dec!(1).into()),
"two".into() => Value::Number(dec!(2).into()),
};
Expand Down

1 comment on commit 22726d2

@vercel
Copy link

@vercel vercel bot commented on 22726d2 Sep 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

rimu-docs – ./docs

rimu-docs.vercel.app
rimu-docs-git-main-ahdinosaur.vercel.app
rimu-docs-ahdinosaur.vercel.app

Please sign in to comment.