|
@@ -8,217 +8,239 @@ pub fn builtins() -> Vec<BuiltinFunc> {
|
|
|
vec![
|
|
|
BuiltinFunc {
|
|
|
name: "rep",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [rep, expr] = exprs {
|
|
|
- let mut buf = String::new();
|
|
|
- let num = state.eval(*rep, env)?.as_num(&state.ast.borrow())?;
|
|
|
- for _ in 0..num {
|
|
|
- buf.push_str(
|
|
|
- &state
|
|
|
- .eval(*expr, env)?
|
|
|
- .as_str(&state.ast.borrow())?
|
|
|
- .to_string(),
|
|
|
- );
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [rep, expr] = exprs {
|
|
|
+ let mut buf = String::new();
|
|
|
+ let num = state.eval(*rep, env)?.as_num(&state.ast.borrow())?;
|
|
|
+ for _ in 0..num {
|
|
|
+ buf.push_str(
|
|
|
+ &state
|
|
|
+ .eval(*expr, env)?
|
|
|
+ .as_str(&state.ast.borrow())?
|
|
|
+ .to_string(),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ Ok(Value::Lit(Literal::Str(buf)))
|
|
|
+ } else {
|
|
|
+ bail!("`rep`: expected two arguments, got {}", exprs.len())
|
|
|
}
|
|
|
- Ok(Value::Lit(Literal::Str(buf)))
|
|
|
- } else {
|
|
|
- bail!("`rep`: expected two arguments, got {}", exprs.len())
|
|
|
- }
|
|
|
- }),
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "str/upper",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [expr] = exprs {
|
|
|
- let s = state.eval(*expr, env)?;
|
|
|
- Ok(Value::Lit(Literal::Str(
|
|
|
- s.as_str(&state.ast.borrow())?.to_uppercase(),
|
|
|
- )))
|
|
|
- } else {
|
|
|
- bail!("`str/capitalize`: expected 1 argument1, got {}", exprs.len());
|
|
|
- }
|
|
|
- }),
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [expr] = exprs {
|
|
|
+ let s = state.eval(*expr, env)?;
|
|
|
+ Ok(Value::Lit(Literal::Str(
|
|
|
+ s.as_str(&state.ast.borrow())?.to_uppercase(),
|
|
|
+ )))
|
|
|
+ } else {
|
|
|
+ bail!(
|
|
|
+ "`str/capitalize`: expected 1 argument1, got {}",
|
|
|
+ exprs.len()
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "str/capitalize",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [expr] = exprs {
|
|
|
- let s = state.eval(*expr, env)?;
|
|
|
- Ok(Value::Lit(Literal::Str(titlecase::titlecase(
|
|
|
- s.as_str(&state.ast.borrow())?,
|
|
|
- ))))
|
|
|
- } else {
|
|
|
- bail!("`str/capitalize`: expected 1 argument1, got {}", exprs.len());
|
|
|
- }
|
|
|
- }),
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [expr] = exprs {
|
|
|
+ let s = state.eval(*expr, env)?;
|
|
|
+ Ok(Value::Lit(Literal::Str(titlecase::titlecase(
|
|
|
+ s.as_str(&state.ast.borrow())?,
|
|
|
+ ))))
|
|
|
+ } else {
|
|
|
+ bail!(
|
|
|
+ "`str/capitalize`: expected 1 argument1, got {}",
|
|
|
+ exprs.len()
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "str/lower",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [expr] = exprs {
|
|
|
- let s = state.eval(*expr, env)?;
|
|
|
- Ok(Value::Lit(Literal::Str(
|
|
|
- s.as_str(&state.ast.borrow())?.to_lowercase(),
|
|
|
- )))
|
|
|
- } else {
|
|
|
- bail!("`str/lower`: expected 1 argument1, got {}", exprs.len());
|
|
|
- }
|
|
|
- }),
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [expr] = exprs {
|
|
|
+ let s = state.eval(*expr, env)?;
|
|
|
+ Ok(Value::Lit(Literal::Str(
|
|
|
+ s.as_str(&state.ast.borrow())?.to_lowercase(),
|
|
|
+ )))
|
|
|
+ } else {
|
|
|
+ bail!("`str/lower`: expected 1 argument1, got {}", exprs.len());
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "add",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [x, y] = exprs {
|
|
|
- let x = state.eval(*x, env)?.as_num(&state.ast.borrow())?;
|
|
|
- let y = state.eval(*y, env)?.as_num(&state.ast.borrow())?;
|
|
|
- Ok(Value::Lit(Literal::Num(x + y)))
|
|
|
- } else {
|
|
|
- bail!("`add`: expected 2 arguments, got {}", exprs.len());
|
|
|
- }
|
|
|
- }),
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [x, y] = exprs {
|
|
|
+ let x = state.eval(*x, env)?.as_num(&state.ast.borrow())?;
|
|
|
+ let y = state.eval(*y, env)?.as_num(&state.ast.borrow())?;
|
|
|
+ Ok(Value::Lit(Literal::Num(x + y)))
|
|
|
+ } else {
|
|
|
+ bail!("`add`: expected 2 arguments, got {}", exprs.len());
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "sub",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [x, y] = exprs {
|
|
|
- let x = state.eval(*x, env)?.as_num(&state.ast.borrow())?;
|
|
|
- let y = state.eval(*y, env)?.as_num(&state.ast.borrow())?;
|
|
|
- Ok(Value::Lit(Literal::Num(x - y)))
|
|
|
- } else {
|
|
|
- bail!("`sub`: expected 2 arguments, got {}", exprs.len());
|
|
|
- }
|
|
|
- }),
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [x, y] = exprs {
|
|
|
+ let x = state.eval(*x, env)?.as_num(&state.ast.borrow())?;
|
|
|
+ let y = state.eval(*y, env)?.as_num(&state.ast.borrow())?;
|
|
|
+ Ok(Value::Lit(Literal::Num(x - y)))
|
|
|
+ } else {
|
|
|
+ bail!("`sub`: expected 2 arguments, got {}", exprs.len());
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "mul",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [x, y] = exprs {
|
|
|
- let x = state.eval(*x, env)?.as_num(&state.ast.borrow())?;
|
|
|
- let y = state.eval(*y, env)?.as_num(&state.ast.borrow())?;
|
|
|
- Ok(Value::Lit(Literal::Num(x * y)))
|
|
|
- } else {
|
|
|
- bail!("`mul`: expected 2 arguments, got {}", exprs.len());
|
|
|
- }
|
|
|
- }),
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [x, y] = exprs {
|
|
|
+ let x = state.eval(*x, env)?.as_num(&state.ast.borrow())?;
|
|
|
+ let y = state.eval(*y, env)?.as_num(&state.ast.borrow())?;
|
|
|
+ Ok(Value::Lit(Literal::Num(x * y)))
|
|
|
+ } else {
|
|
|
+ bail!("`mul`: expected 2 arguments, got {}", exprs.len());
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "tuple/len",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [expr] = exprs {
|
|
|
- let tup = state.eval(*expr, env)?;
|
|
|
- Ok(Value::Lit(Literal::Num(tup.as_tup(&state.ast.borrow())?.len() as i64)))
|
|
|
- } else {
|
|
|
- bail!("`tuple/len`: expected 1 argument, got {}", exprs.len())
|
|
|
- }
|
|
|
- }),
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [expr] = exprs {
|
|
|
+ let tup = state.eval(*expr, env)?;
|
|
|
+ Ok(Value::Lit(Literal::Num(
|
|
|
+ tup.as_tup(&state.ast.borrow())?.len() as i64,
|
|
|
+ )))
|
|
|
+ } else {
|
|
|
+ bail!("`tuple/len`: expected 1 argument, got {}", exprs.len())
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "tuple/concat",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [expr] = exprs {
|
|
|
- let val = state.eval(*expr, env)?;
|
|
|
- let tup = val.as_tup(&state.ast.borrow())?;
|
|
|
- let mut contents = Vec::new();
|
|
|
- for elem in tup {
|
|
|
- for th in state.hnf(elem)?.as_tup(&state.ast.borrow())? {
|
|
|
- contents.push(th.clone());
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [expr] = exprs {
|
|
|
+ let val = state.eval(*expr, env)?;
|
|
|
+ let tup = val.as_tup(&state.ast.borrow())?;
|
|
|
+ let mut contents = Vec::new();
|
|
|
+ for elem in tup {
|
|
|
+ for th in state.hnf(elem)?.as_tup(&state.ast.borrow())? {
|
|
|
+ contents.push(th.clone());
|
|
|
+ }
|
|
|
}
|
|
|
+ Ok(Value::Tup(contents))
|
|
|
+ } else {
|
|
|
+ bail!("tuple/concat: expected 1 argument, got {}", exprs.len());
|
|
|
}
|
|
|
- Ok(Value::Tup(contents))
|
|
|
- } else {
|
|
|
- bail!("tuple/concat: expected 1 argument, got {}", exprs.len());
|
|
|
- }
|
|
|
- }),
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "tuple/index",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [tup, idx] = exprs {
|
|
|
- let tup = state.eval(*tup, env)?;
|
|
|
- let idx = state.eval(*idx, env)?;
|
|
|
- state.hnf(
|
|
|
- &tup.as_tup(&state.ast.borrow())?
|
|
|
- [idx.as_num(&state.ast.borrow())? as usize],
|
|
|
- )
|
|
|
- } else {
|
|
|
- bail!("`tuple/index`: expected 2 arguments, got {}", exprs.len());
|
|
|
- }
|
|
|
- }),
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [tup, idx] = exprs {
|
|
|
+ let tup = state.eval(*tup, env)?;
|
|
|
+ let idx = state.eval(*idx, env)?;
|
|
|
+ state.hnf(
|
|
|
+ &tup.as_tup(&state.ast.borrow())?
|
|
|
+ [idx.as_num(&state.ast.borrow())? as usize],
|
|
|
+ )
|
|
|
+ } else {
|
|
|
+ bail!("`tuple/index`: expected 2 arguments, got {}", exprs.len());
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "tuple/replace",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [tup, idx, new] = exprs {
|
|
|
- let tup_val = state.eval(*tup, env)?;
|
|
|
- let tup = tup_val.as_tup(&state.ast.borrow())?;
|
|
|
- let idx = state.eval(*idx, env)?.as_num(&state.ast.borrow())?;
|
|
|
-
|
|
|
- let mut modified = Vec::with_capacity(tup.len());
|
|
|
- for i in 0..idx {
|
|
|
- modified.push(tup[i as usize].clone());
|
|
|
- }
|
|
|
- modified.push(Thunk::Expr(*new, env.clone()));
|
|
|
- for i in (idx + 1)..(tup.len() as i64) {
|
|
|
- modified.push(tup[i as usize].clone());
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [tup, idx, new] = exprs {
|
|
|
+ let tup_val = state.eval(*tup, env)?;
|
|
|
+ let tup = tup_val.as_tup(&state.ast.borrow())?;
|
|
|
+ let idx = state.eval(*idx, env)?.as_num(&state.ast.borrow())?;
|
|
|
+
|
|
|
+ let mut modified = Vec::with_capacity(tup.len());
|
|
|
+ for i in 0..idx {
|
|
|
+ modified.push(tup[i as usize].clone());
|
|
|
+ }
|
|
|
+ modified.push(Thunk::Expr(*new, env.clone()));
|
|
|
+ for i in (idx + 1)..(tup.len() as i64) {
|
|
|
+ modified.push(tup[i as usize].clone());
|
|
|
+ }
|
|
|
+ Ok(Value::Tup(modified))
|
|
|
+ } else {
|
|
|
+ bail!("`tuple/replace`: expected 3 arguments, got {}", exprs.len());
|
|
|
}
|
|
|
- Ok(Value::Tup(modified))
|
|
|
- } else {
|
|
|
- bail!("`tuple/replace`: expected 3 arguments, got {}", exprs.len());
|
|
|
- }
|
|
|
- }),
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "tuple/fold",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [func, init, tup] = exprs {
|
|
|
- let func = state.eval(*func, env)?;
|
|
|
- let tup = state.eval(*tup, env)?;
|
|
|
-
|
|
|
- let mut result = Thunk::Expr(*init, env.clone());
|
|
|
- for t in tup.as_tup(&state.ast.borrow())? {
|
|
|
- result = Thunk::Value(
|
|
|
- state.eval_closure(
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [func, init, tup] = exprs {
|
|
|
+ let func = state.eval(*func, env)?;
|
|
|
+ let tup = state.eval(*tup, env)?;
|
|
|
+
|
|
|
+ let mut result = Thunk::Expr(*init, env.clone());
|
|
|
+ for t in tup.as_tup(&state.ast.borrow())? {
|
|
|
+ result = Thunk::Value(state.eval_closure(
|
|
|
func.as_closure(&state.ast.borrow())?,
|
|
|
vec![result, t.clone()],
|
|
|
)?);
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- state.hnf(&result)
|
|
|
- } else {
|
|
|
- bail!("`tuple/fold`: expected 3 arguments, got {}", exprs.len());
|
|
|
- }
|
|
|
- }),
|
|
|
+ state.hnf(&result)
|
|
|
+ } else {
|
|
|
+ bail!("`tuple/fold`: expected 3 arguments, got {}", exprs.len());
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
-
|
|
|
BuiltinFunc {
|
|
|
name: "tuple/map",
|
|
|
- callback: Box::new(|state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
- if let [func, tup] = exprs {
|
|
|
- let func = state.eval(*func, env)?;
|
|
|
- let tup = state.eval(*tup, env)?;
|
|
|
+ callback: Box::new(
|
|
|
+ |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
|
|
|
+ if let [func, tup] = exprs {
|
|
|
+ let func = state.eval(*func, env)?;
|
|
|
+ let tup = state.eval(*tup, env)?;
|
|
|
+
|
|
|
+ let mut new_tup = Vec::new();
|
|
|
+ let closure = func.as_closure(&state.ast.borrow())?;
|
|
|
+ for t in tup.as_tup(&state.ast.borrow())? {
|
|
|
+ new_tup
|
|
|
+ .push(Thunk::Value(state.eval_closure(closure, vec![t.clone()])?));
|
|
|
+ }
|
|
|
|
|
|
- let mut new_tup = Vec::new();
|
|
|
- let closure = func.as_closure(&state.ast.borrow())?;
|
|
|
- for t in tup.as_tup(&state.ast.borrow())? {
|
|
|
- new_tup.push(Thunk::Value(state.eval_closure(closure, vec![t.clone()])?));
|
|
|
+ Ok(Value::Tup(new_tup))
|
|
|
+ } else {
|
|
|
+ bail!("`tuple/map`: expected 2 arguments, got {}", exprs.len());
|
|
|
}
|
|
|
-
|
|
|
- Ok(Value::Tup(new_tup))
|
|
|
- } else {
|
|
|
- bail!("`tuple/map`: expected 2 arguments, got {}", exprs.len());
|
|
|
- }
|
|
|
- }),
|
|
|
+ },
|
|
|
+ ),
|
|
|
},
|
|
|
]
|
|
|
}
|