-(define (app? x)
- (and (list? x)
- (>= (length x) 2)
- (not (eq? (car x) 'let))
- (not (eq? (car x) 'lambda))))
+(define (ast-type x)
+ (define (builtin? x)
+ (case x
+ ('+ #t)
+ ('- #t)
+ ('* #t)
+ ('! #t)
+ ('= #t)
+ ('bool->int #t)
+ ('print #t)
+ (else #f)))
+ (cond
+ ((list? x)
+ (case (car x)
+ ('if 'if)
+ ('let 'let)
+ ('lambda 'lambda)
+ ('closure 'closure) ; only available in codegen
+ ('static-string 'static-string) ; only available in codegen
+ (else 'app)))
+ ((builtin? x) 'builtin)
+ ((symbol? x) 'var)
+ ((integer? x) 'int-literal)
+ ((boolean? x) 'bool-literal)
+ ((string? x) 'string-literal)))
-(define (let? x)
- (and (list? x) (eq? (car x) 'let)))
+(define (ast-traverse f x)
+ (case (ast-type x)
+ ('let `(let ,(map (lambda (x) (list (car x) (f (cadr x))))
+ (let-bindings x))
+ ,@(map f (let-body x))))
+ ('app (map f x))
+ ('lambda `(lambda ,(lambda-args x) ,(f (lambda-body x))))
+ ('if `(if ,@(map f (cdr x))))
+ (else x)))
-(define let-bindings cadr)
+(define (ast-collect f x)
+ (define (inner y) (ast-collect f y))
+ (case (ast-type x)
+ ['let (append (f x)
+ (flat-map inner (let-bindings x))
+ (flat-map inner (let-body x)))]
+ ['app (append (f x)
+ (flat-map inner x))]
+ ['lambda (append (f x)
+ (inner (lambda-body x)))]
+ ['if (append (f x)
+ (flat-map inner (cdr x)))]
+ [else (f x)]))
+
+(define (ast-find p x)
+ (define (inner y) (ast-find p y))
+ (define (any p x) (fold-left
+ (lambda (acc y) (if acc #t (p y)))
+ #f
+ x))
+ (define (either . fs)
+ (if (null? fs) #f
+ (if (car fs) (car fs)
+ (apply either (cdr fs)))))
+
+ (case (ast-type x)
+ ['let (either (p x)
+ (any inner (let-bindings x))
+ (any inner (let-body x)))]
+ ['app (either (p x)
+ (any inner x))]
+ ['lambda (either (p x)
+ (inner (lambda-body x)))]
+ ['if (either (p x) (any inner (cdr x)))]
+ [else (p x)]))
+
+(define (let-bindings e)
+ (define (pattern-match x body)
+ (if (eqv? (ast-type x) 'var)
+ (cons x body)
+ (let* ([constructor (car x)]
+ [destructor (lambda (i) `(destruct ,i ,constructor))])
+ (flat-map (lambda (y i)
+ (pattern-match y (list (destructor i) body)))
+ (cdr x)
+ (range 0 (length (cdr x)))))))
+ (flat-map (lambda (x) (pattern-match (car x) (cdr x))) (cadr e)))
(define let-body cddr)
(define (lambda? x)
(and (list? x) (eq? (car x) 'lambda)))
-(define lambda-arg cadr)
-(define lambda-body cddr)
-(define (var? x)
- (and (not (list? x)) (symbol? x)))
+(define (statement-type x)
+ (cond
+ [(and (list? x)
+ (eqv? (car x) 'data)) 'data]
+ [(and (list? x)
+ (eqv? (car x) 'define)) 'define]
+ [else 'expr]))
+
+(define (program-datas program)
+ (filter (lambda (x) (eqv? (statement-type x) 'data))
+ program))
+
+(define (program-defines program)
+ (filter (lambda (x) (eqv? (statement-type x) 'defines))
+ program))
+
+(define (program-body program)
+ `(let ()
+ ,@(filter (lambda (x) (eqv? (statement-type x) 'expr))
+ program)))
+
+; for use in normalized form
+(define lambda-arg caadr)
+; for use elsewhere
+(define lambda-args cadr)
+(define lambda-body caddr)
+
+ ; utils
+(define (range s n)
+ (if (= 0 n) '()
+ (append (range s (- n 1))
+ (list (+ s (- n 1))))))
+
+(define (flat-map f . xs) (fold-left append '() (map f xs)))
+(define (repeat x n) (if (<= n 0) '()
+ (cons x (repeat x (- n 1)))))
+
+
+(define-syntax push!
+ (syntax-rules ()
+ ((_ s x) (set! s (cons x s)))))
+
+(define-syntax pop!
+ (syntax-rules ()
+ ((_ s) (let ([x (car s)])
+ (set! s (cdr s))
+ x))))