306 lines
14 KiB
Scheme
306 lines
14 KiB
Scheme
;;; cprep.ss
|
|
;;; Copyright 1984-2017 Cisco Systems, Inc.
|
|
;;;
|
|
;;; Licensed under the Apache License, Version 2.0 (the "License");
|
|
;;; you may not use this file except in compliance with the License.
|
|
;;; You may obtain a copy of the License at
|
|
;;;
|
|
;;; http://www.apache.org/licenses/LICENSE-2.0
|
|
;;;
|
|
;;; Unless required by applicable law or agreed to in writing, software
|
|
;;; distributed under the License is distributed on an "AS IS" BASIS,
|
|
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
;;; See the License for the specific language governing permissions and
|
|
;;; limitations under the License.
|
|
|
|
|
|
(let ()
|
|
(import (nanopass))
|
|
(include "types.ss")
|
|
(include "base-lang.ss")
|
|
(include "expand-lang.ss")
|
|
|
|
(define-who Lexpand-to-go
|
|
(lambda (x go)
|
|
(define-pass go-Inner : (Lexpand Inner) (ir) -> * (val)
|
|
(Inner : Inner (ir) -> * (val)
|
|
[,lsrc (go lsrc)]
|
|
[(program ,uid ,body) (go ($build-invoke-program uid body))]
|
|
[(library/ct ,uid (,export-id* ...) ,import-code ,visit-code)
|
|
(go ($build-install-library/ct-code uid export-id* import-code visit-code))]
|
|
[(library/rt ,uid (,dl* ...) (,db* ...) (,dv* ...) (,de* ...) ,body)
|
|
(go ($build-install-library/rt-code uid dl* db* dv* de* body))]
|
|
[(library/ct-info ,linfo/ct)
|
|
`(library/ct-info ,(library-info-uid linfo/ct) ,(library/ct-info-import-req* linfo/ct)
|
|
,(library/ct-info-visit-visit-req* linfo/ct)
|
|
,(library/ct-info-visit-req* linfo/ct))]
|
|
[(library/rt-info ,linfo/rt) `(library/rt-info ,(library-info-uid linfo/rt) ,(library/rt-info-invoke-req* linfo/rt))]
|
|
[(program-info ,pinfo) `(program-info ,(program-info-invoke-req* pinfo))])
|
|
(Inner ir))
|
|
(let ([x* (let f ([x x] [x* '()])
|
|
(nanopass-case (Lexpand Outer) x
|
|
[(group ,outer1 ,outer2) (f outer1 (f outer2 x*))]
|
|
[(visit-only ,inner) (cons `(eval-when (visit) ,(go-Inner inner)) x*)]
|
|
[(revisit-only ,inner) (cons `(eval-when (revisit) ,(go-Inner inner)) x*)]
|
|
[,inner (cons (go-Inner inner) x*)]
|
|
[(recompile-info ,rcinfo) (cons `(recompile-requirements ,(recompile-info-import-req* rcinfo) ,(recompile-info-include-req* rcinfo)) x*)]
|
|
[else (sorry! who "unexpected language form ~s" x)]))])
|
|
(safe-assert (not (null? x*)))
|
|
(cond
|
|
[(= (length x*) 1) (car x*)]
|
|
[else `(begin ,@x*)]))))
|
|
|
|
(set-who! $uncprep
|
|
(rec $uncprep
|
|
(case-lambda
|
|
[(x) ($uncprep x #f)]
|
|
[(x sexpr?)
|
|
(define cache-sexpr
|
|
(lambda (preinfo thunk)
|
|
(if sexpr?
|
|
(or (preinfo-sexpr preinfo)
|
|
(let ([sexpr (thunk)])
|
|
(preinfo-sexpr-set! preinfo sexpr)
|
|
sexpr))
|
|
(thunk))))
|
|
(define get-name
|
|
(lambda (x)
|
|
(if sexpr? (prelex-name x) (prelex-uname x))))
|
|
(define uncprep-lambda-clause
|
|
(lambda (cl)
|
|
(nanopass-case (Lsrc CaseLambdaClause) cl
|
|
[(clause (,x* ...) ,interface ,body)
|
|
`(,(if (fx< interface 0)
|
|
(let f ((x* x*))
|
|
(if (pair? (cdr x*))
|
|
(cons (get-name (car x*)) (f (cdr x*)))
|
|
(get-name (car x*))))
|
|
(map get-name x*))
|
|
,@(uncprep-sequence body '()))])))
|
|
(define uncprep-sequence
|
|
(lambda (x ls)
|
|
(nanopass-case (Lsrc Expr) x
|
|
[(profile ,src) (guard (not (null? ls))) ls]
|
|
[(seq ,e1 ,e2)
|
|
(uncprep-sequence e1
|
|
(uncprep-sequence e2 ls))]
|
|
[else (cons (uncprep x) ls)])))
|
|
(define uncprep-fp-conv
|
|
(lambda (x*)
|
|
(map (lambda (x)
|
|
(case x
|
|
[(i3nt-stdcall) '__stdcall]
|
|
[(i3nt-com) '__com]
|
|
[(adjust-active) '__collect_safe]
|
|
[else #f]))
|
|
x*)))
|
|
(define-who uncprep-fp-specifier
|
|
(lambda (x)
|
|
(nanopass-case (Ltype Type) x
|
|
[(fp-void) 'void]
|
|
[(fp-integer ,bits)
|
|
(case bits
|
|
[(8) 'integer-8]
|
|
[(16) 'integer-16]
|
|
[(32) 'integer-32]
|
|
[(64) 'integer-64]
|
|
[else ($oops who "invalid integer size ~s" bits)])]
|
|
[(fp-unsigned ,bits)
|
|
(case bits
|
|
[(8) 'unsigned-8]
|
|
[(16) 'unsigned-16]
|
|
[(32) 'unsigned-32]
|
|
[(64) 'unsigned-64]
|
|
[else ($oops who "invalid unsigned size ~s" bits)])]
|
|
[(fp-scheme-object) 'scheme-object]
|
|
[(fp-u8*) 'u8*]
|
|
[(fp-u16*) 'u16*]
|
|
[(fp-u32*) 'u32*]
|
|
[(fp-fixnum) 'fixnum]
|
|
[(fp-double-float) 'double-float]
|
|
[(fp-single-float) 'single-float]
|
|
[(fp-ftd ,ftd) 'ftype]
|
|
[(fp-ftd& ,ftd) 'ftype])))
|
|
(define uncprep
|
|
(lambda (x)
|
|
(define keyword?
|
|
(lambda (x)
|
|
(memq x
|
|
; UPDATE THIS if new keywords are added
|
|
'(let $primitive quote begin case-lambda
|
|
library-case-lambda lambda if set!
|
|
letrec letrec* $foreign-procedure
|
|
$foreign-callable eval-when))))
|
|
(nanopass-case (Lsrc Expr) x
|
|
[(ref ,maybe-src ,x) (get-name x)]
|
|
[(call ,preinfo0 (case-lambda ,preinfo1 (clause (,x* ...) ,interface ,body)) ,e* ...)
|
|
(guard (fx= (length e*) interface))
|
|
(cache-sexpr preinfo0
|
|
(lambda ()
|
|
(if (null? x*)
|
|
(uncprep body)
|
|
`(let ,(map (lambda (x e)
|
|
`(,(get-name x) ,(uncprep e)))
|
|
x* e*)
|
|
,@(uncprep-sequence body '())))))]
|
|
[(call ,preinfo ,pr (quote ,d))
|
|
(guard (eq? (primref-name pr) '$top-level-value) (symbol? d)
|
|
(not (or (eq? ($real-sym-name d (interaction-environment)) d) (keyword? d))))
|
|
(cache-sexpr preinfo
|
|
(lambda ()
|
|
($real-sym-name d (interaction-environment))))]
|
|
[(call ,preinfo ,pr (quote ,d) ,e)
|
|
(guard (eq? (primref-name pr) '$set-top-level-value!) (symbol? d)
|
|
(not (or (eq? ($real-sym-name d (interaction-environment)) d) (keyword? d))))
|
|
(cache-sexpr preinfo
|
|
(lambda ()
|
|
`(set! ,($real-sym-name d (interaction-environment)) ,(uncprep e))))]
|
|
[(call ,preinfo ,e ,e* ...)
|
|
(cache-sexpr preinfo
|
|
(lambda ()
|
|
`(,(uncprep e) ,@(map uncprep e*))))]
|
|
[,pr (let ([sym (primref-name pr)])
|
|
(if sexpr?
|
|
($sgetprop sym '*unprefixed* sym)
|
|
`($primitive ,(primref-level pr) ,sym)))]
|
|
[(quote ,d)
|
|
(cond
|
|
[(eq? d (void)) '(#2%void)]
|
|
[(self-evaluating? d) d]
|
|
[else `(quote ,d)])]
|
|
[(seq ,e1 ,e2)
|
|
(let ([ls (uncprep-sequence x '())])
|
|
(if (null? (cdr ls))
|
|
(car ls)
|
|
`(begin ,@ls)))]
|
|
[(case-lambda ,preinfo ,cl* ...)
|
|
(cache-sexpr preinfo
|
|
(lambda ()
|
|
(let ((cl* (map uncprep-lambda-clause cl*)))
|
|
(if (and (not (null? cl*)) (null? (cdr cl*)))
|
|
`(lambda ,@(car cl*))
|
|
`(case-lambda ,@cl*)))))]
|
|
[(if ,[e0] ,[e1] ,[e2]) `(if ,e0 ,e1 ,e2)]
|
|
[(set! ,maybe-src ,x ,[e]) `(set! ,(get-name x) ,e)]
|
|
[(letrec ([,x* ,[e*]] ...) ,body)
|
|
`(letrec ,(map (lambda (x e) `(,(get-name x) ,e)) x* e*)
|
|
,@(uncprep-sequence body '()))]
|
|
[(letrec* ([,x* ,[e*]] ...) ,body)
|
|
`(letrec* ,(map (lambda (x e) `(,(get-name x) ,e)) x* e*)
|
|
,@(uncprep-sequence body '()))]
|
|
[(foreign (,conv* ...) ,name ,[e] (,arg-type* ...) ,result-type)
|
|
`($foreign-procedure ,(uncprep-fp-conv conv*) ,name ,e
|
|
,(map uncprep-fp-specifier arg-type*)
|
|
,(uncprep-fp-specifier result-type))]
|
|
[(fcallable (,conv* ...) ,[e] (,arg-type* ...) ,result-type)
|
|
`($foreign-callable ,(uncprep-fp-conv conv*) ,e
|
|
,(map uncprep-fp-specifier arg-type*)
|
|
,(uncprep-fp-specifier result-type))]
|
|
[(record-ref ,rtd ,type ,index ,[e]) `(record-ref ,rtd ',type ,e ,index)]
|
|
[(record-set! ,rtd ,type ,index ,[e1] ,[e2]) `(record-set! ,rtd ',type ,e1 ,index ,e2)]
|
|
[(record ,rtd ,[rtd-expr] ,[e*] ...) `(record ,rtd ,rtd-expr ,@e*)]
|
|
[(record-type ,rtd ,[e]) `(record-type ,rtd ,e)]
|
|
[(record-cd ,rcd ,rtd-expr ,[e]) `(record-cd ,rcd ,e)]
|
|
[(immutable-list (,e* ...) ,[e]) e]
|
|
[(moi) ''moi]
|
|
[(pariah) `(pariah (void))]
|
|
[(profile ,src) `(void)]
|
|
[(cte-optimization-loc ,box ,[e]) e]
|
|
; for debugging:
|
|
[(cpvalid-defer ,[e]) `(cpvalid-defer ,e)]
|
|
[else ($oops who "unexpected record ~s" x)])))
|
|
(Lexpand-to-go x uncprep)])))
|
|
|
|
(let ()
|
|
(define (default-env)
|
|
(if (eq? (subset-mode) 'system)
|
|
($system-environment)
|
|
(interaction-environment)))
|
|
(define e/o
|
|
(lambda (who cte? x env)
|
|
(define (go x)
|
|
($uncprep
|
|
($cpcommonize
|
|
($cpcheck
|
|
(let ([cpletrec-ran? #f])
|
|
(let ([x ((run-cp0)
|
|
(lambda (x)
|
|
(set! cpletrec-ran? #t)
|
|
($cpletrec ($cp0 x $compiler-is-loaded?)))
|
|
($cpvalid x))])
|
|
(if cpletrec-ran? x ($cpletrec x))))))))
|
|
(unless (environment? env)
|
|
($oops who "~s is not an environment" env))
|
|
; claim compiling-a-file to get cte as well as run-time code
|
|
(Lexpand-to-go (expand x env #t cte?) go)))
|
|
(set-who! expand/optimize
|
|
(case-lambda
|
|
[(x) (e/o who #f x (default-env))]
|
|
[(x env) (e/o who #f x env)]))
|
|
(set-who! $expand/cte/optimize
|
|
(case-lambda
|
|
[(x) (e/o who #t x (default-env))]
|
|
[(x env) (e/o who #t x env)]))
|
|
(set-who! $expand/cte
|
|
(rec expand/cte
|
|
(case-lambda
|
|
[(x) (expand/cte x (default-env))]
|
|
[(x env)
|
|
(unless (environment? env)
|
|
($oops who "~s is not an environment" env))
|
|
; claim compiling-a-file to get cte as well as run-time code
|
|
($uncprep (expand x env #t #t))]))))
|
|
|
|
(set-who! $cpcheck-prelex-flags
|
|
(lambda (x after-pass)
|
|
(import (nanopass))
|
|
(include "base-lang.ss")
|
|
|
|
(define-pass cpcheck-prelex-flags : Lsrc (ir) -> Lsrc ()
|
|
(definitions
|
|
#;(define sorry!
|
|
(lambda (who str . arg*)
|
|
(apply fprintf (console-output-port) str arg*)
|
|
(newline (console-output-port))))
|
|
(define initialize-id!
|
|
(lambda (id)
|
|
(prelex-flags-set! id
|
|
(let ([flags (prelex-flags id)])
|
|
(fxlogor
|
|
(fxlogand flags (constant prelex-sticky-mask))
|
|
(fxsll (fxlogand flags (constant prelex-is-mask))
|
|
(constant prelex-was-flags-offset))))))))
|
|
(Expr : Expr (ir) -> Expr ()
|
|
[(ref ,maybe-src ,x)
|
|
(when (prelex-operand x) (sorry! who "~s has an operand after ~s (src ~s)" x after-pass maybe-src))
|
|
(unless (prelex-was-referenced x) (sorry! who "~s referenced but not so marked after ~s (src ~s)" x after-pass maybe-src))
|
|
(when (prelex-referenced x)
|
|
(unless (prelex-was-multiply-referenced x) (sorry! who "~s multiply referenced but not so marked after ~s (src ~s)" x after-pass maybe-src))
|
|
(set-prelex-multiply-referenced! x #t))
|
|
(set-prelex-referenced! x #t)
|
|
`(ref ,maybe-src ,x)]
|
|
[(set! ,maybe-src ,x ,[e])
|
|
(unless (prelex-was-assigned x) (sorry! who "~s assigned but not so marked after ~s (src ~s)" x after-pass maybe-src))
|
|
(set-prelex-assigned! x #t)
|
|
`(set! ,maybe-src ,x ,e)]
|
|
[(letrec ([,x* ,e*] ...) ,body)
|
|
(for-each initialize-id! x*)
|
|
`(letrec ([,x* ,(map Expr e*)] ...) ,(Expr body))]
|
|
[(letrec* ([,x* ,e*] ...) ,body)
|
|
(for-each initialize-id! x*)
|
|
`(letrec* ([,x* ,(map Expr e*)] ...) ,(Expr body))])
|
|
(CaseLambdaClause : CaseLambdaClause (ir) -> CaseLambdaClause ()
|
|
[(clause (,x* ...) ,interface ,body)
|
|
(for-each initialize-id! x*)
|
|
`(clause (,x* ...) ,interface ,(Expr body))]))
|
|
(Lexpand-to-go x cpcheck-prelex-flags)))
|
|
|
|
(set-who! $insert-profile-src! ; called from compiler only
|
|
(lambda (st x)
|
|
; NB: the output should be *, but nanopass won't autogenerate the pass
|
|
(define-pass record-coverage-info! : Lsrc (ir) -> Lsrc ()
|
|
(Expr : Expr (ir) -> Expr ()
|
|
[(profile ,src) (source-table-set! st src 0) `(profile ,src)]))
|
|
(Lexpand-to-go x record-coverage-info!)))
|
|
)
|