Advertisement
Guest User

qq.wart

a guest
Oct 16th, 2012
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.33 KB | None | 0 0
  1. # Quasiquote (ported from an Arc port of GNU clisp 2.47's backquote.lisp).
  2.  
  3. # Like join, except it can create dotted lists if the last arg is an atom
  4.  
  5. def append args
  6. if no.args
  7. nil
  8. ~cdr.args
  9. car.args
  10. let a car.args
  11. if no.a
  12. append @cdr.args
  13. cons car.a (append cdr.a @cdr.args)
  14.  
  15. # Reproduced from arc.arc
  16.  
  17. def rreduce(f xs)
  18. if cddr.xs
  19. f car.xs (rreduce f cdr.xs)
  20. f @xs
  21.  
  22. # Like list, except that the last cons of the constructed list is dotted
  23.  
  24. def dotted_list xs
  25. if ~cdr.xs
  26. car.xs
  27. rreduce cons xs
  28.  
  29. atom? <- ~cons?
  30.  
  31. def dotted?(x)
  32. if atom?.x
  33. nil
  34. and cdr.x (or (atom? cdr.x) (dotted? cdr.x))
  35.  
  36. def proper?(xs)
  37. and list?.xs ~dotted?.xs
  38.  
  39. def qq_non_list_splice_error(expr)
  40. err:str "The syntax `,@" expr " is invalid"
  41.  
  42. def qq_dotted_splice_error(expr)
  43. err:str "The syntax `([exprs] ... ,@" expr ") is invalid"
  44.  
  45. # Quasiquotation
  46.  
  47. mac qq(expr)
  48. qq_expand expr
  49.  
  50. # Since qq handles 'unq and 'unqs, we can define those as macros down to
  51. # errors, as they're automatically outside of a qq.
  52.  
  53. mac unq(expr)
  54. list 'err:str "unq not allowed outside of a qq: " expr
  55.  
  56. mac unqs(expr)
  57. list 'err:str "unqs not allowed outside of a qq: " expr
  58.  
  59. # Recursive Expansion Engine
  60.  
  61. # The behaviour is more-or-less dictated by the Common Lisp HyperSpec's general
  62. # description of backquote:
  63. #
  64. # `atom/nil --> 'atom/nil
  65. # `,expr --> expr
  66. # `,@expr --> error
  67. # ``expr --> `expr-expanded
  68. # `list-expr --> expand each element & handle dotted tails:
  69. # `(x1 x2 ... xn) --> (append y1 y2 ... yn)
  70. # `(x1 x2 ... . xn) --> (append y1 y2 ... 'xn)
  71. # `(x1 x2 ... . ,xn) --> (append y1 y2 ... xn)
  72. # `(x1 x2 ... . ,@xn) --> error
  73. # where each yi is the output of (qq-transform xi).
  74. #
  75. # [NOTE] Mind that the above uses traditional CL syntax of "."s for dotted
  76. # tails; the "..."s represent 0 or more expressions.
  77.  
  78. carif <- (cons? & car)
  79.  
  80. def qq_expand(expr)
  81. qq_appends:qq_expand_list expr
  82.  
  83. def qq_expand(expr) :case atom?.expr
  84. list 'quote expr
  85.  
  86. def qq_expand(expr) :case (carif.expr = 'unq)
  87. cadr expr
  88.  
  89. def qq_expand(expr) :case (carif.expr = 'unqs)
  90. qq_non_list_splice_error cadr.expr
  91.  
  92. def qq_expand(expr) :case (carif.expr = 'qq)
  93. list 'qq (qq_expand cadr.expr)
  94.  
  95. # Produce a list of forms suitable for append.
  96. # Note: if we see 'unq or 'unqs in the middle of a list, we
  97. # assume it's from dotting, since (a ... (unq b)) == (a unq b). This
  98. # is a "problem" if the user does something like `(a unq b c d), which we
  99. # interpret as `(a ... ,b).
  100.  
  101. def qq_expand_list(expr)
  102. cons (qq_transform car.expr) (qq_expand_list cdr.expr)
  103.  
  104. def qq_expand_list(expr) :case no.expr
  105. nil
  106.  
  107. def qq_expand_list(expr) :case (car.expr = 'unq)
  108. list cadr.expr
  109.  
  110. def qq_expand_list(expr) :case (car.expr = 'unqs)
  111. qq_dotted_splice_error cadr.expr
  112.  
  113. def qq_expand_list(expr) :case atom?.expr
  114. list (list 'quote expr)
  115.  
  116. # Do the transformations for elements in qq_expand_list that aren't the dotted
  117. # tail. Also, handle nested quasiquotes.
  118.  
  119. def qq_transform(expr)
  120. qq_list qq_expand.expr
  121.  
  122. def qq_transform(expr) :case (carif.expr = 'unq)
  123. qq_list cadr.expr
  124.  
  125. def qq_transform(expr) :case (carif.expr = 'unqs)
  126. cadr.expr
  127.  
  128. def qq_transform(expr) :case (carif.expr = 'qq)
  129. qq_list (list 'qq (qq_expand cadr.expr))
  130.  
  131. # Expansion Optimizer
  132.  
  133. # This is mainly woven through qq_cons and qq_append. It can run in a
  134. # non-optimized mode (where lists are always consed at run-time), or
  135. # optimizations can be done that reduce run-time consing / simplify the
  136. # macroexpansion. For example,
  137. # `(,(foo) ,(bar))
  138. # non-optimized --> (append (cons (foo) nil) (cons (bar) nil))
  139. # optimized --> (list (foo) (bar))
  140.  
  141. # Optimization is disabled by default, but can be turned on when bugs get
  142. # sorted out, like:
  143. #
  144. # wart> (eval '(quote x))
  145. # 013object.cc:53 can't coerce symbol ' to function
  146. # 021eval.cc:59 Not a call: (quote x)
  147. # Perhaps you need to split the line in two.
  148. # dying
  149. #
  150. # wart> (quote 1)
  151. # 013object.cc:53 can't coerce symbol ' to function
  152. # 021eval.cc:59 Not a call: (quote 1)
  153. # Perhaps you need to split the line in two.
  154. # dying
  155.  
  156. Optimize_cons <- nil
  157. Optimize_append <- nil
  158.  
  159. def toggle_optimize()
  160. Optimize_cons <- no.Optimize_cons
  161. Optimize_append <- no.Optimize_append
  162.  
  163. # Test whether the given expr may yield multiple list elements.
  164. # Note: not only does ,@x splice, but so does ,,@x (unlike in vanilla Arc)
  165.  
  166. def splicing?(expr)
  167. or (carif.expr = 'unqs)
  168. and (carif.expr = 'unq) (splicing? cadr.expr)
  169.  
  170. def splicing_to_non(expr)
  171. if splicing?.expr
  172. list 'append expr
  173. expr
  174.  
  175. def quoted_non_splice?(expr)
  176. and (carif.expr = 'quote)
  177. single? cdr.expr
  178. ~splicing? cadr.expr
  179.  
  180. def literal?(expr)
  181. if (isa expr symbol)
  182. no expr
  183. (isa expr list)
  184. car.expr = 'quote
  185.  
  186. def qq_cons(expr1 expr2)
  187. # assume expr2 is non-splicing
  188. let operator (if splicing?.expr1 'dotted_list 'cons)
  189. if no.Optimize_cons
  190. list operator expr1 expr2
  191. (and literal?.expr1 no.expr2)
  192. list 'quote (list eval.expr1)
  193. no.expr2
  194. list 'list expr1
  195. atom?.expr2
  196. list operator expr1 expr2
  197. (carif.expr2 = 'list)
  198. dotted_list 'list expr1 cdr.expr2
  199. (and quoted_non_splice?.expr1 quoted_non_splice?.expr2)
  200. list 'quote (cons cadr.expr1) cadr.expr2
  201. :else
  202. list operator expr1 expr2
  203.  
  204. def qq_list(expr)
  205. qq_cons expr nil
  206.  
  207. def qq_append(expr1 expr2)
  208. default expr2 to: nil
  209. if no.Optimize_append
  210. list 'append expr1 expr2
  211. no.expr1
  212. expr2
  213. no.expr2
  214. expr1
  215. (carif.expr1 = 'list)
  216. qq_append_list expr1 expr2
  217. (and quoted_non_splice?.expr1
  218. proper?:cadr.expr1
  219. (carif:cadr.expr1 ~= 'unq)) # since unq expects only 1 arg
  220. (rreduce (fn (x xs) (qq_cons (list 'quote x) xs))
  221. (join cadr.expr1 list:splicing_to_non.expr2))
  222. (carif.expr2 = 'append)
  223. dotted_list 'append expr1 cdr.expr2
  224. :else
  225. list 'append expr1 expr2
  226.  
  227. def qq_append_list(expr1 expr2)
  228. if single?.expr1
  229. expr2
  230. single? cdr.expr1
  231. qq_cons cadr.expr1 expr2
  232. :else
  233. cons 'dotted_list (append cdr.expr1 list.expr2)
  234.  
  235. def qq_appends(exprs)
  236. splicing_to_non (rreduce qq_append exprs)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement