checking closures
This commit is contained in:
parent
0a7f12375f
commit
4a2f30b4f2
|
@ -228,6 +228,7 @@
|
||||||
(make-instruction-sequence
|
(make-instruction-sequence
|
||||||
`(,(make-AssignPrimOpStatement target
|
`(,(make-AssignPrimOpStatement target
|
||||||
(make-MakeCompiledProcedure proc-entry
|
(make-MakeCompiledProcedure proc-entry
|
||||||
|
(length (Lam-parameters exp))
|
||||||
lexical-references)))))
|
lexical-references)))))
|
||||||
(compile-lambda-body exp cenv
|
(compile-lambda-body exp cenv
|
||||||
lexical-references
|
lexical-references
|
||||||
|
@ -341,6 +342,8 @@
|
||||||
primitive-branch)))
|
primitive-branch)))
|
||||||
|
|
||||||
compiled-branch
|
compiled-branch
|
||||||
|
(make-instruction-sequence
|
||||||
|
`(,(make-PerformStatement (make-CheckClosureArity! n))))
|
||||||
(end-with-compiled-application-linkage
|
(end-with-compiled-application-linkage
|
||||||
compiled-linkage
|
compiled-linkage
|
||||||
cenv
|
cenv
|
||||||
|
|
|
@ -113,9 +113,11 @@
|
||||||
(define-struct: GetCompiledProcedureEntry ()
|
(define-struct: GetCompiledProcedureEntry ()
|
||||||
#:transparent)
|
#:transparent)
|
||||||
|
|
||||||
;; Constructs a closure, given the label and the set of lexical references
|
;; Constructs a closure, given the label, # of expected arguments,
|
||||||
;; into the environment that the closure needs to close over.
|
;; and the set of lexical references into the environment that the
|
||||||
|
;; closure needs to close over.
|
||||||
(define-struct: MakeCompiledProcedure ([label : Symbol]
|
(define-struct: MakeCompiledProcedure ([label : Symbol]
|
||||||
|
[arity : Natural]
|
||||||
[closed-vals : (Listof EnvReference)])
|
[closed-vals : (Listof EnvReference)])
|
||||||
#:transparent)
|
#:transparent)
|
||||||
|
|
||||||
|
@ -169,6 +171,10 @@
|
||||||
[name : Symbol])
|
[name : Symbol])
|
||||||
#:transparent)
|
#:transparent)
|
||||||
|
|
||||||
|
;; Check the closure procedure value in 'proc and make sure it can accept n values.
|
||||||
|
(define-struct: CheckClosureArity! ([arity : Natural])
|
||||||
|
#:transparent)
|
||||||
|
|
||||||
;; Extends the environment with a prefix that holds
|
;; Extends the environment with a prefix that holds
|
||||||
;; lookups to the namespace.
|
;; lookups to the namespace.
|
||||||
(define-struct: ExtendEnvironment/Prefix! ([names : (Listof Symbol)])
|
(define-struct: ExtendEnvironment/Prefix! ([names : (Listof Symbol)])
|
||||||
|
@ -182,6 +188,7 @@
|
||||||
(define-type PrimitiveCommand (U
|
(define-type PrimitiveCommand (U
|
||||||
SetToplevel!
|
SetToplevel!
|
||||||
CheckToplevelBound!
|
CheckToplevelBound!
|
||||||
|
CheckClosureArity!
|
||||||
ExtendEnvironment/Prefix!
|
ExtendEnvironment/Prefix!
|
||||||
InstallClosureValues!))
|
InstallClosureValues!))
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
;; Compiled procedure closures
|
;; Compiled procedure closures
|
||||||
(define-struct: closure ([label : Symbol]
|
(define-struct: closure ([label : Symbol]
|
||||||
|
[arity : Natural]
|
||||||
[vals : (Listof SlotValue)])
|
[vals : (Listof SlotValue)])
|
||||||
#:transparent)
|
#:transparent)
|
||||||
|
|
||||||
|
|
|
@ -152,18 +152,32 @@
|
||||||
(toplevel-mutate (ensure-toplevel (env-ref m (SetToplevel!-depth op)))
|
(toplevel-mutate (ensure-toplevel (env-ref m (SetToplevel!-depth op)))
|
||||||
(SetToplevel!-pos op)
|
(SetToplevel!-pos op)
|
||||||
(ensure-primitive-value (machine-val m))))]
|
(ensure-primitive-value (machine-val m))))]
|
||||||
|
|
||||||
[(CheckToplevelBound!? op)
|
[(CheckToplevelBound!? op)
|
||||||
(let: ([a-top : toplevel (ensure-toplevel (env-ref m (CheckToplevelBound!-depth op)))])
|
(let: ([a-top : toplevel (ensure-toplevel (env-ref m (CheckToplevelBound!-depth op)))])
|
||||||
(cond
|
(cond
|
||||||
[(undefined? (list-ref (toplevel-vals a-top) (CheckToplevelBound!-pos op)))
|
[(undefined? (list-ref (toplevel-vals a-top) (CheckToplevelBound!-pos op)))
|
||||||
(error 'check-toplevel-bound! "Unbound identifier ~s" (CheckToplevelBound!-name op))]
|
(error 'check-toplevel-bound! "Unbound identifier ~s"
|
||||||
|
(CheckToplevelBound!-name op))]
|
||||||
[else
|
[else
|
||||||
m]))]
|
m]))]
|
||||||
|
|
||||||
|
[(CheckClosureArity!? op)
|
||||||
|
(let: ([clos : SlotValue (machine-proc m)])
|
||||||
|
(cond
|
||||||
|
[(closure? clos)
|
||||||
|
(if (= (closure-arity clos)
|
||||||
|
(CheckClosureArity!-arity op))
|
||||||
|
m
|
||||||
|
(error 'check-closure-arity "arity mismatch"))]
|
||||||
|
[else
|
||||||
|
(error 'check-closure-arity "not a closure")]))]
|
||||||
|
|
||||||
[(ExtendEnvironment/Prefix!? op)
|
[(ExtendEnvironment/Prefix!? op)
|
||||||
(env-push m
|
(env-push m
|
||||||
(make-toplevel (map lookup-primitive
|
(make-toplevel (map lookup-primitive
|
||||||
(ExtendEnvironment/Prefix!-names op))))]
|
(ExtendEnvironment/Prefix!-names op))))]
|
||||||
|
|
||||||
[(InstallClosureValues!? op)
|
[(InstallClosureValues!? op)
|
||||||
(let: ([a-proc : SlotValue (machine-proc m)])
|
(let: ([a-proc : SlotValue (machine-proc m)])
|
||||||
(cond
|
(cond
|
||||||
|
@ -202,6 +216,7 @@
|
||||||
|
|
||||||
[(MakeCompiledProcedure? op)
|
[(MakeCompiledProcedure? op)
|
||||||
(target-updater m (make-closure (MakeCompiledProcedure-label op)
|
(target-updater m (make-closure (MakeCompiledProcedure-label op)
|
||||||
|
(MakeCompiledProcedure-arity op)
|
||||||
(map (lambda: ([r : EnvReference])
|
(map (lambda: ([r : EnvReference])
|
||||||
(lookup-env-reference m r))
|
(lookup-env-reference m r))
|
||||||
(MakeCompiledProcedure-closed-vals op))))]
|
(MakeCompiledProcedure-closed-vals op))))]
|
||||||
|
|
|
@ -108,8 +108,11 @@
|
||||||
|
|
||||||
;; We should see an error here, since the arity is wrong
|
;; We should see an error here, since the arity is wrong
|
||||||
(test/exn ((lambda (x y z) x) 3))
|
(test/exn ((lambda (x y z) x) 3))
|
||||||
|
(test/exn ((lambda (x y z) z) 3))
|
||||||
(test/exn ((lambda (x y z) x) 3 4 5 6))
|
(test/exn ((lambda (x y z) x) 3 4 5 6))
|
||||||
|
|
||||||
|
;; And this should fail because it's not a lambda
|
||||||
|
(test/exn (not-a-procedure 5))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -276,6 +276,7 @@
|
||||||
;; install-closure-values
|
;; install-closure-values
|
||||||
(let ([m
|
(let ([m
|
||||||
(make-machine (make-undefined) (make-closure 'procedure-entry
|
(make-machine (make-undefined) (make-closure 'procedure-entry
|
||||||
|
0
|
||||||
(list 1 2 3))
|
(list 1 2 3))
|
||||||
(list true false) ;; existing environment holds true, false
|
(list true false) ;; existing environment holds true, false
|
||||||
'()
|
'()
|
||||||
|
@ -291,7 +292,7 @@
|
||||||
;; get-compiled-procedure-entry
|
;; get-compiled-procedure-entry
|
||||||
(let ([m
|
(let ([m
|
||||||
(make-machine (make-undefined)
|
(make-machine (make-undefined)
|
||||||
(make-closure 'procedure-entry (list 1 2 3))
|
(make-closure 'procedure-entry 0 (list 1 2 3))
|
||||||
(list true false) ;; existing environment holds true, false
|
(list true false) ;; existing environment holds true, false
|
||||||
'()
|
'()
|
||||||
0
|
0
|
||||||
|
@ -303,13 +304,13 @@
|
||||||
;; make-compiled-procedure, with empty closure set
|
;; make-compiled-procedure, with empty closure set
|
||||||
(let ([m (new-machine `(,(make-AssignPrimOpStatement
|
(let ([m (new-machine `(,(make-AssignPrimOpStatement
|
||||||
'val
|
'val
|
||||||
(make-MakeCompiledProcedure 'procedure-entry (list)))
|
(make-MakeCompiledProcedure 'procedure-entry 0 (list)))
|
||||||
,(make-GotoStatement (make-Label 'end))
|
,(make-GotoStatement (make-Label 'end))
|
||||||
procedure-entry
|
procedure-entry
|
||||||
end
|
end
|
||||||
))])
|
))])
|
||||||
(test (machine-val (run m))
|
(test (machine-val (run m))
|
||||||
(make-closure 'procedure-entry (list))))
|
(make-closure 'procedure-entry 0 (list))))
|
||||||
|
|
||||||
;; make-compiled-procedure: Capturing a few variables.
|
;; make-compiled-procedure: Capturing a few variables.
|
||||||
(let ([m (new-machine `(,(make-PushEnvironment 3)
|
(let ([m (new-machine `(,(make-PushEnvironment 3)
|
||||||
|
@ -318,14 +319,16 @@
|
||||||
,(make-AssignImmediateStatement (make-EnvLexicalReference 2) (make-Const 'moe))
|
,(make-AssignImmediateStatement (make-EnvLexicalReference 2) (make-Const 'moe))
|
||||||
,(make-AssignPrimOpStatement
|
,(make-AssignPrimOpStatement
|
||||||
'val
|
'val
|
||||||
(make-MakeCompiledProcedure 'procedure-entry (list (make-EnvLexicalReference 0)
|
(make-MakeCompiledProcedure 'procedure-entry
|
||||||
(make-EnvLexicalReference 2))))
|
0
|
||||||
|
(list (make-EnvLexicalReference 0)
|
||||||
|
(make-EnvLexicalReference 2))))
|
||||||
,(make-GotoStatement (make-Label 'end))
|
,(make-GotoStatement (make-Label 'end))
|
||||||
procedure-entry
|
procedure-entry
|
||||||
end
|
end
|
||||||
))])
|
))])
|
||||||
(test (machine-val (run m))
|
(test (machine-val (run m))
|
||||||
(make-closure 'procedure-entry (list 'larry 'moe))))
|
(make-closure 'procedure-entry 0 (list 'larry 'moe))))
|
||||||
|
|
||||||
;; make-compiled-procedure: Capturing a toplevel.
|
;; make-compiled-procedure: Capturing a toplevel.
|
||||||
(let ([m (new-machine `(,(make-PerformStatement (make-ExtendEnvironment/Prefix! '(x y z)))
|
(let ([m (new-machine `(,(make-PerformStatement (make-ExtendEnvironment/Prefix! '(x y z)))
|
||||||
|
@ -337,13 +340,15 @@
|
||||||
,(make-PerformStatement (make-SetToplevel! 0 2 'z))
|
,(make-PerformStatement (make-SetToplevel! 0 2 'z))
|
||||||
,(make-AssignPrimOpStatement
|
,(make-AssignPrimOpStatement
|
||||||
'val
|
'val
|
||||||
(make-MakeCompiledProcedure 'procedure-entry (list (make-EnvWholePrefixReference 0))))
|
(make-MakeCompiledProcedure 'procedure-entry
|
||||||
|
0
|
||||||
|
(list (make-EnvWholePrefixReference 0))))
|
||||||
,(make-GotoStatement (make-Label 'end))
|
,(make-GotoStatement (make-Label 'end))
|
||||||
procedure-entry
|
procedure-entry
|
||||||
end
|
end
|
||||||
))])
|
))])
|
||||||
(test (machine-val (run m))
|
(test (machine-val (run m))
|
||||||
(make-closure 'procedure-entry (list (make-toplevel (list "x" "y" "z"))))))
|
(make-closure 'procedure-entry 0 (list (make-toplevel (list "x" "y" "z"))))))
|
||||||
|
|
||||||
;; make-compiled-procedure: Capturing both a toplevel and some lexical values
|
;; make-compiled-procedure: Capturing both a toplevel and some lexical values
|
||||||
(let ([m (new-machine `(,(make-PerformStatement (make-ExtendEnvironment/Prefix! '(x y z)))
|
(let ([m (new-machine `(,(make-PerformStatement (make-ExtendEnvironment/Prefix! '(x y z)))
|
||||||
|
@ -360,18 +365,22 @@
|
||||||
,(make-AssignImmediateStatement (make-EnvLexicalReference 2) (make-Const 'moe))
|
,(make-AssignImmediateStatement (make-EnvLexicalReference 2) (make-Const 'moe))
|
||||||
,(make-AssignPrimOpStatement
|
,(make-AssignPrimOpStatement
|
||||||
'val
|
'val
|
||||||
(make-MakeCompiledProcedure 'procedure-entry (list (make-EnvWholePrefixReference 3)
|
(make-MakeCompiledProcedure 'procedure-entry
|
||||||
(make-EnvLexicalReference 0)
|
0
|
||||||
(make-EnvLexicalReference 2))))
|
(list (make-EnvWholePrefixReference 3)
|
||||||
|
(make-EnvLexicalReference 0)
|
||||||
|
(make-EnvLexicalReference 2))))
|
||||||
,(make-PopEnvironment 3 0)
|
,(make-PopEnvironment 3 0)
|
||||||
,(make-GotoStatement (make-Label 'end))
|
,(make-GotoStatement (make-Label 'end))
|
||||||
procedure-entry
|
procedure-entry
|
||||||
end
|
end
|
||||||
))])
|
))])
|
||||||
(test (machine-val (run m))
|
(test (machine-val (run m))
|
||||||
(make-closure 'procedure-entry (list (make-toplevel (list "x" "y" "z"))
|
(make-closure 'procedure-entry
|
||||||
'larry
|
0
|
||||||
'moe))))
|
(list (make-toplevel (list "x" "y" "z"))
|
||||||
|
'larry
|
||||||
|
'moe))))
|
||||||
|
|
||||||
|
|
||||||
;; Test toplevel lookup
|
;; Test toplevel lookup
|
||||||
|
|
Loading…
Reference in New Issue
Block a user