[pypy-svn] r45076 - in pypy/dist/pypy/lang/scheme: . test
jlg at codespeak.net
jlg at codespeak.net
Sat Jul 14 15:40:42 CEST 2007
Author: jlg
Date: Sat Jul 14 15:40:42 2007
New Revision: 45076
Modified:
pypy/dist/pypy/lang/scheme/object.py
pypy/dist/pypy/lang/scheme/test/test_eval.py
Log:
(arigo, jlg) more tail-recursive friendly calls
Modified: pypy/dist/pypy/lang/scheme/object.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/object.py (original)
+++ pypy/dist/pypy/lang/scheme/object.py Sat Jul 14 15:40:42 2007
@@ -39,7 +39,16 @@
return "<W_Root " + self.to_string() + ">"
def eval(self, ctx):
- return self
+ w_expr = self
+ while ctx is not None:
+ (w_expr, ctx) = w_expr.eval1(ctx)
+
+ assert isinstance(w_expr, W_Root)
+ return w_expr
+ #return self
+
+ def eval1(self, ctx):
+ return (self, None)
class W_Symbol(W_Root):
def __init__(self, val):
@@ -61,14 +70,10 @@
def __repr__(self):
return "<W_Identifier " + self.name + ">"
- def eval(self, ctx):
-
- if ctx is None:
- ctx = ExecutionContext()
-
+ def eval1(self, ctx):
w_obj = ctx.get(self.name)
if w_obj is not None:
- return w_obj
+ return (w_obj, None)
else:
#reference to undefined identifier
#unbound
@@ -164,28 +169,31 @@
cdr = self.cdr.to_string()
return "(" + car + " . " + cdr + ")"
- def eval(self, ctx):
+ def eval1(self, ctx):
oper = self.car.eval(ctx)
if not isinstance(oper, W_Callable):
raise NotCallable(oper)
- return oper.call(ctx, self.cdr)
+ return oper.call1(ctx, self.cdr)
class W_Nil(W_Root):
def to_string(self):
return "()"
class W_Callable(W_Root):
- def call(self, ctx, lst):
+ def call1(self, ctx, lst):
raise NotImplementedError
- def eval_body(self, ctx, body):
+ def eval1_body(self, ctx, body):
body_expression = body
- body_result = None
- while not isinstance(body_expression, W_Nil):
- body_result = body_expression.car.eval(ctx)
+ while True: #not isinstance(body_expression, W_Nil):
+ if isinstance(body_expression.cdr, W_Nil):
+ return (body_expression.car, ctx)
+ else:
+ body_expression.car.eval(ctx)
+
body_expression = body_expression.cdr
- return body_result
+ #return body_result
class W_Procedure(W_Callable):
def __init__(self, pname=""):
@@ -194,21 +202,25 @@
def to_string(self):
return "#<primitive-procedure %s>" % (self.pname,)
- def call(self, ctx, lst):
+ def call1(self, ctx, lst):
#evaluate all arguments into list
arg_lst = []
arg = lst
while not isinstance(arg, W_Nil):
if not isinstance(arg, W_Pair):
raise SchemeSyntaxError
- arg_lst.append(arg.car.eval(ctx))
+ w_obj = arg.car.eval(ctx)
+ arg_lst.append(w_obj)
arg = arg.cdr
- return self.procedure(ctx, arg_lst)
+ return self.procedure1(ctx, arg_lst)
def procedure(self, ctx, lst):
raise NotImplementedError
+ def procedure1(self, ctx, lst):
+ return (self.procedure(ctx, lst), None)
+
class W_Macro(W_Callable):
def __init__(self, pname=""):
self.pname = pname
@@ -216,7 +228,7 @@
def to_string(self):
return "#<primitive-macro %s>" % (self.pname,)
- def call(self, ctx, lst=None):
+ def call1(self, ctx, lst=None):
raise NotImplementedError
class Formal(object):
@@ -248,7 +260,7 @@
def to_string(self):
return "#<procedure %s>" % (self.pname,)
- def procedure(self, ctx, lst):
+ def procedure1(self, ctx, lst):
#ctx is a caller context, which is joyfully ignored
local_ctx = self.closure.copy()
@@ -261,7 +273,7 @@
else:
local_ctx.put(formal.name, lst[idx])
- return self.eval_body(local_ctx, self.body)
+ return self.eval1_body(local_ctx, self.body)
def plst2lst(plst):
"""coverts python list() of W_Root into W_Pair scheme list"""
@@ -483,7 +495,7 @@
# Macro
##
class Define(W_Macro):
- def call(self, ctx, lst):
+ def call1(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
w_identifier = lst.car
@@ -492,10 +504,10 @@
w_val = lst.cdr.car.eval(ctx)
ctx.set(w_identifier.name, w_val)
- return w_val
+ return (w_val, None)
class Sete(W_Macro):
- def call(self, ctx, lst):
+ def call1(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
w_identifier = lst.car
@@ -504,10 +516,10 @@
w_val = lst.cdr.car.eval(ctx)
ctx.sete(w_identifier.name, w_val)
- return w_val
+ return (w_val, None)
class MacroIf(W_Macro):
- def call(self, ctx, lst):
+ def call1(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
w_condition = lst.car
@@ -519,18 +531,18 @@
w_cond_val = w_condition.eval(ctx)
if w_cond_val.to_boolean() is True:
- return w_then.eval(ctx)
+ return (w_then, ctx)
else:
- return w_else.eval(ctx)
+ return (w_else, ctx)
class Lambda(W_Macro):
- def call(self, ctx, lst):
+ def call1(self, ctx, lst):
w_args = lst.car
w_body = lst.cdr
- return W_Lambda(w_args, w_body, ctx)
+ return (W_Lambda(w_args, w_body, ctx), None)
class Let(W_Macro):
- def call(self, ctx, lst):
+ def call1(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
local_ctx = ctx.copy()
@@ -542,10 +554,10 @@
local_ctx.put(name, val)
w_formal = w_formal.cdr
- return self.eval_body(local_ctx, lst.cdr)
+ return self.eval1_body(local_ctx, lst.cdr)
class Letrec(W_Macro):
- def call(self, ctx, lst):
+ def call1(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
local_ctx = ctx.copy()
@@ -565,30 +577,30 @@
local_ctx.set(name, val)
w_formal = w_formal.cdr
- return self.eval_body(local_ctx, lst.cdr)
+ return self.eval1_body(local_ctx, lst.cdr)
def literal(sexpr):
return W_Pair(W_Identifier('quote'), W_Pair(sexpr, W_Nil()))
class Quote(W_Macro):
- def call(self, ctx, lst):
+ def call1(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
if not isinstance(lst.cdr, W_Nil):
raise SchemeSyntaxError
- return lst.car
+ return (lst.car, None)
class Delay(W_Macro):
- def call(self, ctx, lst):
+ def call1(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
if not isinstance(lst.cdr, W_Nil):
raise SchemeSyntaxError
- return W_Promise(lst.car, ctx)
+ return (W_Promise(lst.car, ctx), None)
##
# Location()
@@ -682,6 +694,7 @@
"""update existing location or raise
directly used by (set! <var> <expr>) macro
"""
+ assert isinstance(obj, W_Root)
loc = self.scope.get(name, None)
if loc is not None:
loc.obj = obj
@@ -696,6 +709,7 @@
def set(self, name, obj):
"""update existing location or create new location"""
+ assert isinstance(obj, W_Root)
if self.closure:
loc = self.scope.get(name, None)
else:
@@ -708,6 +722,7 @@
def put(self, name, obj):
"""create new location"""
+ assert isinstance(obj, W_Root)
if self.closure:
self.scope[name] = Location(obj)
else:
Modified: pypy/dist/pypy/lang/scheme/test/test_eval.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/test/test_eval.py (original)
+++ pypy/dist/pypy/lang/scheme/test/test_eval.py Sat Jul 14 15:40:42 2007
@@ -5,13 +5,13 @@
def test_eval_obj():
w_num = W_Pair(W_Identifier("+"),
W_Pair(W_Integer(4), W_Pair(W_Integer(5), W_Nil())))
- assert w_num.eval(None).to_number() == 9
+ assert w_num.eval(ExecutionContext()).to_number() == 9
def eval_expr(ctx, expr):
return parse(expr)[0].eval(ctx)
def eval_noctx(expr):
- return parse(expr)[0].eval(None)
+ return parse(expr)[0].eval(ExecutionContext())
def test_numerical():
w_num = eval_noctx("(+)")
@@ -215,7 +215,8 @@
def test_lambda_args():
ctx = ExecutionContext()
- eval_expr(ctx, "(define f1 (lambda (n) n))")
+ w_lam = eval_expr(ctx, "(define f1 (lambda (n) n))")
+ assert isinstance(w_lam, W_Lambda)
w_result = eval_expr(ctx, "(f1 42)")
assert isinstance(w_result, W_Integer)
@@ -462,3 +463,17 @@
""")
w_num = eval_expr(ctx, "(b)")
assert w_num.to_number() == 42
+
+def test_evaluator():
+ ctx = ExecutionContext()
+ eval_expr(ctx, "(define a 0)")
+ w_obj = parse("(let () (set! a 42) a)")[0]
+ (w_expr, new_ctx) = w_obj.eval1(ctx)
+ assert ctx.get("a").to_number() == 42
+ assert isinstance(w_expr, W_Identifier)
+ assert new_ctx is not ctx
+ assert isinstance(new_ctx, ExecutionContext)
+ (w_obj, newer_ctx) = w_expr.eval1(new_ctx)
+ assert isinstance(w_obj, W_Number)
+ assert w_obj.to_number() == 42
+ assert newer_ctx is None
More information about the Pypy-commit
mailing list