Merge branch 'ast3-dev'

This commit is contained in:
Justin Ethier 2018-09-12 10:35:38 -04:00
commit 61cdf4ea5c
7 changed files with 177 additions and 101 deletions

View file

@ -2,6 +2,16 @@
## 0.9.3 - TBD ## 0.9.3 - TBD
Features
- Allow pretty printing of bytevectors.
- Internal change to the compiler - preserve lambda AST forms throughout compilation process. This should make it easier to implement certain optimizations in future releases.
Bug Fixes
- Fix `input-port?`, `output-port?`, `input-port-open?`, and `output-port-open?` to return `#f` instead of raising an error when a non-port object is passed.
- Fix overflow detection when performing fixnum multiplication to avoid undefined behavior in the C runtime.
## 0.9.2 - August 26, 2018 ## 0.9.2 - August 26, 2018
Features Features

View file

@ -432,7 +432,7 @@
(wrap-mutables expr globals)) (wrap-mutables expr globals))
input-program)) input-program))
(trace:info "---------------- after wrap-mutables:") (trace:info "---------------- after wrap-mutables:")
(trace:info input-program) ;pretty-print (trace:info (ast:ast->pp-sexp input-program))
(set! input-program (set! input-program
(map (map
@ -441,17 +441,15 @@
((define? expr) ((define? expr)
;; Global ;; Global
`(define ,(define->var expr) `(define ,(define->var expr)
,@(caddr (closure-convert (define->exp expr) globals *optimization-level*)))) ,@(car (ast:lambda-body (closure-convert (define->exp expr) globals *optimization-level*)))))
((define-c? expr) ((define-c? expr)
expr) expr)
(else (else
(caddr ;; Strip off superfluous lambda (car (ast:lambda-body ;; Strip off superfluous lambda
(closure-convert expr globals *optimization-level*))))) (closure-convert expr globals *optimization-level*))))))
input-program)) input-program))
; (caddr ;; Strip off superfluous lambda
; (closure-convert input-program)))
(trace:info "---------------- after closure-convert:") (trace:info "---------------- after closure-convert:")
(trace:info input-program) ;pretty-print (trace:info (ast:ast->pp-sexp input-program))
(when (not *do-code-gen*) (when (not *do-code-gen*)
(trace:error "DEBUG, existing program") (trace:error "DEBUG, existing program")

View file

@ -1360,7 +1360,9 @@
(define-c input-port? (define-c input-port?
"(void *data, int argc, closure _, object k, object port)" "(void *data, int argc, closure _, object k, object port)"
" port_type *p = (port_type *)port; " port_type *p = (port_type *)port;
Cyc_check_port(data, port); if (boolean_f == Cyc_is_port(port)) {
return_closcall1(data, k, boolean_f);
}
return_closcall1( return_closcall1(
data, data,
k, k,
@ -1368,7 +1370,9 @@
(define-c output-port? (define-c output-port?
"(void *data, int argc, closure _, object k, object port)" "(void *data, int argc, closure _, object k, object port)"
" port_type *p = (port_type *)port; " port_type *p = (port_type *)port;
Cyc_check_port(data, port); if (boolean_f == Cyc_is_port(port)) {
return_closcall1(data, k, boolean_f);
}
return_closcall1( return_closcall1(
data, data,
k, k,
@ -1376,7 +1380,9 @@
(define-c input-port-open? (define-c input-port-open?
"(void *data, int argc, closure _, object k, object port)" "(void *data, int argc, closure _, object k, object port)"
" port_type *p = (port_type *)port; " port_type *p = (port_type *)port;
Cyc_check_port(data, port); if (boolean_f == Cyc_is_port(port)) {
return_closcall1(data, k, boolean_f);
}
return_closcall1( return_closcall1(
data, data,
k, k,
@ -1384,7 +1390,9 @@
(define-c output-port-open? (define-c output-port-open?
"(void *data, int argc, closure _, object k, object port)" "(void *data, int argc, closure _, object k, object port)"
" port_type *p = (port_type *)port; " port_type *p = (port_type *)port;
Cyc_check_port(data, port); if (boolean_f == Cyc_is_port(port)) {
return_closcall1(data, k, boolean_f);
}
return_closcall1( return_closcall1(
data, data,
k, k,

View file

@ -312,6 +312,11 @@
;; require CPS, so this flag is not applicable to them. ;; require CPS, so this flag is not applicable to them.
(define (c-compile-exp exp append-preamble cont trace cps?) (define (c-compile-exp exp append-preamble cont trace cps?)
(cond (cond
; Special case - global function w/out a closure. Create an empty closure
((ast:lambda? exp)
(c-compile-exp
`(%closure ,exp)
append-preamble cont trace cps?))
; Core forms: ; Core forms:
((const? exp) (c-compile-const exp)) ((const? exp) (c-compile-const exp))
((prim? exp) ((prim? exp)
@ -329,11 +334,6 @@
(c-compile-global exp append-preamble cont trace)) (c-compile-global exp append-preamble cont trace))
((define-c? exp) ((define-c? exp)
(c-compile-raw-global-lambda exp append-preamble cont trace)) (c-compile-raw-global-lambda exp append-preamble cont trace))
; Special case - global function w/out a closure. Create an empty closure
((tagged-list? 'lambda exp)
(c-compile-exp
`(%closure ,exp)
append-preamble cont trace cps?))
; Application: ; Application:
((app? exp) (c-compile-app exp append-preamble cont trace cps?)) ((app? exp) (c-compile-app exp append-preamble cont trace cps?))
@ -717,6 +717,28 @@
(let* ((args (app->args exp)) (let* ((args (app->args exp))
(fun (app->fun exp))) (fun (app->fun exp)))
(cond (cond
((ast:lambda? fun)
(let* ((lid (allocate-lambda (c-compile-lambda fun trace #t))) ;; TODO: pass in free vars? may be needed to track closures
;; properly, wait until this comes up in an example
(this-cont (string-append "__lambda_" (number->string lid)))
(cgen
(c-compile-args
args
append-preamble
""
this-cont
trace
cps?))
(num-cargs (c:num-args cgen)))
(set-c-call-arity! num-cargs)
(c-code
(string-append
(c:allocs->str (c:allocs cgen))
"return_direct" (number->string num-cargs)
"(data," this-cont
(if (> num-cargs 0) "," "") ; TODO: how to propagate continuation - cont " "
(c:body cgen) ");"))))
;; Direct recursive call of top-level function ;; Direct recursive call of top-level function
((and (pair? trace) ((and (pair? trace)
(not (null? (cdr trace))) (not (null? (cdr trace)))
@ -770,28 +792,6 @@
"goto loop;"))) "goto loop;")))
) )
((lambda? fun)
(let* ((lid (allocate-lambda (c-compile-lambda fun trace #t))) ;; TODO: pass in free vars? may be needed to track closures
;; properly, wait until this comes up in an example
(this-cont (string-append "__lambda_" (number->string lid)))
(cgen
(c-compile-args
args
append-preamble
""
this-cont
trace
cps?))
(num-cargs (c:num-args cgen)))
(set-c-call-arity! num-cargs)
(c-code
(string-append
(c:allocs->str (c:allocs cgen))
"return_direct" (number->string num-cargs)
"(data," this-cont
(if (> num-cargs 0) "," "") ; TODO: how to propagate continuation - cont " "
(c:body cgen) ");"))))
((prim? fun) ((prim? fun)
(let* ((c-fun (let* ((c-fun
(c-compile-prim fun cont)) (c-compile-prim fun cont))
@ -967,7 +967,7 @@
(car (define->exp exp))))) (car (define->exp exp)))))
(add-global (add-global
var var
(lambda? body) (ast:lambda? body)
(c-compile-exp (c-compile-exp
body append-preamble cont body append-preamble cont
(st:add-function! trace var) #t)) (st:add-function! trace var) #t))
@ -978,7 +978,7 @@
; ,(define-c->inline-var exp) ; ,(define-c->inline-var exp)
; ,(prim:udf? (define-c->inline-var exp)) ; ,(prim:udf? (define-c->inline-var exp))
; )) ; ))
(when (and (lambda? body) (when (and (ast:lambda? body)
(prim:udf? (define-c->inline-var exp))) (prim:udf? (define-c->inline-var exp)))
(add-global-inline (add-global-inline
var var
@ -1075,6 +1075,10 @@
(define lambdas '()) (define lambdas '())
(define inline-lambdas '()) (define inline-lambdas '())
;; TODO: may need to pass in AST lambda ID and store a mapping
;; of cgen lambda ID to it, in order to use data from the
;; analysis DB later on during code generation.
;;
; allocate-lambda : (string -> string) -> lambda-id ; allocate-lambda : (string -> string) -> lambda-id
(define (allocate-lambda lam . cps?) (define (allocate-lambda lam . cps?)
(let ((id num-lambdas)) (let ((id num-lambdas))
@ -1089,7 +1093,7 @@
; (cdr (assv id lambdas))) ; (cdr (assv id lambdas)))
(define (lambda->env exp) (define (lambda->env exp)
(let ((formals (lambda-formals->list exp))) (let ((formals (ast:lambda-formals->list exp)))
(if (pair? formals) (if (pair? formals)
(car formals) (car formals)
'unused))) 'unused)))
@ -1108,15 +1112,27 @@
;; Note this must be the count before additional closure/CPS arguments ;; Note this must be the count before additional closure/CPS arguments
;; are added, so we need to detect those and not include them. ;; are added, so we need to detect those and not include them.
(define (compute-num-args lam) (define (compute-num-args lam)
(let ((count (lambda-num-args lam))) ;; Current arg count, may be too high (let ((count (ast:lambda-num-args lam))) ;; Current arg count, may be too high
(cond (cond
((< count 0) -1) ;; Unlimited ((< count 0) -1) ;; Unlimited
(else (else
(let ((formals (lambda-formals->list lam))) (let ((formals (ast:lambda-formals->list lam)))
(- count (- count
(if (fl/closure? formals) 1 0) (if (fl/closure? formals) 1 0)
(if (fl/cont? formals) 1 0))))))) (if (fl/cont? formals) 1 0)))))))
;; Minimum number of required arguments for a lambda
(define (ast:lambda-num-args exp)
(let ((type (ast:lambda-formals-type exp))
(num (length (ast:lambda-formals->list exp))))
(cond
((equal? type 'args:varargs)
-1) ;; Unlimited
((equal? type 'args:fixed-with-varargs)
(- num 1)) ;; Last arg is optional
(else
num))))
;; Formal list with a closure? ;; Formal list with a closure?
(define (fl/closure? lis) (define (fl/closure? lis)
(cond (cond
@ -1254,13 +1270,13 @@
(let* ((formals (c-compile-formals (let* ((formals (c-compile-formals
(if (not cps?) (if (not cps?)
;; Ignore continuation (k) arg for non-CPS funcs ;; Ignore continuation (k) arg for non-CPS funcs
(cdr (lambda->formals exp)) (cdr (ast:lambda-args exp))
(lambda->formals exp)) (ast:lambda-args exp))
(lambda-formals-type exp))) (ast:lambda-formals-type exp)))
(tmp-ident (if (> (length (lambda-formals->list exp)) 0) (tmp-ident (if (> (length (ast:lambda-formals->list exp)) 0)
(mangle (if (pair? (lambda->formals exp)) (mangle (if (pair? (ast:lambda-args exp))
(car (lambda->formals exp)) (car (ast:lambda-args exp))
(lambda->formals exp))) (ast:lambda-args exp)))
"")) ""))
(return-type (return-type
(if cps? "void" "object")) (if cps? "void" "object"))
@ -1288,7 +1304,7 @@
formals)) formals))
(env-closure (lambda->env exp)) (env-closure (lambda->env exp))
(body (c-compile-exp (body (c-compile-exp
(car (lambda->exp exp)) ;; car ==> assume single expr in lambda body after CPS (car (ast:lambda-body exp)) ;; car ==> assume single expr in lambda body after CPS
append-preamble append-preamble
(mangle env-closure) (mangle env-closure)
trace trace
@ -1300,18 +1316,18 @@
formals* formals*
") {\n" ") {\n"
preamble preamble
(if (lambda-varargs? exp) (if (ast:lambda-varargs? exp)
;; Load varargs from C stack into Scheme list ;; Load varargs from C stack into Scheme list
(string-append (string-append
; DEBUGGING: ; DEBUGGING:
;"printf(\"%d %d\\n\", argc, " ;"printf(\"%d %d\\n\", argc, "
; (number->string (length (lambda-formals->list exp))) ");" ; (number->string (length (ast:lambda-formals->list exp))) ");"
"load_varargs(" "load_varargs("
(mangle (lambda-varargs-var exp)) (mangle (ast:lambda-varargs-var exp))
", " ", "
(mangle (lambda-varargs-var exp)) (mangle (ast:lambda-varargs-var exp))
"_raw, argc - " (number->string "_raw, argc - " (number->string
(- (length (lambda-formals->list exp)) (- (length (ast:lambda-formals->list exp))
1 1
(if has-closure? 1 0))) (if has-closure? 1 0)))
");\n"); ");\n");
@ -1337,6 +1353,18 @@
(define cgen:mangle-global #f) (define cgen:mangle-global #f)
(define (ast:lambda-varargs-var exp)
(if (ast:lambda-varargs? exp)
(if (equal? (ast:lambda-formals-type exp) 'args:varargs)
(ast:lambda-args exp) ; take symbol directly
(car (reverse (ast:lambda-formals->list exp)))) ; Last arg is varargs
#f))
(define (ast:lambda-varargs? exp)
(let ((type (ast:lambda-formals-type exp)))
(or (equal? type 'args:varargs)
(equal? type 'args:fixed-with-varargs))))
;; Convert a library name to string, so it can be ;; Convert a library name to string, so it can be
;; appended to the identifiers it exports. ;; appended to the identifiers it exports.
(define (import->string import) (define (import->string import)

View file

@ -1573,7 +1573,26 @@
(define (_closure-convert exp globals optimization-level) (define (_closure-convert exp globals optimization-level)
(define (convert exp self-var free-var-lst) (define (convert exp self-var free-var-lst)
(define (cc exp) (define (cc exp)
;(trace:error `(cc ,exp))
(cond (cond
((ast:lambda? exp)
(let* ((new-self-var (gensym 'self))
(body (ast:lambda-body exp))
(new-free-vars
(difference
(difference (free-vars body) (ast:lambda-formals->list exp))
globals)))
`(%closure
,(ast:%make-lambda
(ast:lambda-id exp)
(list->lambda-formals
(cons new-self-var (ast:lambda-formals->list exp))
(ast:lambda-formals-type exp))
(list (convert (car body) new-self-var new-free-vars))
(ast:lambda-has-cont exp))
,@(map (lambda (v) ;; TODO: splice here?
(cc v))
new-free-vars))))
((const? exp) exp) ((const? exp) exp)
((quote? exp) exp) ((quote? exp) exp)
((ref? exp) ((ref? exp)
@ -1591,22 +1610,7 @@
,@(map cc (cdr exp)))) ;; TODO: need to splice? ,@(map cc (cdr exp)))) ;; TODO: need to splice?
((set!? exp) `(set! ,(set!->var exp) ((set!? exp) `(set! ,(set!->var exp)
,(cc (set!->exp exp)))) ,(cc (set!->exp exp))))
((lambda? exp) ((lambda? exp) (error `(Unexpected lambda in closure-convert ,exp)))
(let* ((new-self-var (gensym 'self))
(body (lambda->exp exp))
(new-free-vars
(difference
(difference (free-vars body) (lambda-formals->list exp))
globals)))
`(%closure
(lambda
,(list->lambda-formals
(cons new-self-var (lambda-formals->list exp))
(lambda-formals-type exp))
,(convert (car body) new-self-var new-free-vars)) ;; TODO: should this be a map??? was a list in 90-min-scc.
,@(map (lambda (v) ;; TODO: splice here?
(cc v))
new-free-vars))))
((if? exp) `(if ,@(map cc (cdr exp)))) ((if? exp) `(if ,@(map cc (cdr exp))))
((cell? exp) `(cell ,(cc (cell->value exp)))) ((cell? exp) `(cell ,(cc (cell->value exp))))
((cell-get? exp) `(cell-get ,(cc (cell-get->cell exp)))) ((cell-get? exp) `(cell-get ,(cc (cell-get->cell exp))))
@ -1616,16 +1620,16 @@
(let ((fn (car exp)) (let ((fn (car exp))
(args (map cc (cdr exp)))) (args (map cc (cdr exp))))
(cond (cond
((lambda? fn) ((ast:lambda? fn)
(cond (cond
;; If the lambda argument is not used, flag so the C code is ;; If the lambda argument is not used, flag so the C code is
;; all generated within the same function ;; all generated within the same function
((and #f ((and #f
(> optimization-level 0) (> optimization-level 0)
(eq? (lambda-formals-type fn) 'args:fixed) (eq? (ast:lambda-formals-type fn) 'args:fixed)
(pair? (lambda-formals->list fn)) (pair? (ast:lambda-formals->list fn))
(with-var (with-var
(car (lambda-formals->list fn)) (car (ast:lambda-formals->list fn))
(lambda (var) (lambda (var)
(zero? (adbv:ref-count var)))) (zero? (adbv:ref-count var))))
;; Non-CPS args ;; Non-CPS args
@ -1638,30 +1642,40 @@
args)) args))
`(Cyc-seq `(Cyc-seq
,@args ,@args
,@(map cc (lambda->exp fn)))) ,@(map cc (ast:lambda-body fn))))
(else (else
(let* ((body (lambda->exp fn)) (let* ((body (ast:lambda-body fn))
(new-free-vars (new-free-vars
(difference (difference
(difference (free-vars body) (lambda-formals->list fn)) (difference (free-vars body) (ast:lambda-formals->list fn))
globals)) globals))
(new-free-vars? (> (length new-free-vars) 0))) (new-free-vars? (> (length new-free-vars) 0)))
(if new-free-vars? (if new-free-vars?
; Free vars, create a closure for them ; Free vars, create a closure for them
(let* ((new-self-var (gensym 'self))) (let* ((new-self-var (gensym 'self)))
`((%closure `((%closure
(lambda ,(ast:%make-lambda
,(list->lambda-formals (ast:lambda-id fn)
(cons new-self-var (lambda-formals->list fn)) (list->lambda-formals
(lambda-formals-type fn)) (cons new-self-var (ast:lambda-formals->list fn))
,(convert (car body) new-self-var new-free-vars)) (ast:lambda-formals-type fn))
(list (convert (car body) new-self-var new-free-vars))
(ast:lambda-has-cont fn)
)
,@(map (lambda (v) (cc v)) ,@(map (lambda (v) (cc v))
new-free-vars)) new-free-vars))
,@args)) ,@args))
; No free vars, just create simple lambda ; No free vars, just create simple lambda
`((lambda ,(lambda->formals fn) `(,(ast:%make-lambda
,@(map cc body)) (ast:lambda-id fn)
,@args)))))) (ast:lambda-args fn)
(map cc body)
(ast:lambda-has-cont fn)
)
,@args)
)))))
((lambda? fn) (error `(Unexpected lambda in closure-convert ,exp)))
(else (else
(let ((f (cc fn))) (let ((f (cc fn)))
`((%closure-ref ,f 0) `((%closure-ref ,f 0)
@ -1671,8 +1685,10 @@
(error "unhandled exp: " exp)))) (error "unhandled exp: " exp))))
(cc exp)) (cc exp))
`(lambda () (ast:make-lambda
,(convert exp #f '()))) (list)
(list (convert exp #f '()))
#f))
(define (analyze:find-named-lets exp) (define (analyze:find-named-lets exp)
(define (scan exp lp) (define (scan exp lp)

View file

@ -84,6 +84,9 @@
(cond ((pair? obj) (wr-expr obj col)) (cond ((pair? obj) (wr-expr obj col))
((null? obj) (wr-lst obj col)) ((null? obj) (wr-lst obj col))
((vector? obj) (wr-lst (vector->list obj) (out "#" col))) ((vector? obj) (wr-lst (vector->list obj) (out "#" col)))
((bytevector? obj) (wr-lst
(map char->integer (string->list (utf8->string obj)))
(out "#u8" col)))
((boolean? obj) (out (if obj "#t" "#f") col)) ((boolean? obj) (out (if obj "#t" "#f") col))
((number? obj) (out (number->string obj) col)) ((number? obj) (out (number->string obj) col))
((symbol? obj) (out (symbol->string obj) col)) ((symbol? obj) (out (symbol->string obj) col))

View file

@ -630,6 +630,9 @@
(define (search exp) (define (search exp)
(cond (cond
; Core forms: ; Core forms:
((ast:lambda? exp)
(difference (reduce union (map search (ast:lambda-body exp)) '())
(ast:lambda-formals->list exp)))
((const? exp) '()) ((const? exp) '())
((prim? exp) '()) ((prim? exp) '())
((quote? exp) '()) ((quote? exp) '())
@ -726,22 +729,34 @@
; wrap-mutables : exp -> exp ; wrap-mutables : exp -> exp
(define (wrap-mutables exp globals) (define (wrap-mutables exp globals)
(define (wrap-mutable-formals formals body-exp) (define (wrap-mutable-formals id formals body-exp has-cont)
(if (not (pair? formals)) (if (not (pair? formals))
body-exp body-exp
;(list body-exp)
(if (is-mutable? (car formals)) (if (is-mutable? (car formals))
`((lambda (,(car formals)) (list
,(wrap-mutable-formals (cdr formals) body-exp)) (list ;(ast:%make-lambda
(cell ,(car formals))) ; id
(wrap-mutable-formals (cdr formals) body-exp)))) (ast:make-lambda
(list (car formals))
(wrap-mutable-formals id (cdr formals) body-exp has-cont)
has-cont)
`(cell ,(car formals))))
(wrap-mutable-formals id (cdr formals) body-exp has-cont))))
(cond (cond
; Core forms: ; Core forms:
((ast:lambda? exp) ((ast:lambda? exp)
`(lambda ,(ast:lambda-args exp) (ast:%make-lambda
,(wrap-mutable-formals (ast:lambda-id exp)
(ast:lambda-args exp)
(wrap-mutable-formals
(ast:lambda-id exp)
(ast:lambda-formals->list exp) (ast:lambda-formals->list exp)
(wrap-mutables (car (ast:lambda-body exp)) globals)))) ;; Assume single expr in lambda body, since after CPS phase (list (wrap-mutables (car (ast:lambda-body exp)) globals))
(ast:lambda-has-cont exp))
(ast:lambda-has-cont exp)
)) ;; Assume single expr in lambda body, since after CPS phase
((const? exp) exp) ((const? exp) exp)
((ref? exp) (if (and (not (member exp globals)) ((ref? exp) (if (and (not (member exp globals))
(is-mutable? exp)) (is-mutable? exp))
@ -749,9 +764,7 @@
exp)) exp))
((prim? exp) exp) ((prim? exp) exp)
((quote? exp) exp) ((quote? exp) exp)
((lambda? exp) `(lambda ,(lambda->formals exp) ((lambda? exp) (error `(Unexpected lambda in wrap-mutables ,exp)))
,(wrap-mutable-formals (lambda-formals->list exp)
(wrap-mutables (car (lambda->exp exp)) globals)))) ;; Assume single expr in lambda body, since after CPS phase
((set!? exp) `(,(if (member (set!->var exp) globals) ((set!? exp) `(,(if (member (set!->var exp) globals)
'set-global! 'set-global!
'set-cell!) 'set-cell!)