builtins.rs 10 KB

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