syn-param.scm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. ;;; -*- Mode: Scheme -*-
  2. ;;;; Operators with Extended Parameter Syntax, Version 2
  3. ;;; This code is written by Taylor R. Campbell and placed in the Public
  4. ;;; Domain. All warranties are disclaimed.
  5. ;;; Example:
  6. ;;;
  7. ;;; (define (foo x y z) ...)
  8. ;;;
  9. ;;; (with-extended-parameter-operators*
  10. ;;; ((foo* (<-)
  11. ;;; (foo (x (x <- ?value) ?value 0)
  12. ;;; (y (y <- ?value) ?value 0)
  13. ;;; (z (z <- ?value) ?value 0))))
  14. ;;; (foo* 5 ;First argument corresponds with X.
  15. ;;; z <- 3 ;Named argument Z
  16. ;;; y <- 1)) ;Named argument Y
  17. ;;; <=>
  18. ;;; (foo 5 1 3)
  19. ;;;
  20. ;;; WITH-EXTENDED-PARAMETER-OPERATORS* binds FOO* to a macro that
  21. ;;; accepts arguments by position or by a named pattern. The first
  22. ;;; arguments are positional, corresponding with the parameter
  23. ;;; positions X, Y, and Z. Following any positional arguments are
  24. ;;; named arguments, which match the patterns like (X <- ?VALUE), (Y <-
  25. ;;; ?VALUE), and so on. These patterns are SYNTAX-RULES patterns,
  26. ;;; where the names in (<-) and the name of the parameter are taken
  27. ;;; literally. ?VALUE is the expression for the parameter's value, and
  28. ;;; 0 is the default value if none was supplied. Once all arguments
  29. ;;; have been processed, FOO* expands to a positional call to FOO.
  30. ;;;
  31. ;;; The patterns are actually spliced into the parameter list of the
  32. ;;; FOO* macro; that's why we wrote (FOO* ... Z <- 3 ...) without any
  33. ;;; parentheses. One must write the pattern with a double layer of
  34. ;;; parentheses to require that the named parameter be passed with a
  35. ;;; single layer of parentheses. Also, each pattern must contain the
  36. ;;; parameter's name; otherwise the macro would be unable to
  37. ;;; distinguish it from the pattern for any other parameter. However,
  38. ;;; the patterns need not have similar structure; they could be (X ->
  39. ;;; ?VALUE), ((=> Z ?VALUE)), (?VALUE Z ZORGLEBLOT), and so on.
  40. ;;;
  41. ;;; There is a simpler form, WITH-EXTENDED-PARAMETER-OPERATORS, which
  42. ;;; implements a common pattern of (=> <name> <value>). This is what
  43. ;;; loop, for which this code was originally written, uses. For example,
  44. ;;;
  45. ;;; (with-extended-parameter-operators
  46. ;;; ((foo*
  47. ;;; (foo (x . 0) ;Note the dotted list.
  48. ;;; (y . 0)
  49. ;;; (z . 0))))
  50. ;;; (foo* 5 (=> z 3) (=> y 1)))
  51. ;;; <=>
  52. ;;; (foo 5 1 3)
  53. ;;; I have *voluminously* commented this hideous macro of astonishing
  54. ;;; complexity in the hopes that it can be read by any other than
  55. ;;; macrological deities. I use syntactic continuation-passing style
  56. ;;; in one small place, for a discussion of which the reader should see
  57. ;;; the Hilsdale & Friedman paper [1]; everything else is just mutually
  58. ;;; tail-recursive local macros.
  59. ;;;
  60. ;;; [1] Erik Hilsdale and Daniel P. Friedman. `Writing Macros in
  61. ;;; Continuation-Passing Style'. Scheme and Functional Programming
  62. ;;; 2000, pp. 53--60, September 2000. Available on the web:
  63. ;;; <http://repository.readscheme.org/ftp/papers/sw2000/hilsdale.ps.gz>
  64. ;;; The question mark prefix indicates pattern variables.
  65. ;;; The number of question marks indicates the nesting depth
  66. ;;; of the macro which introduced the pattern variable.
  67. ;;; An asterisk marks a syntactic continuation's environment.
  68. (define-syntax with-extended-parameter-operators*
  69. (syntax-rules ()
  70. ((with-extended-parameter-operators*
  71. ((?extended-argument-macro-name
  72. (?named-parameter-literal ...)
  73. (?positional-form-name (?parameter (?pattern ...) ?value ?default)
  74. ...))
  75. ...)
  76. ?body0
  77. ?body1
  78. ...)
  79. (letrec-syntax
  80. ((?extended-argument-macro-name
  81. (syntax-rules ()
  82. ((?extended-argument-macro-name . ??arguments)
  83. (letrec-syntax
  84. ((apply-positional
  85. (syntax-rules ()
  86. ((apply-positional ???positionals)
  87. (reverse-apply ?positional-form-name ???positionals))))
  88. ;; Process all of the leading positional arguments.
  89. ;; Once we reach a named argument, pass control on
  90. ;; to PROCESS-NAMED.
  91. ;;
  92. ;; ???PARAMETERS is the list of remaining parameter
  93. ;; specifiers (i.e. (parameter . default)) to
  94. ;; process, in order.
  95. ;;
  96. ;; ???POSITIONALS is the current reversed list of
  97. ;; positional argument expressions accumulated.
  98. ;;
  99. ;; ???ARGUMENTS is the list of remaining argument
  100. ;; expressions in the input.
  101. (process-positionals
  102. (syntax-rules (?named-parameter-literal ... ?parameter ...)
  103. ;; No more parameters -- ignore the remaining
  104. ;; arguments (signal a syntax error?), and just
  105. ;; do positional application. There were no
  106. ;; named arguments.
  107. ((process-positionals () ???positionals . ???arguments)
  108. (apply-positional ???positionals))
  109. ;; No more positional arguments; fill in default
  110. ;; values for the remaining parameters.
  111. ((process-positionals ???parameters ???positionals)
  112. (process-defaults ???parameters ???positionals))
  113. ;; Named argument -- move on to
  114. ;; PROCESS-NAMED.
  115. ((process-positionals ???parameters
  116. ???positionals
  117. ?pattern ...
  118. . ???arguments)
  119. (process-named ???parameters
  120. ???positionals
  121. ?pattern ...
  122. . ???arguments))
  123. ... ;***
  124. ;; Positional argument -- accumulate and
  125. ;; proceed.
  126. ((process-positionals (???parameter . ???parameters)
  127. ???positionals
  128. ???positional
  129. . ???arguments)
  130. (process-positionals ???parameters
  131. (???positional . ???positionals)
  132. . ???arguments))))
  133. ;; If we ran out of positional arguments, for each
  134. ;; remaining parameter specifier, fill in its
  135. ;; default expression.
  136. (process-defaults
  137. (syntax-rules ()
  138. ((process-defaults () ???positionals)
  139. (apply-positional ???positionals))
  140. ((process-defaults ((???parameter . ???default)
  141. . ???parameters/defaults)
  142. ???positionals)
  143. (process-defaults ???parameters/defaults
  144. (???default . ???positionals)))))
  145. ;; Find the named argument corresponding with each
  146. ;; parameter specifier, in order.
  147. ;;
  148. ;; ???PARAMETERS is the list of remaining parameter
  149. ;; specifiers to process, in order.
  150. ;;
  151. ;; ???POSITIONALS is the currently accumulated list
  152. ;; of positional argument expressions, in reverse
  153. ;; order.
  154. ;;
  155. ;; ???ARGUMENTS is the list of remaining arguments
  156. ;; to process. No more positional arguments are
  157. ;; allowed at this point in the game, and we never
  158. ;; take anything off of this list.
  159. (process-named
  160. (syntax-rules ()
  161. ;; No more pararmeters -- apply.
  162. ((process-named () ???positionals . ???arguments)
  163. (apply-positional ???positionals))
  164. ;; No more arguments -- fill in defaults.
  165. ((process-named ???parameters ???postionals)
  166. (process-defaults ???parameters ???positionals))
  167. ;; Match up this parameter with its argument
  168. ;; expression; then go on with the remaining
  169. ;; parameters, and all of the arguments.
  170. ((process-named ((???parameter . ???default)
  171. . ???parameters)
  172. ???positionals
  173. . ???arguments)
  174. (match-parameter-by-name
  175. ???arguments
  176. ???parameter
  177. ???default
  178. (process-named-continuation ???positionals
  179. ???parameters
  180. . ???arguments)))))
  181. ;; Continuation for the named parameter matcher.
  182. ;; When we get a value, add it to the saved list of
  183. ;; positionals, and proceed with the saved list of
  184. ;; remaining parameter specifiers, and the saved
  185. ;; list of argument expressions.
  186. (process-named-continuation
  187. (syntax-rules ()
  188. ((process-named-continuation ???value
  189. ???positionals*
  190. ???parameters*
  191. . ???arguments*)
  192. (process-named ???parameters*
  193. (???value . ???positionals*)
  194. . ???arguments*))))
  195. ;; Find the named argument corresponding with a
  196. ;; parameter specifier. If none exists, use the
  197. ;; default given.
  198. (match-parameter-by-name
  199. (syntax-rules (?named-parameter-literal ... ?parameter ...)
  200. ;; For each of the possible named parameters, if
  201. ;; it matches this one, use it -- add the
  202. ;; corresponding argument expression to the list
  203. ;; of positionals.
  204. ((match-parameter-by-name
  205. (?pattern ... . ???arguments)
  206. ?parameter
  207. ???default
  208. (???continuation . ???environment))
  209. (???continuation ?value . ???environment))
  210. ... ;***
  211. ;; Argument does not match -- skip it.
  212. ;++ Is this right? Ought we not to signal a
  213. ;++ syntax error?
  214. ((match-parameter-by-name (???argument . ???arguments)
  215. ???parameter
  216. ???default
  217. ???continuation)
  218. (match-parameter-by-name ???arguments
  219. ???parameter
  220. ???default
  221. ???continuation))
  222. ;; No more arguments -- use the default.
  223. ((match-parameter-by-name
  224. ()
  225. ???parameter
  226. ???default
  227. (???continuation . ???environment))
  228. (???continuation ???default . ???environment))))
  229. ;; Apply ???OPERATOR to the reversal of the arguments.
  230. (reverse-apply
  231. (syntax-rules ()
  232. ((reverse-apply ???operator ???reversed-arguments)
  233. (reverse-apply ???operator ???reversed-arguments ()))
  234. ((reverse-apply ???operator
  235. (???argument . ???more)
  236. ???arguments)
  237. (reverse-apply ???operator
  238. ???more
  239. (???argument . ???arguments)))
  240. ((reverse-apply ???operator () ???arguments)
  241. (???operator . ???arguments)))))
  242. ;; Start the whole process.
  243. (process-positionals ((?parameter . ?default) ...)
  244. ()
  245. . ??arguments)))))
  246. ...)
  247. ?body0
  248. ?body1
  249. ...))))
  250. ;;; This is the original WITH-EXTENDED-PARAMETER-OPERATORS, specialized
  251. ;;; to an extended parameter pattern of (=> <name> <value>), which is
  252. ;;; what loop uses.
  253. (define-syntax with-extended-parameter-operators
  254. (syntax-rules ()
  255. ((with-extended-parameter-operators
  256. ((?extended-argument-macro-name
  257. (?positional-form-name (?parameter . ?default)
  258. ...))
  259. ...)
  260. body0
  261. body1
  262. ...)
  263. (with-extended-parameter-operators*
  264. ((?extended-argument-macro-name
  265. (=>)
  266. (?positional-form-name
  267. (?parameter ((=> ?parameter ??value)) ??value ?default)
  268. ...))
  269. ...)
  270. body0
  271. body1
  272. ...))))