1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use num_traits::identities::{One, Zero};
use yolol_number::YololNumber;
use crate::ast::{InfixOp, YolkNode, YololNode};
use crate::environment::{Context, Environment};
use crate::error::TranspileError;
use crate::function::Function;
use crate::value::{ArrayExpr, NumberExpr, Value};
#[cfg(test)]
mod tests;
pub fn transpile(stmts: &[YolkNode]) -> Result<(Vec<YololNode>, Context), TranspileError> {
let mut env = Environment::new();
let mut assigns = Vec::new();
for stmt in stmts.iter() {
match stmt {
YolkNode::ImportStmt { ident } => env.import(&ident)?,
YolkNode::DefineStmt {
ident,
params,
body,
} => env.define(&ident, Function::new(&ident, params, &*body)?)?,
YolkNode::LetStmt { ident, expr } => {
assigns.extend(env.let_value(&ident, expr_to_value(&env, &*expr)?)?);
}
YolkNode::ExportStmt { ident } => env.export(&ident)?,
_ => panic!("expected Yolk statement, but got: {:?}", stmt),
}
}
Ok((assigns, env.context()))
}
fn expr_to_value(env: &Environment, expr: &YolkNode) -> Result<Value, TranspileError> {
match expr {
YolkNode::PrefixExpr { op, expr } => {
let value = expr_to_value(env, &expr)?;
Ok(value.apply_prefix_op(&op))
}
YolkNode::BuiltinExpr { ident, args } => match ident.as_ref() {
"sum" => sum_to_value(env, args),
"product" => product_to_value(env, args),
_ => panic!("expected builtin, but got: {:?}", ident),
},
YolkNode::CallExpr { ident, args } => {
let function = env.function(ident)?;
let expr = function.call(args)?;
expr_to_value(env, &expr)
}
YolkNode::InfixExpr { lhs, op, rhs } => {
let lhs = expr_to_value(env, &lhs)?;
let rhs = expr_to_value(env, &rhs)?;
lhs.apply_infix_op(&op, &rhs)
}
YolkNode::Ident(s) => env.variable(s),
YolkNode::Literal(y) => Ok(Value::Number(NumberExpr::from_yolol_number(y.clone()))),
YolkNode::Array(exprs) => {
let mut numbers = Vec::new();
for expr in exprs.iter() {
let value = expr_to_value(env, &expr)?;
match value {
Value::Number(n) => numbers.push(n),
Value::Array(_) => return Err(TranspileError::NestedArrays),
}
}
Ok(Value::Array(ArrayExpr::from_number_exprs(&numbers)))
}
_ => panic!("expected Yolk expression, but got: {:?}", expr),
}
}
fn sum_to_value(env: &Environment, args: &[YolkNode]) -> Result<Value, TranspileError> {
let mut values = Vec::new();
for arg in args.iter() {
values.push(expr_to_value(env, arg)?);
}
Ok(Value::reduce(
&values,
&InfixOp::Add,
&NumberExpr::from_yolol_number(YololNumber::zero()),
))
}
fn product_to_value(env: &Environment, args: &[YolkNode]) -> Result<Value, TranspileError> {
let mut values = Vec::new();
for arg in args.iter() {
values.push(expr_to_value(env, arg)?);
}
Ok(Value::reduce(
&values,
&InfixOp::Mul,
&NumberExpr::from_yolol_number(YololNumber::one()),
))
}