-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathstrategy-term.rkt
113 lines (93 loc) · 2.93 KB
/
strategy-term.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#lang racket/base
#|
|#
(require "strategy.rkt" "util.rkt")
;;;
;;; Abstract term access operations.
;;;
(define* (term-for-each f strategic)
(for-each f (term-fields strategic)))
(define* (term-map f strategic)
(set-term-fields strategic (map f (term-fields strategic))))
;;;
;;; Stateful term access operators.
;;;
;; Rewrites subterms of `ast` with strategy `f`, threading through
;; state `st` in the process. The function `f` must take and return an
;; extra state value, whose initial value is `st`.
(define* (term-rewrite-all/stateful f st ast)
(let ([ast
(term-rewrite-all
(lambda (ast)
(let-values ([(sub-st ast) (f st ast)])
(set! st sub-st)
ast))
ast)])
(values st ast)))
(module* test #f
(require rackunit)
(struct List (lst)
#:methods gen:strategic
[(define (term-visit-all s strategic)
(list-visit-all s (List-lst strategic)))
(define (term-rewrite-all s strategic)
(define r (list-rewrite-all s (List-lst strategic)))
(and r (List r)))
(define (term-fields strategic)
(list (List-lst strategic)))
(define (set-term-fields strategic lst)
(apply List lst))])
(define lst (List '(1 2 3)))
(let ((x 0))
(define (s ast) (set! x (add1 x)))
(define (br ast) (break))
((all-visitor s) lst)
(check-eqv? x 3)
((seq-visit-break (all-visitor s) (all-visitor s)) lst)
(check-eqv? x 9)
((seq-visit-break (all-visitor s) br (all-visitor s)) lst)
(check-eqv? x 12)))
;;;
;;; Primitive strategies.
;;;
(define-specific-data-strategy* term-all-visitor term-visit-all)
(define-specific-data-strategy* term-all-rewriter term-rewrite-all)
(define-specific-data-strategy* term-some-rewriter term-rewrite-some)
(define-specific-data-strategy* term-one-rewriter term-rewrite-one)
;;;
;;; Breakable strategies.
;;;
(struct Break () #:transparent)
(struct BreakWith (v) #:transparent)
(define-syntax* break
(syntax-rules ()
((_ v)
(BreakWith v))
((_)
(Break))))
;; A sequence that may be interrupted without failing by invoking `break`.
(define-syntax-rule* (seq-break s ...)
(lambda (ast)
(let/ec k
(and (begin (set! ast (s ast))
(when (BreakWith? ast)
(k (BreakWith-v ast)))
ast) ...
ast))))
(define-syntax-rule* (seq-visit-break s ...)
(lambda (ast)
(and (not (Break? (s ast))) ...)
(void)))
;; Not quite the Stratego `rec`, but close, and handles the common
;; case. `impl` is (-> ast (or/c ast #f)), and has both `s` and itself
;; (as `again`) in scope.
(define-syntax-rule (rec again s impl)
(lambda (s)
(letrec ([again impl])
again)))
(define* topdown-break
(rec again s
(seq-break s (all-rewriter again))))
(define* topdown-visit-break
(rec again s
(seq-visit-break s (all-rewriter again))))