builtins.rs 8.1 KB

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