A fork of Crisp for HARP
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

414 lines
10 KiB

6 years ago
6 years ago
  1. require "time"
  2. require "readline"
  3. require "./expr"
  4. require "./error"
  5. require "./printer"
  6. require "./reader"
  7. module Crisp
  8. extend self
  9. macro calc_op(op)
  10. -> (args : Array(Crisp::Expr)) {
  11. x, y = args[0].unwrap, args[1].unwrap
  12. Crisp.eval_error "invalid arguments for binary operator {{op.id}}" unless x.is_a?(Int32) && y.is_a?(Int32)
  13. Crisp::Expr.new(x {{op.id}} y)
  14. }
  15. end
  16. def list(args)
  17. args.to_crisp_value
  18. end
  19. def list?(args)
  20. args.first.unwrap.is_a? Crisp::List
  21. end
  22. def empty?(args)
  23. a = args.first.unwrap
  24. a.is_a?(Array) ? a.empty? : false
  25. end
  26. def count(args)
  27. a = args.first.unwrap
  28. case a
  29. when Array
  30. a.size.as Int32
  31. when Nil
  32. 0
  33. else
  34. Crisp.eval_error "invalid argument for function 'count'"
  35. end
  36. end
  37. def pr_str(args)
  38. args.map{|a| Printer.new.print(a)}.join(" ")
  39. end
  40. def str(args)
  41. args.map{|a| Printer.new(false).print(a)}.join
  42. end
  43. def prn(args)
  44. puts self.pr_str(args)
  45. nil
  46. end
  47. def println(args)
  48. puts args.map{|a| Printer.new(false).print(a)}.join(" ")
  49. nil
  50. end
  51. def read_string(args)
  52. head = args.first.unwrap
  53. Crisp.eval_error "argument of read-str must be string" unless head.is_a? String
  54. read_str head
  55. end
  56. def slurp(args)
  57. head = args.first.unwrap
  58. Crisp.eval_error "argument of slurp must be string" unless head.is_a? String
  59. begin
  60. File.read head
  61. rescue e : Errno
  62. Crisp.eval_error "no such file"
  63. end
  64. end
  65. def cons(args)
  66. head, tail = args[0].as Crisp::Expr, args[1].unwrap
  67. Crisp.eval_error "2nd arg of cons must be list" unless tail.is_a? Array
  68. ([head] + tail).to_crisp_value
  69. end
  70. def concat(args)
  71. args.each_with_object(Crisp::List.new) do |arg, list|
  72. a = arg.unwrap
  73. Crisp.eval_error "arguments of concat must be list" unless a.is_a?(Array)
  74. a.each{|e| list << e}
  75. end
  76. end
  77. def nth(args)
  78. a0, a1 = args[0].unwrap, args[1].unwrap
  79. Crisp.eval_error "1st argument of nth must be list or vector" unless a0.is_a? Array
  80. Crisp.eval_error "2nd argument of nth must be integer" unless a1.is_a? Int32
  81. a0[a1]
  82. end
  83. def first(args)
  84. a0 = args[0].unwrap
  85. return nil if a0.nil?
  86. Crisp.eval_error "1st argument of first must be list or vector or nil" unless a0.is_a? Array
  87. a0.empty? ? nil : a0.first
  88. end
  89. def rest(args)
  90. a0 = args[0].unwrap
  91. return Crisp::List.new if a0.nil?
  92. Crisp.eval_error "1st argument of first must be list or vector or nil" unless a0.is_a? Array
  93. return Crisp::List.new if a0.empty?
  94. a0[1..-1].to_crisp_value
  95. end
  96. def apply(args)
  97. Crisp.eval_error "apply must take at least 2 arguments" unless args.size >= 2
  98. head = args.first.unwrap
  99. last = args.last.unwrap
  100. Crisp.eval_error "last argument of apply must be list or vector" unless last.is_a? Array
  101. case head
  102. when Crisp::Closure
  103. head.fn.call(args[1..-2] + last)
  104. when Crisp::Func
  105. head.call(args[1..-2] + last)
  106. else
  107. Crisp.eval_error "1st argument of apply must be function or closure"
  108. end
  109. end
  110. def map(args)
  111. func = args.first.unwrap
  112. list = args[1].unwrap
  113. Crisp.eval_error "2nd argument of map must be list or vector" unless list.is_a? Array
  114. f = case func
  115. when Crisp::Closure then func.fn
  116. when Crisp::Func then func
  117. else Crisp.eval_error "1st argument of map must be function"
  118. end
  119. list.each_with_object(Crisp::List.new) do |elem, mapped|
  120. mapped << f.call([elem])
  121. end
  122. end
  123. def nil_value?(args)
  124. args.first.unwrap.nil?
  125. end
  126. def true?(args)
  127. a = args.first.unwrap
  128. a.is_a?(Bool) && a
  129. end
  130. def false?(args)
  131. a = args.first.unwrap
  132. a.is_a?(Bool) && !a
  133. end
  134. def symbol?(args)
  135. args.first.unwrap.is_a?(Crisp::Symbol)
  136. end
  137. def symbol(args)
  138. head = args.first.unwrap
  139. Crisp.eval_error "1st argument of symbol function must be string" unless head.is_a? String
  140. Crisp::Symbol.new head
  141. end
  142. def keyword(args)
  143. head = args.first.unwrap
  144. Crisp.eval_error "1st argument of symbol function must be string" unless head.is_a? String
  145. "\u029e" + head
  146. end
  147. def keyword?(args)
  148. head = args.first.unwrap
  149. head.is_a?(String) && !head.empty? && head[0] == '\u029e'
  150. end
  151. def vector(args)
  152. args.to_crisp_value(Crisp::Vector)
  153. end
  154. def vector?(args)
  155. args.first.unwrap.is_a? Crisp::Vector
  156. end
  157. def hash_map(args)
  158. Crisp.eval_error "hash-map must take even number of arguments" unless args.size.even?
  159. map = Crisp::HashMap.new
  160. args.each_slice(2) do |kv|
  161. k = kv[0].unwrap
  162. Crisp.eval_error "key must be string" unless k.is_a? String
  163. map[k] = kv[1]
  164. end
  165. map
  166. end
  167. def map?(args)
  168. args.first.unwrap.is_a? Crisp::HashMap
  169. end
  170. def assoc(args)
  171. head = args.first.unwrap
  172. Crisp.eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap
  173. Crisp.eval_error "assoc must take a list and even number of arguments" unless (args.size - 1).even?
  174. map = Crisp::HashMap.new
  175. head.each{|k, v| map[k] = v}
  176. args[1..-1].each_slice(2) do |kv|
  177. k = kv[0].unwrap
  178. Crisp.eval_error "key must be string" unless k.is_a? String
  179. map[k] = kv[1]
  180. end
  181. map
  182. end
  183. def dissoc(args)
  184. head = args.first.unwrap
  185. Crisp.eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap
  186. map = Crisp::HashMap.new
  187. head.each{|k,v| map[k] = v}
  188. args[1..-1].each do |arg|
  189. key = arg.unwrap
  190. Crisp.eval_error "key must be string" unless key.is_a? String
  191. map.delete key
  192. end
  193. map
  194. end
  195. def get(args)
  196. a0, a1 = args[0].unwrap, args[1].unwrap
  197. return nil unless a0.is_a? Crisp::HashMap
  198. Crisp.eval_error "2nd argument of get must be string" unless a1.is_a? String
  199. # a0[a1]? isn't available because type of a0[a1] is inferred NoReturn
  200. a0.has_key?(a1) ? a0[a1] : nil
  201. end
  202. def contains?(args)
  203. a0, a1 = args[0].unwrap, args[1].unwrap
  204. Crisp.eval_error "1st argument of get must be hashmap" unless a0.is_a? Crisp::HashMap
  205. Crisp.eval_error "2nd argument of get must be string" unless a1.is_a? String
  206. a0.has_key? a1
  207. end
  208. def keys(args)
  209. head = args.first.unwrap
  210. Crisp.eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap
  211. head.keys.each_with_object(Crisp::List.new){|e,l| l << Crisp::Expr.new(e)}
  212. end
  213. def vals(args)
  214. head = args.first.unwrap
  215. Crisp.eval_error "1st argument of assoc must be hashmap" unless head.is_a? Crisp::HashMap
  216. head.values.to_crisp_value
  217. end
  218. def sequential?(args)
  219. args.first.unwrap.is_a? Array
  220. end
  221. def readline(args)
  222. head = args.first.unwrap
  223. Crisp.eval_error "1st argument of readline must be string" unless head.is_a? String
  224. Readline.readline head
  225. end
  226. def meta(args)
  227. m = args.first.meta
  228. m.nil? ? nil : m
  229. end
  230. def with_meta(args)
  231. t = args.first.dup
  232. t.meta = args[1]
  233. t
  234. end
  235. def atom(args)
  236. Crisp::Atom.new args.first
  237. end
  238. def atom?(args)
  239. args.first.unwrap.is_a? Crisp::Atom
  240. end
  241. def deref(args)
  242. head = args.first.unwrap
  243. Crisp.eval_error "1st argument of deref must be atom" unless head.is_a? Crisp::Atom
  244. head.val
  245. end
  246. def reset!(args)
  247. head = args.first.unwrap
  248. Crisp.eval_error "1st argument of reset! must be atom" unless head.is_a? Crisp::Atom
  249. head.val = args[1]
  250. end
  251. def swap!(args)
  252. atom = args.first.unwrap
  253. Crisp.eval_error "1st argument of swap! must be atom" unless atom.is_a? Crisp::Atom
  254. a = [atom.val] + args[2..-1]
  255. func = args[1].unwrap
  256. case func
  257. when Crisp::Func
  258. atom.val = func.call a
  259. when Crisp::Closure
  260. atom.val = func.fn.call a
  261. else
  262. Crisp.eval_error "2nd argumetn of swap! must be function"
  263. end
  264. end
  265. def conj(args)
  266. seq = args.first.unwrap
  267. case seq
  268. when Crisp::List
  269. (args[1..-1].reverse + seq).to_crisp_value
  270. when Crisp::Vector
  271. (seq + args[1..-1]).to_crisp_value(Crisp::Vector)
  272. else
  273. Crisp.eval_error "1st argument of conj must be list or vector"
  274. end
  275. end
  276. def time_ms(args)
  277. Time.now.epoch_ms.to_i32
  278. end
  279. # Note:
  280. # Simply using ->self.some_func doesn't work
  281. macro func(name)
  282. -> (args : Array(Crisp::Expr)) { Crisp::Expr.new self.{{name.id}}(args) }
  283. end
  284. macro rel_op(op)
  285. -> (args : Array(Crisp::Expr)) { Crisp::Expr.new (args[0] {{op.id}} args[1]) }
  286. end
  287. NameSpace = {
  288. "+" => calc_op(:+),
  289. "-" => calc_op(:-),
  290. "*" => calc_op(:*),
  291. "/" => calc_op(:/),
  292. "list" => func(:list),
  293. "list?" => func(:list?),
  294. "empty?" => func(:empty?),
  295. "count" => func(:count),
  296. "=" => rel_op(:==),
  297. "<" => rel_op(:<),
  298. ">" => rel_op(:>),
  299. "<=" => rel_op(:<=),
  300. ">=" => rel_op(:>=),
  301. "pr-str" => func(:pr_str),
  302. "str" => func(:str),
  303. "prn" => func(:prn),
  304. "println" => func(:println),
  305. "read-string" => func(:read_string),
  306. "slurp" => func(:slurp),
  307. "cons" => func(:cons),
  308. "concat" => func(:concat),
  309. "nth" => func(:nth),
  310. "first" => func(:first),
  311. "rest" => func(:rest),
  312. "throw" => -> (args : Array(Crisp::Expr)) { raise Crisp::RuntimeException.new args[0] },
  313. "apply" => func(:apply),
  314. "map" => func(:map),
  315. "nil?" => func(:nil_value?),
  316. "true?" => func(:true?),
  317. "false?" => func(:false?),
  318. "symbol?" => func(:symbol?),
  319. "symbol" => func(:symbol),
  320. "keyword" => func(:keyword),
  321. "keyword?" => func(:keyword?),
  322. "vector" => func(:vector),
  323. "vector?" => func(:vector?),
  324. "hash-map" => func(:hash_map),
  325. "map?" => func(:map?),
  326. "assoc" => func(:assoc),
  327. "dissoc" => func(:dissoc),
  328. "get" => func(:get),
  329. "contains?" => func(:contains?),
  330. "keys" => func(:keys),
  331. "vals" => func(:vals),
  332. "sequential?" => func(:sequential?),
  333. "readline" => func(:readline),
  334. "meta" => func(:meta),
  335. "with-meta" => func(:with_meta),
  336. "atom" => func(:atom),
  337. "atom?" => func(:atom?),
  338. "deref" => func(:deref),
  339. "deref" => func(:deref),
  340. "reset!" => func(:reset!),
  341. "swap!" => func(:swap!),
  342. "conj" => func(:conj),
  343. "time-ms" => func(:time_ms),
  344. } of String => Crisp::Func
  345. end