runtime-progress.rkt (7304B)
1 #lang racket/base 2 (require racket/list 3 syntax/parse/private/minimatch) 4 (provide ps-empty 5 ps-add-car 6 ps-add-cdr 7 ps-add-stx 8 ps-add-unbox 9 ps-add-unvector 10 ps-add-unpstruct 11 ps-add-opaque 12 ps-add-post 13 ps-add 14 (struct-out ord) 15 16 ps-pop-opaque 17 ps-pop-ord 18 ps-pop-post 19 ps-context-syntax 20 ps-difference 21 22 (struct-out failure) 23 failure* 24 25 expect? 26 (struct-out expect:thing) 27 (struct-out expect:atom) 28 (struct-out expect:literal) 29 (struct-out expect:message) 30 (struct-out expect:disj) 31 (struct-out expect:proper-pair) 32 33 es-add-thing 34 es-add-message 35 es-add-atom 36 es-add-literal 37 es-add-proper-pair) 38 39 ;; FIXME: add phase to expect:literal 40 41 ;; == Failure == 42 43 #| 44 A Failure is (failure PS ExpectStack) 45 46 A FailureSet is one of 47 - Failure 48 - (cons FailureSet FailureSet) 49 50 A FailFunction = (FailureSet -> Answer) 51 |# 52 (define-struct failure (progress expectstack) #:prefab) 53 54 ;; failure* : PS ExpectStack/#f -> Failure/#t 55 (define (failure* ps es) (if es (failure ps es) #t)) 56 57 ;; == Progress == 58 59 #| 60 Progress (PS) is a non-empty list of Progress Frames (PF). 61 62 A Progress Frame (PF) is one of 63 - stx ;; "Base" frame, or ~parse/#:with term 64 - 'car ;; car of pair; also vector->list, unbox, struct->list, etc 65 - nat ;; Represents that many repeated cdrs 66 - 'post ;; late/post-traversal check 67 - #s(ord group index) ;; ~and subpattern, only comparable w/in group 68 - 'opaque 69 70 The error-reporting context (ie, syntax-parse #:context arg) is always 71 the final frame. 72 73 All non-stx frames (eg car, cdr) interpreted as applying to nearest following 74 stx frame. 75 76 A stx frame is introduced 77 - always at base (that is, by syntax-parse) 78 - if syntax-parse has #:context arg, then two stx frames at bottom: 79 (list to-match-stx context-stx) 80 - by #:with/~parse 81 - by #:fail-*/#:when/~fail & stx 82 83 Interpretation: later frames are applied first. 84 eg, (list 'car 1 stx) 85 means ( car of ( cdr once of stx ) ) 86 NOT apply car, then apply cdr once, then stop 87 |# 88 (define-struct ord (group index) #:prefab) 89 90 (define (ps-empty stx ctx) 91 (if (eq? stx ctx) 92 (list stx) 93 (list stx ctx))) 94 (define (ps-add-car parent) 95 (cons 'car parent)) 96 (define (ps-add-cdr parent [times 1]) 97 (if (zero? times) 98 parent 99 (match (car parent) 100 [(? exact-positive-integer? n) 101 (cons (+ times n) (cdr parent))] 102 [_ 103 (cons times parent)]))) 104 (define (ps-add-stx parent stx) 105 (cons stx parent)) 106 (define (ps-add-unbox parent) 107 (ps-add-car parent)) 108 (define (ps-add-unvector parent) 109 (ps-add-car parent)) 110 (define (ps-add-unpstruct parent) 111 (ps-add-car parent)) 112 (define (ps-add-opaque parent) 113 (cons 'opaque parent)) 114 (define (ps-add parent frame) 115 (cons frame parent)) 116 (define (ps-add-post parent) 117 (cons 'post parent)) 118 119 ;; ps-context-syntax : Progress -> syntax 120 (define (ps-context-syntax ps) 121 ;; Bottom frame is always syntax 122 (last ps)) 123 124 ;; ps-difference : PS PS -> nat 125 ;; Returns N s.t. B = (ps-add-cdr^N A) 126 (define (ps-difference a b) 127 (define-values (a-cdrs a-base) 128 (match a 129 [(cons (? exact-positive-integer? a-cdrs) a-base) 130 (values a-cdrs a-base)] 131 [_ (values 0 a)])) 132 (define-values (b-cdrs b-base) 133 (match b 134 [(cons (? exact-positive-integer? b-cdrs) b-base) 135 (values b-cdrs b-base)] 136 [_ (values 0 b)])) 137 (unless (eq? a-base b-base) 138 (error 'ps-difference "INTERNAL ERROR: ~e does not extend ~e" b a)) 139 (- b-cdrs a-cdrs)) 140 141 ;; ps-pop-opaque : PS -> PS 142 ;; Used to continue with progress from opaque head pattern. 143 (define (ps-pop-opaque ps) 144 (match ps 145 [(cons (? exact-positive-integer? n) (cons 'opaque ps*)) 146 (ps-add-cdr ps* n)] 147 [(cons 'opaque ps*) 148 ps*] 149 [_ (error 'ps-pop-opaque "INTERNAL ERROR: opaque frame not found: ~e" ps)])) 150 151 ;; ps-pop-ord : PS -> PS 152 (define (ps-pop-ord ps) 153 (match ps 154 [(cons (? exact-positive-integer? n) (cons (? ord?) ps*)) 155 (ps-add-cdr ps* n)] 156 [(cons (? ord?) ps*) 157 ps*] 158 [_ (error 'ps-pop-ord "INTERNAL ERROR: ord frame not found: ~e" ps)])) 159 160 ;; ps-pop-post : PS -> PS 161 (define (ps-pop-post ps) 162 (match ps 163 [(cons (? exact-positive-integer? n) (cons 'post ps*)) 164 (ps-add-cdr ps* n)] 165 [(cons 'post ps*) 166 ps*] 167 [_ (error 'ps-pop-post "INTERNAL ERROR: post frame not found: ~e" ps)])) 168 169 170 ;; == Expectations == 171 172 #| 173 There are multiple types that use the same structures, optimized for 174 different purposes. 175 176 -- During parsing, the goal is to minimize/consolidate allocations. 177 178 An ExpectStack (during parsing) is one of 179 - (expect:thing Progress String Boolean String/#f ExpectStack) 180 - (expect:thing Progress #f #f String/#f ExpectStack) 181 * (expect:message String ExpectStack) 182 * (expect:atom Datum ExpectStack) 183 * (expect:literal Identifier ExpectStack) 184 * (expect:proper-pair FirstDesc ExpectStack) 185 * #t 186 187 The *-marked variants can only occur at the top of the stack (ie, not 188 in the next field of another Expect). The top of the stack contains 189 the most specific information. 190 191 An ExpectStack can also be #f, which means no failure tracking is 192 requested (and thus no more ExpectStacks should be allocated). 193 194 -- During reporting, the goal is ease of manipulation. 195 196 An ExpectList (during reporting) is (listof Expect). 197 198 An Expect is one of 199 - (expect:thing #f String #t String/#f StxIdx) 200 * (expect:message String StxIdx) 201 * (expect:atom Datum StxIdx) 202 * (expect:literal Identifier StxIdx) 203 * (expect:proper-pair FirstDesc StxIdx) 204 * (expect:disj (NEListof Expect) StxIdx) 205 - '... 206 207 A StxIdx is (cons Syntax Nat) 208 209 That is, the next link is replaced with the syntax+index of the term 210 being complained about. An expect:thing's progress is replaced with #f. 211 212 An expect:disj never contains a '... or another expect:disj. 213 214 We write ExpectList when the most specific information comes first and 215 RExpectList when the most specific information comes last. 216 |# 217 (struct expect:thing (term description transparent? role next) #:prefab) 218 (struct expect:message (message next) #:prefab) 219 (struct expect:atom (atom next) #:prefab) 220 (struct expect:literal (literal next) #:prefab) 221 (struct expect:disj (expects next) #:prefab) 222 (struct expect:proper-pair (first-desc next) #:prefab) 223 224 (define (expect? x) 225 (or (expect:thing? x) 226 (expect:message? x) 227 (expect:atom? x) 228 (expect:literal? x) 229 (expect:disj? x) 230 (expect:proper-pair? x))) 231 232 (define (es-add-thing ps description transparent? role next) 233 (if (and next (or description (not transparent?))) 234 (expect:thing ps description transparent? role next) 235 next)) 236 237 (define (es-add-message message next) 238 (if (and next message) 239 (expect:message message next) 240 next)) 241 242 (define (es-add-atom atom next) 243 (and next (expect:atom atom next))) 244 245 (define (es-add-literal literal next) 246 (and next (expect:literal literal next))) 247 248 (define (es-add-proper-pair first-desc next) 249 (and next (expect:proper-pair first-desc next))) 250 251 #| 252 A FirstDesc is one of 253 - #f -- unknown, multiple possible, etc 254 - string -- description 255 - (list 'any) 256 - (list 'literal symbol) 257 - (list 'datum datum) 258 |#