-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathscanner.rkt
107 lines (98 loc) · 3.11 KB
/
scanner.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
#lang typed/racket/base
(require (for-syntax typed/racket/base)
racket/match
"core-lang.rkt")
(provide
scan
Ast-scan
AstEnv-scan
Stx-scan
)
;; scanner
;;
;; NOTE: the #%name syntax reads as a symbol in Racket, but I'm
;; using it to flag primitive values.
;;
;; NOTE: this scanner can scan things like Funs and Closures for
;; testing purposes.
(define-match-expander primitive
(lambda (stx)
(syntax-case stx ()
((_ pat)
#'(? symbol?
(app symbol->string
(regexp #px"\\#\\%(.*)"
(list _ (? string? (app string->symbol pat))))))))))
(define (scan (i : Any)) : Val
(match i
;; Scan Closure:
((list (primitive 'closure) fun env)
(define f (scan fun))
(unless (Fun? f)
(error "scan: expected a fun in closure" fun))
(Closure f (AstEnv-scan env)))
;; Scan Fun:
((list (primitive 'fun) (list (? symbol? #{vars : (Listof Symbol)}) ...) body)
(Fun (map Var vars) (Ast-scan body)))
;; Scan Stx:
((list (primitive 'stx) raw-exp)
(Stx
(match (scan raw-exp)
((? Exp? exp) exp)
(_ (error "scan: bad exp for Stx" raw-exp)))
;; NOTE: Ctx not a Val, so it can't be scanned, so don't bother
;; trying to read context:
(EmptyCtx)))
;; Scan PrimAst:
((list (primitive 'ast) ast) (PrimAst (Ast-scan ast)))
;; Scan Seq:
((list subs ...) (list->Seq (map scan subs)))
;; Scan PrimOp:
((primitive name) (PrimOp name))
;; Scan Sym
((? symbol? name) (Sym name))
;; Scan Integer
((? (make-predicate Integer) i) i)
(_ (error "scan: unrecognized syntax" i))))
(define (Ast-scan (i : Any)) : Ast
(match i
;; Quoting to scan symbols and sequences as values:
((list (primitive 'val) val) (scan val))
;; Scan App:
((list op-args ...) (App (map Ast-scan op-args)))
;; Scan Var:
((? symbol? name) (Var name))
;; Everything else as a value:
(_ (scan i))))
(define (AstEnv-scan (i : Any)) : AstEnv
(match i
((list (list (? symbol? #{names : (Listof Symbol)}) vals) ...)
(for/list ((name names)
(val vals))
(list (Var name) (scan val))))))
(define (Stx-scan (i : Any)) : Stx
(match i
;; Scan Seq:
((list subs ...) (Stx (list->Seq (map Stx-scan subs)) (EmptyCtx)))
;; Scan Sym
((? symbol? name) (Stx (Sym name) (EmptyCtx)))
;; Scan Integer
((? (make-predicate Integer) i) (Stx i (EmptyCtx)))
(_ (error "Stx-scan: unrecognized syntax" i))))
(module+ test
(require typed/rackunit)
;; Scanner:
(check equal? (scan 'x)
(Sym 'x))
(check equal? (scan '(#%fun (x y) (y x)))
(Fun (list (Var 'x) (Var 'y)) (App (list (Var 'y) (Var 'x)))))
(check equal? (scan '(#%ast x))
(PrimAst (Var 'x)))
(check equal? (scan '(#%ast (x y z)))
(PrimAst (App (list (Var 'x) (Var 'y) (Var 'z)))))
(check equal? (scan '(x y z))
(Seq (Sym 'x) (Sym 'y) (Sym 'z)))
(check equal? (scan '#%cons) (PrimOp 'cons))
(check equal? (scan 1) 1)
(check equal? (scan '(#%stx 2))
(Stx 2 (EmptyCtx))))