builtins.rs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. use crate::ast::*;
  2. use crate::interp::*;
  3. use anyhow::{bail, Error};
  4. /// The list of builtins provided at startup.
  5. pub fn builtins() -> Vec<BuiltinFunc> {
  6. vec![
  7. BuiltinFunc {
  8. name: "rep",
  9. callback: Box::new(
  10. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  11. if let [rep, expr] = exprs {
  12. let mut buf = String::new();
  13. let num = state.eval(*rep, env)?.as_num(&state.ast.borrow())?;
  14. for _ in 0..num {
  15. buf.push_str(
  16. state
  17. .eval(*expr, env)?
  18. .as_str(&state.ast.borrow())?,
  19. );
  20. }
  21. Ok(Value::Lit(Literal::Str(buf)))
  22. } else {
  23. bail!("`rep`: expected two arguments, got {}", exprs.len())
  24. }
  25. },
  26. ),
  27. },
  28. BuiltinFunc {
  29. name: "str/upper",
  30. callback: Box::new(
  31. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  32. if let [expr] = exprs {
  33. let s = state.eval(*expr, env)?;
  34. Ok(Value::Lit(Literal::Str(
  35. s.as_str(&state.ast.borrow())?.to_uppercase(),
  36. )))
  37. } else {
  38. bail!(
  39. "`str/capitalize`: expected 1 argument1, got {}",
  40. exprs.len()
  41. );
  42. }
  43. },
  44. ),
  45. },
  46. BuiltinFunc {
  47. name: "str/capitalize",
  48. callback: Box::new(
  49. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  50. if let [expr] = exprs {
  51. let s = state.eval(*expr, env)?;
  52. Ok(Value::Lit(Literal::Str(titlecase::titlecase(
  53. s.as_str(&state.ast.borrow())?,
  54. ))))
  55. } else {
  56. bail!(
  57. "`str/capitalize`: expected 1 argument1, got {}",
  58. exprs.len()
  59. );
  60. }
  61. },
  62. ),
  63. },
  64. BuiltinFunc {
  65. name: "str/lower",
  66. callback: Box::new(
  67. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  68. if let [expr] = exprs {
  69. let s = state.eval(*expr, env)?;
  70. Ok(Value::Lit(Literal::Str(
  71. s.as_str(&state.ast.borrow())?.to_lowercase(),
  72. )))
  73. } else {
  74. bail!("`str/lower`: expected 1 argument1, got {}", exprs.len());
  75. }
  76. },
  77. ),
  78. },
  79. BuiltinFunc {
  80. name: "add",
  81. callback: Box::new(
  82. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  83. if let [x, y] = exprs {
  84. let x = state.eval(*x, env)?.as_num(&state.ast.borrow())?;
  85. let y = state.eval(*y, env)?.as_num(&state.ast.borrow())?;
  86. Ok(Value::Lit(Literal::Num(x + y)))
  87. } else {
  88. bail!("`add`: expected 2 arguments, got {}", exprs.len());
  89. }
  90. },
  91. ),
  92. },
  93. BuiltinFunc {
  94. name: "sub",
  95. callback: Box::new(
  96. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  97. if let [x, y] = exprs {
  98. let x = state.eval(*x, env)?.as_num(&state.ast.borrow())?;
  99. let y = state.eval(*y, env)?.as_num(&state.ast.borrow())?;
  100. Ok(Value::Lit(Literal::Num(x - y)))
  101. } else {
  102. bail!("`sub`: expected 2 arguments, got {}", exprs.len());
  103. }
  104. },
  105. ),
  106. },
  107. BuiltinFunc {
  108. name: "mul",
  109. callback: Box::new(
  110. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  111. if let [x, y] = exprs {
  112. let x = state.eval(*x, env)?.as_num(&state.ast.borrow())?;
  113. let y = state.eval(*y, env)?.as_num(&state.ast.borrow())?;
  114. Ok(Value::Lit(Literal::Num(x * y)))
  115. } else {
  116. bail!("`mul`: expected 2 arguments, got {}", exprs.len());
  117. }
  118. },
  119. ),
  120. },
  121. BuiltinFunc {
  122. name: "tuple/len",
  123. callback: Box::new(
  124. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  125. if let [expr] = exprs {
  126. let tup = state.eval(*expr, env)?;
  127. Ok(Value::Lit(Literal::Num(
  128. tup.as_tup(&state.ast.borrow())?.len() as i64,
  129. )))
  130. } else {
  131. bail!("`tuple/len`: expected 1 argument, got {}", exprs.len())
  132. }
  133. },
  134. ),
  135. },
  136. BuiltinFunc {
  137. name: "tuple/concat",
  138. callback: Box::new(
  139. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  140. if let [expr] = exprs {
  141. let val = state.eval(*expr, env)?;
  142. let tup = val.as_tup(&state.ast.borrow())?;
  143. let mut contents = Vec::new();
  144. for elem in tup {
  145. for th in state.hnf(elem)?.as_tup(&state.ast.borrow())? {
  146. contents.push(th.clone());
  147. }
  148. }
  149. Ok(Value::Tup(contents))
  150. } else {
  151. bail!("tuple/concat: expected 1 argument, got {}", exprs.len());
  152. }
  153. },
  154. ),
  155. },
  156. BuiltinFunc {
  157. name: "tuple/index",
  158. callback: Box::new(
  159. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  160. if let [tup, idx] = exprs {
  161. let tup = state.eval(*tup, env)?;
  162. let idx = state.eval(*idx, env)?;
  163. state.hnf(
  164. &tup.as_tup(&state.ast.borrow())?
  165. [idx.as_num(&state.ast.borrow())? as usize],
  166. )
  167. } else {
  168. bail!("`tuple/index`: expected 2 arguments, got {}", exprs.len());
  169. }
  170. },
  171. ),
  172. },
  173. BuiltinFunc {
  174. name: "tuple/replace",
  175. callback: Box::new(
  176. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  177. if let [tup, idx, new] = exprs {
  178. let tup_val = state.eval(*tup, env)?;
  179. let tup = tup_val.as_tup(&state.ast.borrow())?;
  180. let idx = state.eval(*idx, env)?.as_num(&state.ast.borrow())?;
  181. let mut modified = Vec::with_capacity(tup.len());
  182. for i in 0..idx {
  183. modified.push(tup[i as usize].clone());
  184. }
  185. modified.push(Thunk::Expr(*new, env.clone()));
  186. for i in (idx + 1)..(tup.len() as i64) {
  187. modified.push(tup[i as usize].clone());
  188. }
  189. Ok(Value::Tup(modified))
  190. } else {
  191. bail!("`tuple/replace`: expected 3 arguments, got {}", exprs.len());
  192. }
  193. },
  194. ),
  195. },
  196. BuiltinFunc {
  197. name: "tuple/fold",
  198. callback: Box::new(
  199. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  200. if let [func, init, tup] = exprs {
  201. let func = state.eval(*func, env)?;
  202. let tup = state.eval(*tup, env)?;
  203. let mut result = Thunk::Expr(*init, env.clone());
  204. for t in tup.as_tup(&state.ast.borrow())? {
  205. result = Thunk::Value(state.eval_closure(
  206. func.as_closure(&state.ast.borrow())?,
  207. vec![result, t.clone()],
  208. )?);
  209. }
  210. state.hnf(&result)
  211. } else {
  212. bail!("`tuple/fold`: expected 3 arguments, got {}", exprs.len());
  213. }
  214. },
  215. ),
  216. },
  217. BuiltinFunc {
  218. name: "tuple/map",
  219. callback: Box::new(
  220. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, Error> {
  221. if let [func, tup] = exprs {
  222. let func = state.eval(*func, env)?;
  223. let tup = state.eval(*tup, env)?;
  224. let mut new_tup = Vec::new();
  225. let closure = func.as_closure(&state.ast.borrow())?;
  226. for t in tup.as_tup(&state.ast.borrow())? {
  227. new_tup
  228. .push(Thunk::Value(state.eval_closure(closure, vec![t.clone()])?));
  229. }
  230. Ok(Value::Tup(new_tup))
  231. } else {
  232. bail!("`tuple/map`: expected 2 arguments, got {}", exprs.len());
  233. }
  234. },
  235. ),
  236. },
  237. ]
  238. }