Close.
This commit is contained in:
+80
-16
@@ -10,6 +10,7 @@
|
|||||||
| { bind {{ <id> <TOY> } ... } <TOY> ... }
|
| { bind {{ <id> <TOY> } ... } <TOY> ... }
|
||||||
| { bindrec {{ <id> <TOY> } ... } <TOY> ... }
|
| { bindrec {{ <id> <TOY> } ... } <TOY> ... }
|
||||||
| { fun { <id> ... } <TOY> ... }
|
| { fun { <id> ... } <TOY> ... }
|
||||||
|
| { rfun { <id> ... } <TOY> ... }
|
||||||
| { <TOY> <TOY> ... }
|
| { <TOY> <TOY> ... }
|
||||||
| { if <TOY> <TOY> <TOY> }
|
| { if <TOY> <TOY> <TOY> }
|
||||||
| { set! <id> <TOY> }
|
| { set! <id> <TOY> }
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
[Bind (Listof Symbol) (Listof TOY) (Listof TOY)]
|
[Bind (Listof Symbol) (Listof TOY) (Listof TOY)]
|
||||||
[Bindrec (Listof Symbol) (Listof TOY) (Listof TOY)]
|
[Bindrec (Listof Symbol) (Listof TOY) (Listof TOY)]
|
||||||
[Fun (Listof Symbol) (Listof TOY)]
|
[Fun (Listof Symbol) (Listof TOY)]
|
||||||
|
[Rfun (Listof Symbol) (Listof TOY)]
|
||||||
[Call TOY (Listof TOY)]
|
[Call TOY (Listof TOY)]
|
||||||
[If TOY TOY TOY]
|
[If TOY TOY TOY]
|
||||||
[Set Symbol TOY])
|
[Set Symbol TOY])
|
||||||
@@ -53,19 +55,21 @@
|
|||||||
((if (symbol=? b 'bind) Bind Bindrec)
|
((if (symbol=? b 'bind) Bind Bindrec)
|
||||||
names
|
names
|
||||||
(map parse-sexpr nameds)
|
(map parse-sexpr nameds)
|
||||||
(last (map parse-sexpr body)))
|
(map parse-sexpr body))
|
||||||
(error 'parse-sexpr "duplicate `~s' names: ~s" binder names))
|
(error 'parse-sexpr "duplicate `~s' names: ~s" binder names))
|
||||||
(error 'parse-sexpr "bind expression missing body: ~s" sexpr))]
|
(error 'parse-sexpr "bind expression missing body: ~s" sexpr))]
|
||||||
[else (error 'parse-sexpr "bad `~s' syntax in ~s" binder sexpr)])]
|
[else (error 'parse-sexpr "bad `~s' syntax in ~s" binder sexpr)])]
|
||||||
|
|
||||||
; Function definition.
|
; Reference function definition.
|
||||||
[(cons 'fun more)
|
[(cons (and funer (or 'fun 'rfun)) more)
|
||||||
(match sexpr
|
(match sexpr
|
||||||
[(list 'fun (list (symbol: names) ...) body)
|
[(list f (list (symbol: parameters) ...) body ...)
|
||||||
(if (unique-list? names)
|
(if (not (null? body))
|
||||||
(Fun names (parse-sexpr body))
|
(if (unique-list? parameters)
|
||||||
(error 'parse-sexpr "duplicate `fun' names: ~s" names))]
|
((if (symbol=? f 'fun) Fun Rfun) parameters (map parse-sexpr body))
|
||||||
[else (error 'parse-sexpr "bad `fun' syntax in ~s" sexpr)])]
|
(error 'parse-sexpr "bad parameters defined for function in ~s" sexpr))
|
||||||
|
(error 'parse-sexpr "disemobodied function in ~s" sexpr))]
|
||||||
|
[else (error 'parse-sexpr "bad function syntax in ~s" sexpr)])]
|
||||||
|
|
||||||
; Conditional.
|
; Conditional.
|
||||||
[(cons 'if more)
|
[(cons 'if more)
|
||||||
@@ -107,7 +111,8 @@
|
|||||||
|
|
||||||
(define-type VAL
|
(define-type VAL
|
||||||
[RktV Any]
|
[RktV Any]
|
||||||
[FunV (Listof Symbol) TOY ENV]
|
; Parameters, body expressions, whether it's an Rfun, environment.
|
||||||
|
[FunV (Listof Symbol) (Listof TOY) Boolean ENV]
|
||||||
[PrimV ((Listof VAL) -> VAL)]
|
[PrimV ((Listof VAL) -> VAL)]
|
||||||
[VoidV])
|
[VoidV])
|
||||||
|
|
||||||
@@ -133,8 +138,6 @@
|
|||||||
names vals)
|
names vals)
|
||||||
newenv)
|
newenv)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(: lookup : Symbol ENV -> (Boxof VAL))
|
(: lookup : Symbol ENV -> (Boxof VAL))
|
||||||
;; lookup a symbol in an environment, frame by frame,
|
;; lookup a symbol in an environment, frame by frame,
|
||||||
;; return its value or throw an error if it isn't bound
|
;; return its value or throw an error if it isn't bound
|
||||||
@@ -195,18 +198,20 @@
|
|||||||
[(Num n) (RktV n)]
|
[(Num n) (RktV n)]
|
||||||
[(Id name) (unbox (lookup name env))]
|
[(Id name) (unbox (lookup name env))]
|
||||||
[(Bind names exprs bound-body)
|
[(Bind names exprs bound-body)
|
||||||
(eval bound-body (extend names (map eval* exprs) env))]
|
(eval-body bound-body (extend names (map eval* exprs) env))]
|
||||||
[(Bindrec names exprs bound-body)
|
[(Bindrec names exprs bound-body)
|
||||||
(eval bound-body (extend-rec names exprs env))]
|
(eval-body bound-body (extend-rec names exprs env))]
|
||||||
[(Fun names bound-body)
|
[(Fun names bound-body)
|
||||||
(FunV names bound-body env)]
|
(FunV names bound-body #f env)]
|
||||||
|
[(Rfun names bound-body)
|
||||||
|
(FunV names bound-body #t env)]
|
||||||
[(Call fun-expr arg-exprs)
|
[(Call fun-expr arg-exprs)
|
||||||
(let ([fval (eval* fun-expr)]
|
(let ([fval (eval* fun-expr)]
|
||||||
[arg-vals (map eval* arg-exprs)])
|
[arg-vals (map eval* arg-exprs)])
|
||||||
(cases fval
|
(cases fval
|
||||||
[(PrimV proc) (proc arg-vals)]
|
[(PrimV proc) (proc arg-vals)]
|
||||||
[(FunV names body fun-env)
|
[(FunV names body ref? fun-env)
|
||||||
(eval body (extend names arg-vals fun-env))]
|
(if ref? (eval-rfun names arg-exprs body fun-env) (eval-body body (extend names arg-vals fun-env)))]
|
||||||
[else (error 'eval "function call with a non-function: ~s"
|
[else (error 'eval "function call with a non-function: ~s"
|
||||||
fval)]))]
|
fval)]))]
|
||||||
[(If cond-expr then-expr else-expr)
|
[(If cond-expr then-expr else-expr)
|
||||||
@@ -219,6 +224,25 @@
|
|||||||
(set-box! (lookup thing env) (eval* as)) ; We are not a lazy language.
|
(set-box! (lookup thing env) (eval* as)) ; We are not a lazy language.
|
||||||
(VoidV)]))
|
(VoidV)]))
|
||||||
|
|
||||||
|
(: eval-rfun : (Listof Symbol) (Listof TOY) (Listof TOY) ENV -> VAL)
|
||||||
|
(define (eval-rfun params args body env)
|
||||||
|
(eval-body body (raw-extend params (get-boxes args env) env)))
|
||||||
|
|
||||||
|
(: get-boxes : (Listof TOY) ENV -> (Listof (Boxof VAL)))
|
||||||
|
(define (get-boxes ids env)
|
||||||
|
(: boxes (Listof (Boxof VAL)))
|
||||||
|
(define boxes '())
|
||||||
|
(for-each (lambda ([id : TOY])
|
||||||
|
(cases id
|
||||||
|
[(Id name) (set! boxes (cons (lookup name env) boxes))]
|
||||||
|
[else (error 'get-boxes "non-identifier")])) ids)
|
||||||
|
boxes)
|
||||||
|
|
||||||
|
(: eval-body : (Listof TOY) ENV -> VAL)
|
||||||
|
; Evaluates a body of expressions, returning the result of the last.
|
||||||
|
(define (eval-body exprs env)
|
||||||
|
(list-ref (map (lambda ([expr : TOY]) (eval expr env)) exprs) (sub1 (length exprs))))
|
||||||
|
|
||||||
(: run : String -> Any)
|
(: run : String -> Any)
|
||||||
;; evaluate a TOY program contained in a string
|
;; evaluate a TOY program contained in a string
|
||||||
(define (run str)
|
(define (run str)
|
||||||
@@ -230,6 +254,46 @@
|
|||||||
|
|
||||||
;;; ----------------------------------------------------------------
|
;;; ----------------------------------------------------------------
|
||||||
;;; Tests
|
;;; Tests
|
||||||
|
(test (run "
|
||||||
|
{bind
|
||||||
|
{
|
||||||
|
{swap!
|
||||||
|
{rfun {x y}
|
||||||
|
{bind {{tmp x}}
|
||||||
|
{set! x y}
|
||||||
|
{set! y tmp}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{a 1}
|
||||||
|
|
||||||
|
{b 2}
|
||||||
|
}
|
||||||
|
|
||||||
|
{swap! a b}
|
||||||
|
|
||||||
|
{+ a {* 10 b}}
|
||||||
|
}
|
||||||
|
") => 12)
|
||||||
|
|
||||||
|
(test (run "{bind {{make-counter
|
||||||
|
{fun {}
|
||||||
|
{bind {{c 0}}
|
||||||
|
{fun {}
|
||||||
|
{set! c {+ 1 c}}
|
||||||
|
c}}}}}
|
||||||
|
{bind {{c1 {make-counter}}
|
||||||
|
{c2 {make-counter}}}
|
||||||
|
{* {c1} {c1} {c2} {c1}}}}")
|
||||||
|
|
||||||
|
=> 6)
|
||||||
|
(test (run "{bindrec {{foo {fun {}
|
||||||
|
|
||||||
|
{set! foo {fun {} 2}}
|
||||||
|
1}}}
|
||||||
|
{+ {foo} {* 10 {foo}}}}")
|
||||||
|
=> 21)
|
||||||
|
|
||||||
(test (run "{bindrec {{fact {fun {n}
|
(test (run "{bindrec {{fact {fun {n}
|
||||||
{if {= 0 n}
|
{if {= 0 n}
|
||||||
|
|||||||
Reference in New Issue
Block a user