builtins.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. use crate::ast::*;
  2. use crate::core::Loc;
  3. use crate::errors::MatzoError;
  4. use crate::interp::*;
  5. fn arity_error(func: &str, expected: usize, actual: &[ExprRef]) -> Result<Value, MatzoError> {
  6. let msg = format!(
  7. "`{}`: expected {} argument{}, got {}",
  8. func,
  9. expected,
  10. if expected == 1 { "" } else { "s" },
  11. actual.len()
  12. );
  13. if actual.is_empty() {
  14. panic!("should not be possible to express")
  15. // Err(MatzoError::new(Span::empty(), msg))
  16. } else {
  17. let span = Span {
  18. start: actual[0].loc.span.start,
  19. end: actual[actual.len() - 1].loc.span.end,
  20. };
  21. let file = actual[0].loc.file;
  22. Err(MatzoError::new(Loc { span, file }, msg))
  23. }
  24. }
  25. /// The list of builtins provided at startup.
  26. pub fn builtins() -> Vec<BuiltinFunc> {
  27. vec![
  28. BuiltinFunc {
  29. name: "rep",
  30. callback: Box::new(
  31. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  32. if let [rep, expr] = exprs {
  33. let mut buf = String::new();
  34. let num = state
  35. .eval(*rep, env)?
  36. .as_num(&state.ast.borrow(), rep.loc)?;
  37. for _ in 0..num {
  38. buf.push_str(
  39. state
  40. .eval(*expr, env)?
  41. .as_str(&state.ast.borrow(), expr.loc)?,
  42. );
  43. }
  44. Ok(Value::Lit(Literal::Str(buf)))
  45. } else {
  46. arity_error("rep", 2, exprs)
  47. }
  48. },
  49. ),
  50. },
  51. BuiltinFunc {
  52. name: "str/upper",
  53. callback: Box::new(
  54. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  55. if let [expr] = exprs {
  56. let s = state.eval(*expr, env)?;
  57. Ok(Value::Lit(Literal::Str(
  58. s.as_str(&state.ast.borrow(), expr.loc)?.to_uppercase(),
  59. )))
  60. } else {
  61. arity_error("str/upper", 1, exprs)
  62. }
  63. },
  64. ),
  65. },
  66. BuiltinFunc {
  67. name: "str/capitalize",
  68. callback: Box::new(
  69. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  70. if let [expr] = exprs {
  71. let s = state.eval(*expr, env)?;
  72. Ok(Value::Lit(Literal::Str(titlecase::titlecase(
  73. s.as_str(&state.ast.borrow(), expr.loc)?,
  74. ))))
  75. } else {
  76. arity_error("str/capitalize", 1, exprs)
  77. }
  78. },
  79. ),
  80. },
  81. BuiltinFunc {
  82. name: "str/lower",
  83. callback: Box::new(
  84. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  85. if let [expr] = exprs {
  86. let s = state.eval(*expr, env)?;
  87. Ok(Value::Lit(Literal::Str(
  88. s.as_str(&state.ast.borrow(), expr.loc)?.to_lowercase(),
  89. )))
  90. } else {
  91. arity_error("str/lower", 1, exprs)
  92. }
  93. },
  94. ),
  95. },
  96. BuiltinFunc {
  97. name: "wd",
  98. callback: Box::new(
  99. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  100. let mut buf = String::new();
  101. for expr in exprs {
  102. let s = state.eval(*expr, env)?;
  103. buf.push_str(s.as_str(&state.ast.borrow(), expr.loc)?);
  104. }
  105. Ok(Value::Lit(Literal::Str(buf)))
  106. },
  107. ),
  108. },
  109. BuiltinFunc {
  110. name: "se",
  111. callback: Box::new(
  112. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  113. let mut buf = String::new();
  114. let mut capitalized = false;
  115. let mut last_char = '\0';
  116. for expr in exprs.iter() {
  117. let s = state.eval(*expr, env)?;
  118. let s = s.as_str(&state.ast.borrow(), expr.loc)?;
  119. if !capitalized && !s.trim().is_empty() {
  120. capitalized = true;
  121. let mut chars = s.chars();
  122. for c in chars.next().unwrap().to_uppercase() {
  123. buf.push(c);
  124. }
  125. for c in chars {
  126. buf.push(c);
  127. }
  128. } else if last_char.is_alphanumeric()
  129. && s.chars().next().map_or(false, |c| c.is_alphanumeric())
  130. {
  131. buf.push(' ');
  132. buf.push_str(s.trim());
  133. } else {
  134. buf.push_str(s.trim());
  135. }
  136. if buf.len() > 0 {
  137. last_char = buf.chars().last().unwrap();
  138. }
  139. }
  140. Ok(Value::Lit(Literal::Str(buf)))
  141. },
  142. ),
  143. },
  144. BuiltinFunc {
  145. name: "add",
  146. callback: Box::new(
  147. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  148. if let [x, y] = exprs {
  149. let x = state.eval(*x, env)?.as_num(&state.ast.borrow(), x.loc)?;
  150. let y = state.eval(*y, env)?.as_num(&state.ast.borrow(), y.loc)?;
  151. Ok(Value::Lit(Literal::Num(x + y)))
  152. } else {
  153. arity_error("add", 2, exprs)
  154. }
  155. },
  156. ),
  157. },
  158. BuiltinFunc {
  159. name: "sub",
  160. callback: Box::new(
  161. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  162. if let [x, y] = exprs {
  163. let x = state.eval(*x, env)?.as_num(&state.ast.borrow(), x.loc)?;
  164. let y = state.eval(*y, env)?.as_num(&state.ast.borrow(), y.loc)?;
  165. Ok(Value::Lit(Literal::Num(x - y)))
  166. } else {
  167. arity_error("sub", 2, exprs)
  168. }
  169. },
  170. ),
  171. },
  172. BuiltinFunc {
  173. name: "mul",
  174. callback: Box::new(
  175. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  176. if let [x, y] = exprs {
  177. let x = state.eval(*x, env)?.as_num(&state.ast.borrow(), x.loc)?;
  178. let y = state.eval(*y, env)?.as_num(&state.ast.borrow(), y.loc)?;
  179. Ok(Value::Lit(Literal::Num(x * y)))
  180. } else {
  181. arity_error("mul", 2, exprs)
  182. }
  183. },
  184. ),
  185. },
  186. BuiltinFunc {
  187. name: "tuple/len",
  188. callback: Box::new(
  189. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  190. if let [expr] = exprs {
  191. let tup = state.eval(*expr, env)?;
  192. Ok(Value::Lit(Literal::Num(
  193. tup.as_tup(&state.ast.borrow(), expr.loc)?.len() as i64,
  194. )))
  195. } else {
  196. arity_error("tuple/len", 1, exprs)
  197. }
  198. },
  199. ),
  200. },
  201. BuiltinFunc {
  202. name: "tuple/concat",
  203. callback: Box::new(
  204. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  205. if let [expr] = exprs {
  206. let val = state.eval(*expr, env)?;
  207. let tup = val.as_tup(&state.ast.borrow(), expr.loc)?;
  208. let mut contents = Vec::new();
  209. for elem in tup {
  210. for th in state
  211. .hnf(elem)?
  212. .as_tup(&state.ast.borrow(), expr.loc)?
  213. {
  214. contents.push(th.clone());
  215. }
  216. }
  217. Ok(Value::Tup(contents))
  218. } else {
  219. arity_error("tuple/concat", 1, exprs)
  220. }
  221. },
  222. ),
  223. },
  224. BuiltinFunc {
  225. name: "tuple/index",
  226. callback: Box::new(
  227. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  228. if let [tup_e, idx_e] = exprs {
  229. let tup = state.eval(*tup_e, env)?;
  230. let idx = state.eval(*idx_e, env)?;
  231. state.hnf(
  232. &tup.as_tup(&state.ast.borrow(), tup_e.loc)?
  233. [idx.as_num(&state.ast.borrow(), idx_e.loc)? as usize],
  234. )
  235. } else {
  236. arity_error("tuple/index", 1, exprs)
  237. }
  238. },
  239. ),
  240. },
  241. BuiltinFunc {
  242. name: "tuple/replace",
  243. callback: Box::new(
  244. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  245. if let [tup, idx, new] = exprs {
  246. let tup_val = state.eval(*tup, env)?;
  247. let tup = tup_val.as_tup(&state.ast.borrow(), tup.loc)?;
  248. let idx = state
  249. .eval(*idx, env)?
  250. .as_num(&state.ast.borrow(), idx.loc)?;
  251. let mut modified = Vec::with_capacity(tup.len());
  252. for i in 0..idx {
  253. modified.push(tup[i as usize].clone());
  254. }
  255. modified.push(Thunk::Expr(*new, env.clone()));
  256. for i in (idx + 1)..(tup.len() as i64) {
  257. modified.push(tup[i as usize].clone());
  258. }
  259. Ok(Value::Tup(modified))
  260. } else {
  261. arity_error("tuple/replace", 3, exprs)
  262. }
  263. },
  264. ),
  265. },
  266. BuiltinFunc {
  267. name: "tuple/fold",
  268. callback: Box::new(
  269. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  270. if let [func_e, init, tup_e] = exprs {
  271. let func = state.eval(*func_e, env)?;
  272. let tup = state.eval(*tup_e, env)?;
  273. let mut result = Thunk::Expr(*init, env.clone());
  274. for t in tup.as_tup(&state.ast.borrow(), tup_e.loc)? {
  275. result = Thunk::Value(state.eval_closure(
  276. func.as_closure(&state.ast.borrow(), func_e.loc)?,
  277. vec![result, t.clone()],
  278. )?);
  279. }
  280. state.hnf(&result)
  281. } else {
  282. arity_error("tuple/fold", 3, exprs)
  283. }
  284. },
  285. ),
  286. },
  287. BuiltinFunc {
  288. name: "tuple/map",
  289. callback: Box::new(
  290. |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
  291. if let [func_e, tup_e] = exprs {
  292. let func = state.eval(*func_e, env)?;
  293. let tup = state.eval(*tup_e, env)?;
  294. let mut new_tup = Vec::new();
  295. let closure = func.as_closure(&state.ast.borrow(), func_e.loc)?;
  296. for t in tup.as_tup(&state.ast.borrow(), tup_e.loc)? {
  297. new_tup
  298. .push(Thunk::Value(state.eval_closure(closure, vec![t.clone()])?));
  299. }
  300. Ok(Value::Tup(new_tup))
  301. } else {
  302. arity_error("tuple/map", 2, exprs)
  303. }
  304. },
  305. ),
  306. },
  307. ]
  308. }