multi-id.scrbl (13064B)
1 #lang scribble/manual 2 @require[@for-label[multi-id 3 racket/base 4 racket/contract/base] 5 scribble-enhanced] 6 7 @title{Polyvalent identifiers with @racket[multi-id]} 8 @author[@author+email["Suzanne Soy" "racket@suzanne.soy"]] 9 10 @defmodule[multi-id] 11 12 This library is implemented using literate programming. The 13 implementation details are presented in the 14 @other-doc['(lib "multi-id/multi-id.hl.rkt")] 15 document. 16 17 This package helps defining identifiers with many different meanings in 18 different contexts. An identifier can be given a meaning: 19 20 @itemlist[ 21 @item{As a type expander @racket[(: foo (Listof (ident arg …)))] 22 (see @racketmodname[type-expander #:indirect])} 23 @item{As a @tech[#:doc '(lib "scribblings/reference/reference.scrbl")]{ 24 match expander}} 25 @item{As a @tech[#:doc '(lib "scribblings/guide/guide.scrbl")]{macro} 26 (i.e. when it appears in the first position of a form)} 27 @item{As a simple identifier (i.e. used as a variable, via an 28 @tech[#:doc '(lib "scribblings/guide/guide.scrbl")]{identifier macro})} 29 @item{As a @racket[set!] subform}] 30 31 @defform[(define-multi-id name 32 maybe-type-expander 33 maybe-match-expander 34 maybe-maybe-set!+call+id 35 fallback-clause ...) 36 #:grammar ([maybe-type-expander 37 (code:line) 38 (code:line #:type-expander proc)] 39 [maybe-match-expander 40 (code:line) 41 (code:line #:match-expander proc)] 42 [maybe-set!+call+id 43 (code:line) 44 (code:line #:set!-transformer proc) 45 (code:line else) 46 (code:line maybe-set! maybe-call maybe-id)] 47 [maybe-set! 48 (code:line #:set! proc)] 49 [maybe-call 50 (code:line #:call proc) 51 (code:line #:call-id identifier)] 52 [maybe-id 53 (code:line #:id proc) 54 (code:line #:id-id identifier)] 55 [else 56 (code:line #:else-id identifier) 57 (code:line #:mutable-else-id identifier) 58 (code:line #:else identifier-expression) 59 (code:line #:mutable-else identifier-expression)] 60 [fallback-clause 61 (code:line #:??? expression)] 62 [??? "any struct-type-property?, without the prop:"])]{ 63 Defines @racket[name] as a 64 @tech[#:doc '(lib "type-expander/scribblings/type-expander.scrbl")]{ 65 type expander}, 66 @tech[#:doc '(lib "scribblings/reference/reference.scrbl")]{ 67 match expander}, 68 @seclink["set__Transformers" #:doc '(lib "scribblings/guide/guide.scrbl")]{ 69 set! transformer}, 70 @tech[#:doc '(lib 71 "scribblings/guide/guide.scrbl")]{identifier macro}, a 72 regular 73 @tech[#:doc '(lib "scribblings/guide/guide.scrbl")]{macro}, 74 some other concepts, each implemented with an arbitrary 75 @racket[struct-type-property?], 76 or combinations of those. 77 78 In the syntax described above, each @racket[proc] should 79 be a transformer procedure accepting a single 80 @racket[syntax?] argument and returning a @racket[syntax?] 81 value, i.e. the signature of each @racket[proc] should be 82 @racket[(syntax? . -> . syntax?)]. Each 83 @racket[identifier] should be an identifier, and each 84 @racket[identifier-expression] should be a compile-time 85 expression producing an identifier. 86 87 The following options are currently supported: 88 @specsubform[#:unwrap (#:??? expression) 89 #:grammar 90 ([??? "any struct-type-property?, without the prop:"])]{ 91 The identifier @racket[name] is a struct with the @racket[prop:???] struct 92 type property, using the given @racket[_expression] 93 94 In the syntax above, @racket[#:???] is only a placeholder; any keyword can be 95 used, so long as prefixing the keyword's name with @racket[prop:] gives an 96 identifier which is a @racket[struct-type-property?].} 97 @specsubform[#:unwrap (#:type-expander proc)]{ The 98 identifier @racket[name] acts as a 99 @tech[#:doc '(lib "type-expander/scribblings/type-expander.scrbl")]{ 100 type expander}, using the given @racket[proc] which 101 should return the syntax for a type.} 102 @specsubform[#:unwrap (#:match-expander proc)]{ 103 The identifier @racket[name] acts as a 104 @tech[#:doc '(lib "scribblings/reference/reference.scrbl")]{ 105 match expander}, using the given @racket[proc] which 106 should return the syntax for a match pattern.} 107 @specsubform[#:unwrap (#:set!-transformer proc)]{ 108 The identifier @racket[name] acts as a 109 @seclink["set__Transformers" #:doc '(lib "scribblings/guide/guide.scrbl")]{ 110 set! transformer}, using the given @racket[proc] which 111 should return a @racket[syntax?] value. The @racket[proc] 112 is used both when @racket[name] is used in a 113 @racket[set!] form, and when it is used as a macro or 114 identifier macro.} 115 @specsubform[#:unwrap (#:set! proc)]{ 116 The identifier @racket[name] acts as a 117 @seclink["set__Transformers" #:doc '(lib "scribblings/guide/guide.scrbl")]{ 118 set! transformer} when it is used in a @racket[set!] 119 form, using the given @racket[proc] which should return a 120 @racket[syntax?] value. 121 122 The @racket[proc] is used only when @racket[name] is used 123 in a @racket[set!] form, but not when it is used as a 124 macro or identifier macro. In these cases, @racket[#:call] and 125 @racket[#:id], respectively, are used instead. 126 127 If @racket[#:id] is not specified, but @racket[name] is used 128 as an identifier macro, the @racket[exn:fail:syntax] 129 exception is raised. If @racket[#:call] is not specified, 130 but @racket[name] is used as a regular macro, the 131 @racket[exn:fail:syntax] exception is raised.} 132 @specsubform[#:unwrap (#:call proc)]{ 133 The identifier @racket[name] 134 acts as a macro when it appears in the first position of 135 a form, using the given @racket[proc] which should return 136 a @racket[syntax?] value. 137 138 The @racket[proc] is used only when @racket[name] is used 139 as a regular macro, but not when it is used as an 140 identifier macro or when it is used in a @racket[set!] 141 form. In these cases, @racket[#:id] and @racket[#:set!], 142 respectively, are used instead. 143 144 If @racket[#:set!] is not specified, but @racket[name] is 145 used in a @racket[set!] form, the @racket[exn:fail:syntax] 146 exception is raised. If @racket[#:id] is not specified, but 147 @racket[name] is used as an identifier macro, the 148 @racket[exn:fail:syntax] exception is raised.} 149 @specsubform[#:unwrap (#:call-id identifier)]{ 150 The identifier @racket[name] 151 acts as a macro when it appears in the first position of a 152 form. The occurrence of @racket[name] is replaced by the 153 given @racket[identifier], which should either be a 154 function or a macro. 155 156 When @racket[name] is used as a macro, i.e. in a form 157 like @racket[(name . args)], the whole form is replaced 158 by @racket[(identifier . args)]. If the identifier is 159 itself a regular macro, then the whole 160 @racket[(identifier . args)] form is expanded. 161 162 The @racket[identifier] is used only when @racket[name] 163 is used as a regular macro, not when it is used as an 164 identifier macro or as a @racket[set!] transformer. 165 In these cases, @racket[#:id] and @racket[#:set!], 166 respectively, are used instead. 167 168 If @racket[#:set!] is not specified, but @racket[name] is 169 used in a @racket[set!] form, the @racket[exn:fail:syntax] 170 exception is raised. If @racket[#:id] is not specified, but 171 @racket[name] is used as an identifier macro, the 172 @racket[exn:fail:syntax] exception is raised.} 173 174 @specsubform[#:unwrap (#:id proc)]{ 175 The identifier @racket[name] acts as an 176 @tech[#:doc '(lib "scribblings/guide/guide.scrbl")]{identifier macro}, 177 using the given @racket[proc] which should return a 178 @racket[syntax?] value. 179 180 The @racket[proc] is used only when @racket[name] is used 181 as an identifier macro, but not when it appears in the 182 first position of a form, nor when it is used in a 183 @racket[set!] form. In these cases, @racket[#:call] and 184 @racket[#:set!], respectively, are used instead. 185 186 If @racket[#:set!] is not specified, but @racket[name] 187 is used in a @racket[set!] form, the @racket[exn:fail:syntax] 188 exception is raised. If @racket[#:call] is not specified, but 189 @racket[name] is used as a regular macro, the 190 @racket[exn:fail:syntax] exception is raised.} 191 192 @specsubform[#:unwrap (#:id-id proc)]{ 193 The identifier @racket[name] acts as an 194 @tech[#:doc '(lib 195 "scribblings/guide/guide.scrbl")]{identifier macro}. The 196 occurrence of @racket[name] is replaced by the given 197 @racket[identifier]. If the @racket[identifier] is itself 198 an identifier macro, it is expanded again. 199 200 The @racket[identifier] is used only when @racket[name] 201 is used as an identifier macro, but not when it appears 202 in the first position of a form, nor when it is used in a 203 @racket[set!] form. In these cases, @racket[#:call] and 204 @racket[#:set!], respectively, are used instead. 205 206 If @racket[#:set!] is not specified, but @racket[name] is 207 used in a @racket[set!] form, the @racket[exn:fail:syntax] 208 exception is raised. If @racket[#:call] is not specified, 209 but @racket[name] is used as a regular macro, 210 the @racket[exn:fail:syntax] exception is raised.} 211 212 @specsubform[#:unwrap (#:else-id identifier)]{ 213 The identifier @racket[name] 214 acts as a regular macro and as an identifier macro. The 215 occurrence of @racket[name] is replaced by the given 216 @racket[identifier], which should either be a function, or 217 be both a macro and an identifier macro at the same time. 218 219 When @racket[name] is used as an identifier macro, it is 220 replaced by @racket[identifier]. If the 221 @racket[identifier] is itself an identifier macro, then it 222 is expanded. 223 224 When @racket[name] is used as a macro, i.e. in a form 225 like @racket[(name . args)], the whole form is replaced by 226 @racket[(identifier . args)]. If the identifier is itself 227 a regular macro, then the whole 228 @racket[(identifier . args)] form is expanded. 229 230 The @racket[identifier] is not used when @racket[name] is 231 used in a @racket[set!] form, instead the 232 @racket[exn:fail:syntax] exception is raised.} 233 234 @specsubform[#:unwrap (#:mutable-else-id identifier)]{ 235 The identifier @racket[name] 236 acts as a regular macro, as an identifier macro and as a 237 @racket[set!] transformer. In all three cases, the 238 occurrence of @racket[name] is replaced by the given 239 @racket[identifier], which should either be a function, or 240 be a macro and an identifier macro and a @racket[set!] 241 transformer at the same time. 242 243 This option works like @racket[#:else-id], except that 244 @racket[name] can also be used in a @racket[set!] form. 245 246 When @racket[name] is used in a @racket[set!] form like 247 @racket[(set! name . vals)], the whole form is replaced 248 by @racket[(set! identifier . vals)]. If the identifier is 249 itself a @racket[set!] transformer, then the whole 250 @racket[(set! identifier . vals)] form is expanded.} 251 252 @specsubform[#:unwrap (#:else identifier-expression)]{ 253 The identifier @racket[name] 254 acts as a regular macro and as an identifier macro. The 255 occurrence of @racket[name] is replaced by the result of 256 the compile-time expression 257 @racket[identifier-expression], which should either 258 produce the syntax for a function, or the syntax for an 259 identifier which is both a macro and an identifier macro 260 at the same time. 261 262 It is equivalent to @racket[#:else-id], except that the 263 identifier is not constant, but is instead produced by 264 @racket[identifier-expression]. Note that 265 @racket[identifier-expression] is not a transformer 266 function (it will not be able to access the original 267 syntax). In other words, the compile-time contract for 268 @racket[identifier-expression] is @racket[syntax?], not 269 @racket[(syntax? . -> . syntax?)]. 270 271 The @racket[identifier-expression] is not used when 272 @racket[name] is used in a @racket[set!] form, instead the 273 @racket[exn:fail:syntax] exception is raised.} 274 275 @specsubform[#:unwrap (#:mutable-else identifier-expression)]{ 276 The identifier @racket[name] acts as a regular macro, as 277 an identifier macro and as a @racket[set!] transformer. In 278 all three cases, the occurrence of @racket[name] is 279 replaced by the result of the compile-time expression 280 @racket[identifier-expression], which should either 281 produce the syntax for a mutable identifier containing a 282 function, or the syntax for an identifier which is a macro 283 and an identifier macro and a @racket[set!] transformer at 284 the same time. 285 286 It is equivalent to @racket[#:mutable-else-id], except 287 that the identifier is not constant, but is instead 288 produced by @racket[identifier-expression]. Note that 289 @racket[identifier-expression] is not a transformer 290 function (it will not be able to access the original 291 syntax). In other words, the compile-time contract for 292 @racket[identifier-expression] is @racket[syntax?], not 293 @racket[(syntax? . -> . syntax?)].}}