WIP on typechecker refactor
[scheme.git] / ast.scm
diff --git a/ast.scm b/ast.scm
index 19dc7a0f5d3bea33793e1de676016be618baa103..2beb94507572eafd20b586d2ce9ef3867ec63d3e 100644 (file)
--- a/ast.scm
+++ b/ast.scm
@@ -1,11 +1,74 @@
-(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 (ast-collect f x)
+  (define (inner y) (ast-collect f y))
+  (case (ast-type x)
+    ['let (append (f x)
+                 (fold-map inner (let-bindings x))
+                 (fold-map inner (let-body x)))]
+    ['app (append (f x)
+                 (fold-map inner x))]
+    ['lambda (append (f x)
+                    (inner (lambda-body x)))]
+    ['if (append (f x)
+                (fold-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 cadr)
 (define let-body cddr)
 (define (lambda? x)
   (and (list? x) (eq? (car x) 'lambda)))
 
-(define lambda-arg cadr)
-(define lambda-body cddr)
+; for use in normalized form
+(define lambda-arg caadr)
+; for use elsewhere
+(define lambda-args cadr)
+(define lambda-body caddr)
+
+; utils
+(define (fold-map f x) (fold-left append '() (map f x)))
+(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 (var? x)
-  (and (not (list? x)) (symbol? x)))
+(define-syntax pop!
+  (syntax-rules ()
+    ((_ s) (let ([x (car s)])
+            (set! s (cdr s))
+            x))))