pre-global-post-order.scrbl (3512B)
1 #lang scribble/manual 2 @require[scribble/example 3 "utils.rkt" 4 @for-label[phc-toolkit/untyped 5 extensible-parser-specifications 6 generic-syntax-expanders 7 racket/base 8 syntax/parse 9 (only-in racket/base [... …])]] 10 11 @title{Order in which the attributes are bound for post operations and 12 global operations} 13 14 Within the @racket[_A-pattern]s of post operations, the regular attributes bound 15 by all the clauses inside @racket[~seq-no-order] or @racket[~no-order] are 16 bound. The attributes defined as part of all "global" actions are bound too. The 17 attributes defined as part of "post" actions of other clauses are bound only if 18 the clause defining them appears before the current clause in the source code. 19 For example, the following code works because the clause containing 20 @racket[{~post-fail "2 is incompatible with 1" #:when (not (attribute a))}] 21 appears after the clause which binds @racket[a] with the "post" action 22 @racket[{~post-check {~bind ([a #'the-a])}}]. 23 24 @racketblock[ 25 {~seq-no-order 26 {~post-check {~and the-a 1} {~bind ([a #'the-a])}} 27 {~and 2 {~post-fail "2 is incompatible with 1" #:when (not (attribute a))}}}] 28 29 If the two clauses are swapped, then the following code would raise a syntax 30 error because @racket[a] is not bound as an attribute in the 31 @racket[~post-fail]: 32 33 @racketblock[ 34 {~seq-no-order 35 {~and 2 {~post-fail "2 is incompatible with 1" #:when (not (attribute a))}} 36 {~post-check {~and the-a 1} {~bind ([a #'the-a])}}}] 37 38 On the other hand, the following code, which does not bind @racket[a] as part 39 of a post operation, is valid: 40 41 @racketblock[ 42 {~seq-no-order 43 {~and 2 {~post-fail "2 is incompatible with 1" #:when (not (attribute a))}} 44 {~and the-a 1 {~bind ([a #'the-a])}}}] 45 46 Furthermore, the following code still works, as attributes are bound by the 47 "global" operations before the "post" operations are executed: 48 49 @racketblock[ 50 {~seq-no-order 51 {~and 2 {~post-fail "2 is incompatible with 1" #:when (not (attribute a))}} 52 {~global-or a 1}}] 53 54 Note that the order in which clauses appear within the @racket[~seq-no-order] 55 or @racket[~no-order] does not impact the order in which the elements must 56 appear in the matched syntax (aside from issues related to greediness). 57 58 @defform[(try-attribute #,tribute-name)]{ 59 This macro expands to @racket[(attribute #,tribute-name)] if 60 @racket[#,tribute-name] is bound as a syntax pattern variable, and to 61 @racket[#f] otherwise. 62 63 This macro can be used to check for mutual exclusion of an attribute which is 64 bound by other mixins that might or might not be present in the final 65 @racket[~no-order] or @racket[~seq-no-order]. 66 67 Use this sparingly, as if an syntax pattern variable with that name is bound by 68 an outer scope, the @racket[try-attribute] macro will still access it, ignorant 69 of the fact that the current @racket[~seq-no-order] does not contain any mixin 70 which binds that attribute. 71 72 Instead, it is better practice to use 73 @racket[{~global-or [_attribute-name #f]}] or 74 @racket[{~global-and [_attribute-name #t]}] to ensure that the attribute is 75 declared, while using the operation's neutral element to not alter the final 76 result.} 77 78 @defform[(if-attribute #,tribute-name if-branch else-branch)]{ 79 This macro expands to @racket[if-branch] if @racket[#,tribute-name] is bound as 80 a syntax pattern variable, and to @racket[else-branch] otherwise. 81 82 The same caveats as for @racket[try-attribute] apply.}