#lang typed/racket/base
(require "arity-structs.rkt"
"expression-structs.rkt"
"lexical-structs.rkt"
"il-structs.rkt"
(except-in "compiler.rkt" compile)
"compiler-structs.rkt")
(require (rename-in "compiler.rkt"
[compile whalesong-compile]))
(require/typed "../parameters.rkt"
(current-defined-name (Parameterof (U Symbol LamPositionalName))))
(require/typed "../parser/parse-bytecode.rkt"
(parse-bytecode (Any -> Expression)))
(provide get-bootstrapping-code)
(: call/cc-label Symbol)
(define call/cc-label 'callCCEntry)
(define call/cc-closure-entry 'callCCClosureEntry)
(define (make-call/cc-code)
(statements
(append-instruction-sequences
call/cc-label
(make-AssignImmediate 'proc (make-EnvLexicalReference 0 #f))
(make-PushEnvironment 2 #f)
(make-AssignPrimOp (make-EnvLexicalReference 0 #f)
(make-CaptureControl 0 default-continuation-prompt-tag))
(make-AssignPrimOp (make-EnvLexicalReference 1 #f)
(make-CaptureEnvironment 3 default-continuation-prompt-tag))
(make-AssignPrimOp (make-EnvLexicalReference 2 #f)
(make-MakeCompiledProcedure call/cc-closure-entry
1 (list 0 1)
'call/cc))
(make-PopEnvironment (make-Const 2)
(make-Const 0))
(make-AssignImmediate 'argcount (make-Const 1))
(compile-general-procedure-call '()
(make-Const 1) 'val
return-linkage)
call/cc-closure-entry
(make-AssignImmediate 'val (make-EnvLexicalReference 0 #f))
(make-Perform (make-InstallClosureValues! 2))
(make-Perform (make-RestoreControl! default-continuation-prompt-tag))
(make-Perform (make-RestoreEnvironment!))
(make-AssignImmediate 'proc (make-ControlStackLabel))
(make-PopControlFrame)
(make-Goto (make-Reg 'proc)))))
(: make-bootstrapped-primitive-code (Symbol Any -> (Listof Statement)))
(define make-bootstrapped-primitive-code
(let ([ns (make-base-empty-namespace)])
(parameterize ([current-namespace ns]) (namespace-require ''#%kernel))
(lambda (name src)
(parameterize ([current-defined-name name])
(append
(whalesong-compile (parameterize ([current-namespace ns])
(parse-bytecode (compile src)))
(make-PrimitivesReference name) next-linkage/drop-multiple))))))
(: make-map-src (Symbol Symbol -> Any))
(define (make-map-src name combiner)
`(letrec-values ([(first-tuple) (lambda (lists)
(if (null? lists)
'()
(cons (car (car lists))
(first-tuple (cdr lists)))))]
[(rest-lists) (lambda (lists)
(if (null? lists)
'()
(cons (cdr (car lists))
(rest-lists (cdr lists)))))]
[(all-empty?) (lambda (lists)
(if (null? lists)
#t
(if (null? (car lists))
(all-empty? (cdr lists))
#f)))]
[(some-empty?) (lambda (lists)
(if (null? lists)
#f
(if (null? (car lists))
#t
(some-empty? (cdr lists)))))]
[(do-it) (lambda (f lists)
(letrec-values ([(loop) (lambda (lists)
(if (all-empty? lists)
null
(if (some-empty? lists)
(error
',name
"all lists must have the same size")
(,combiner (apply f (first-tuple lists))
(loop (rest-lists lists))))))])
(loop lists)))])
(lambda (f . args)
(do-it f args))))
(: get-bootstrapping-code (-> (Listof Statement)))
(define (get-bootstrapping-code)
(append
(make-bootstrapped-primitive-code
'map
(make-map-src 'map 'cons))
(make-bootstrapped-primitive-code
'for-each
(make-map-src 'for-each 'begin))
(make-bootstrapped-primitive-code
'andmap
(make-map-src 'andmap 'and))
(make-bootstrapped-primitive-code
'ormap
(make-map-src 'ormap 'or))
(make-bootstrapped-primitive-code
'caar
'(lambda (x)
(car (car x))))
(make-bootstrapped-primitive-code
'memq
'(letrec-values ([(memq) (lambda (x l)
(if (null? l)
#f
(if (eq? x (car l))
l
(memq x (cdr l)))))])
memq))
(make-bootstrapped-primitive-code
'memv
'(letrec-values ([(memv) (lambda (x l)
(if (null? l)
#f
(if (eqv? x (car l))
l
(memv x (cdr l)))))])
memv))
(make-bootstrapped-primitive-code
'memf
'(letrec-values ([(memf) (lambda (x f l)
(if (null? l)
#f
(if (f x)
l
(memf x f (cdr l)))))])
memf))
(make-bootstrapped-primitive-code
'assq
'(letrec-values ([(assq) (lambda (x l)
(if (null? l)
#f
(if (eq? x (caar l))
(car l)
(assq x (cdr l)))))])
assq))
(make-bootstrapped-primitive-code
'assv
'(letrec-values ([(assv) (lambda (x l)
(if (null? l)
#f
(if (eqv? x (caar l))
(car l)
(assv x (cdr l)))))])
assv))
(make-bootstrapped-primitive-code
'assoc
'(letrec-values ([(assoc) (lambda (x l)
(if (null? l)
#f
(if (equal? x (caar l))
(car l)
(assoc x (cdr l)))))])
assoc))
(make-bootstrapped-primitive-code
'length
'(letrec-values ([(length-iter) (lambda (l i)
(if (null? l)
i
(length-iter (cdr l) (add1 i))))])
(lambda (l) (length-iter l 0))))
(make-bootstrapped-primitive-code
'append
'(letrec-values ([(append-many) (lambda (lsts)
(if (null? lsts)
null
(if (null? (cdr lsts))
(car lsts)
(append-2 (car lsts)
(append-many (cdr lsts))))))]
[(append-2) (lambda (l1 l2)
(if (null? l1)
l2
(cons (car l1) (append-2 (cdr l1) l2))))])
(lambda args (append-many args))))
(make-bootstrapped-primitive-code
'call-with-values
'(lambda (producer consumer)
(call-with-values (lambda () (producer)) consumer)))
(let ([after-call/cc-code (make-label 'afterCallCCImplementation)])
(append
`(,(make-AssignPrimOp (make-PrimitivesReference 'call/cc)
(make-MakeCompiledProcedure call/cc-label 1 '() 'call/cc))
,(make-AssignPrimOp (make-PrimitivesReference 'call-with-current-continuation)
(make-MakeCompiledProcedure call/cc-label 1 '() 'call/cc))
,(make-Goto (make-Label after-call/cc-code)))
(make-call/cc-code)
`(,after-call/cc-code)))
(let ([after-values-body-defn (make-label 'afterValues)]
[values-entry (make-label 'valuesEntry)]
[on-zero-values (make-label 'onZeroValues)]
[on-single-value (make-label 'onSingleValue)])
`(,(make-Goto (make-Label after-values-body-defn))
,values-entry
,(make-TestAndJump (make-TestOne (make-Reg 'argcount)) on-single-value)
,(make-TestAndJump (make-TestZero (make-Reg 'argcount)) on-zero-values)
,(make-AssignImmediate 'val (make-EnvLexicalReference 0 #f))
,(make-PopEnvironment (make-Const 1) (make-Const 0))
,(make-AssignImmediate 'proc (make-ControlStackLabel/MultipleValueReturn))
,(make-PopControlFrame)
,(make-Goto (make-Reg 'proc))
,on-single-value
,(make-AssignImmediate 'val (make-EnvLexicalReference 0 #f))
,(make-PopEnvironment (make-Const 1) (make-Const 0))
,(make-AssignImmediate 'proc (make-ControlStackLabel))
,(make-PopControlFrame)
,(make-Goto (make-Reg 'proc))
,on-zero-values
,(make-AssignImmediate 'proc (make-ControlStackLabel/MultipleValueReturn))
,(make-PopControlFrame)
,(make-Goto (make-Reg 'proc))
,after-values-body-defn
,(make-AssignPrimOp (make-PrimitivesReference 'values)
(make-MakeCompiledProcedure values-entry
(make-ArityAtLeast 0)
'()
'values))))
(let ([after-apply-code (make-label 'afterApplyCode)]
[apply-entry (make-label 'applyEntry)])
`(,(make-Goto (make-Label after-apply-code))
,apply-entry
,(make-AssignImmediate 'proc (make-EnvLexicalReference 0 #f))
,(make-PopEnvironment (make-Const 1) (make-Const 0))
,(make-AssignImmediate 'argcount (make-SubtractArg (make-Reg 'argcount)
(make-Const 1)))
,(make-Perform (make-SpliceListIntoStack! (make-SubtractArg (make-Reg 'argcount)
(make-Const 1))))
,@(statements (compile-general-procedure-call '()
(make-Reg 'argcount) 'val
return-linkage))
,after-apply-code
,(make-AssignPrimOp (make-PrimitivesReference 'apply)
(make-MakeCompiledProcedure apply-entry (make-ArityAtLeast 2) '() 'apply))))))