A fork of Crisp for HARP
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

414 lignes
10 KiB

il y a 7 ans
il y a 7 ans
  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