[pypy-svn] r45512 - in pypy/dist/pypy/lang/scheme: . test
jlg at codespeak.net
jlg at codespeak.net
Mon Aug 6 11:56:10 CEST 2007
Author: jlg
Date: Mon Aug 6 11:56:09 2007
New Revision: 45512
Modified:
pypy/dist/pypy/lang/scheme/execution.py
pypy/dist/pypy/lang/scheme/object.py
pypy/dist/pypy/lang/scheme/test/test_macro.py
Log:
OPERATION_MAP generated based on _symbol_name class atribute; macros tuning, most test are passing
Modified: pypy/dist/pypy/lang/scheme/execution.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/execution.py (original)
+++ pypy/dist/pypy/lang/scheme/execution.py Mon Aug 6 11:56:09 2007
@@ -1,72 +1,25 @@
-from pypy.lang.scheme.object import *
+import pypy.lang.scheme.object as ssobject
+#from pypy.lang.scheme.object import *
class Location(object):
def __init__(self, w_obj=None):
self.obj = w_obj
-##
-# dict mapping operations to W_Xxx objects
-# callables must have 2 arguments
-# - ctx = execution context
-# - lst = list of arguments
-##
-OMAP = \
- {
- #arithmetic operations
- '+': Add,
- '-': Sub,
- '*': Mul,
- '/': Div,
- #list operations
- 'cons': Cons,
- 'car': Car,
- 'cdr': Cdr,
- 'set-car!': SetCar,
- 'set-cdr!': SetCdr,
- 'list': List,
- 'quit': Quit,
- #comparisons
- '=': Equal,
- #predicates
- 'integer?': IntegerP,
- 'rational?': RealP,
- 'real?': RealP,
- 'complex?': NumberP,
- 'number?': NumberP,
- 'exact?': ExactP,
- 'inexact?': InexactP,
- 'zero?': ZeroP,
- 'odd?': OddP,
- 'even?': EvenP,
- #delayed evaluation
- 'force': Force,
- 'delay': Delay, #macro
- #macros
- 'define': Define,
- 'set!': Sete,
- 'if': MacroIf,
- 'lambda': Lambda,
- 'begin': Begin,
- 'let': Let,
- 'let*': LetStar,
- 'letrec': Letrec,
- 'quote': Quote,
- 'quasiquote': QuasiQuote,
- 'syntax-rules': SyntaxRules,
- 'define-syntax': DefineSyntax,
- 'let-syntax': LetSyntax,
- }
-
OPERATION_MAP = {}
-for name, cls in OMAP.items():
- OPERATION_MAP[name] = cls(name)
+for obj_name in dir(ssobject):
+ obj = getattr(ssobject, obj_name)
+ try:
+ issubclass(obj, ssobject.W_Callable)
+ OPERATION_MAP[obj._symbol_name] = obj(obj._symbol_name)
+ except (TypeError, AttributeError):
+ pass
class ExecutionContext(object):
"""Execution context implemented as a dict.
{ "IDENTIFIER": Location(W_Root()) }
"""
- def __init__(self, globalscope=None, scope=None, closure=False, macro=False):
+ def __init__(self, globalscope=None, scope=None, closure=False):
if globalscope is None:
self.globalscope = {}
for name, oper in OPERATION_MAP.items():
@@ -83,13 +36,13 @@
self.closure = closure
def _dispatch(self, symb):
- if isinstance(symb, SymbolClosure):
+ if isinstance(symb, ssobject.SymbolClosure):
return (symb.closure, symb.name)
- elif isinstance(symb, W_Symbol):
+ elif isinstance(symb, ssobject.W_Symbol):
return (self, symb.name)
- raise SchemeSyntaxError
+ raise ssobject.SchemeSyntaxError
def copy(self):
return ExecutionContext(self.globalscope, self.scope.copy(), True)
@@ -98,16 +51,16 @@
loc = self.scope.get(name, None)
if loc is not None:
if loc.obj is None:
- raise UnboundVariable(name)
+ raise ssobject.UnboundVariable(name)
return loc.obj
loc = self.globalscope.get(name, None)
if loc is not None:
if loc.obj is None:
- raise UnboundVariable(name)
+ raise ssobject.UnboundVariable(name)
return loc.obj
- raise UnboundVariable(name)
+ raise ssobject.UnboundVariable(name)
def ssete(self, symb, obj):
(ctx, name) = self._dispatch(symb)
@@ -117,7 +70,7 @@
"""update existing location or raise
directly used by (set! <var> <expr>) macro
"""
- assert isinstance(obj, W_Root)
+ assert isinstance(obj, ssobject.W_Root)
loc = self.scope.get(name, None)
if loc is not None:
loc.obj = obj
@@ -128,11 +81,11 @@
loc.obj = obj
return obj
- raise UnboundVariable(name)
+ raise ssobject.UnboundVariable(name)
def set(self, name, obj):
"""update existing location or create new location"""
- assert isinstance(obj, W_Root)
+ assert isinstance(obj, ssobject.W_Root)
if self.closure:
loc = self.scope.get(name, None)
else:
@@ -149,7 +102,7 @@
def put(self, name, obj):
"""create new location"""
- assert isinstance(obj, W_Root)
+ assert isinstance(obj, ssobject.W_Root)
if self.closure:
self.scope[name] = Location(obj)
else:
@@ -179,3 +132,4 @@
return loc
return None
+
Modified: pypy/dist/pypy/lang/scheme/object.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/object.py (original)
+++ pypy/dist/pypy/lang/scheme/object.py Mon Aug 6 11:56:09 2007
@@ -440,6 +440,7 @@
Op.default_result = W_Integer(default_result)
Op.__name__ = "Op" + title
+ Op._symbol_name = oper
return Op
Add = create_op_class('+', '', "Add", 0)
@@ -448,6 +449,8 @@
Div = create_op_class('/', '1 /', "Div")
class Equal(W_Procedure):
+ _symbol_name = "="
+
def procedure(self, ctx, lst):
if len(lst) < 2:
return W_Boolean(True)
@@ -467,10 +470,14 @@
return W_Boolean(True)
class List(W_Procedure):
+ _symbol_name = "list"
+
def procedure(self, ctx, lst):
return plst2lst(lst)
class Cons(W_Procedure):
+ _symbol_name = "cons"
+
def procedure(self, ctx, lst):
w_car = lst[0]
w_cdr = lst[1]
@@ -478,6 +485,8 @@
return W_Pair(w_car, w_cdr)
class Car(W_Procedure):
+ _symbol_name = "car"
+
def procedure(self, ctx, lst):
w_pair = lst[0]
if not isinstance(w_pair, W_Pair):
@@ -485,6 +494,8 @@
return w_pair.car
class Cdr(W_Procedure):
+ _symbol_name = "cdr"
+
def procedure(self, ctx, lst):
w_pair = lst[0]
if not isinstance(w_pair, W_Pair):
@@ -492,6 +503,8 @@
return w_pair.cdr
class SetCar(W_Procedure):
+ _symbol_name = "set-car!"
+
def procedure(self, ctx, lst):
w_pair = lst[0]
w_obj = lst[1]
@@ -502,6 +515,8 @@
return w_undefined
class SetCdr(W_Procedure):
+ _symbol_name = "set-cdr!"
+
def procedure(self, ctx, lst):
w_pair = lst[0]
w_obj = lst[1]
@@ -512,10 +527,14 @@
return w_undefined
class Quit(W_Procedure):
+ _symbol_name = "quit"
+
def procedure(self, ctx, lst):
raise SchemeQuit
class Force(W_Procedure):
+ _symbol_name = "force"
+
def procedure(self, ctx, lst):
if len(lst) != 1:
raise WrongArgsNumber
@@ -544,6 +563,8 @@
raise NotImplementedError
class IntegerP(PredicateNumber):
+ _symbol_name = "integer?"
+
def predicate(self, w_obj):
if not w_obj.exact:
return w_obj.is_integer()
@@ -551,26 +572,44 @@
return True
class RealP(PredicateNumber):
+ _symbol_name = "real?"
+
def predicate(self, w_obj):
return isinstance(w_obj, W_Real)
+class RationalP(RealP):
+ _symbol_name = "rational?"
+
class NumberP(PredicateNumber):
+ _symbol_name = "number?"
+
def predicate(self, w_obj):
return isinstance(w_obj, W_Number)
+class ComplexP(NumberP):
+ _symbol_name = "complex?"
+
class ExactP(PredicateNumber):
+ _symbol_name = "exact?"
+
def predicate(self, w_obj):
return w_obj.exact
class InexactP(PredicateNumber):
+ _symbol_name = "inexact?"
+
def predicate(self, w_obj):
return not w_obj.exact
class ZeroP(PredicateNumber):
+ _symbol_name = "zero?"
+
def predicate(self, w_obj):
return w_obj.to_number() == 0.0
class OddP(PredicateNumber):
+ _symbol_name = "odd?"
+
def predicate(self, w_obj):
if not w_obj.is_integer():
raise WrongArgType(w_obj, "Integer")
@@ -578,6 +617,8 @@
return w_obj.round() % 2 != 0
class EvenP(PredicateNumber):
+ _symbol_name = "even?"
+
def predicate(self, w_obj):
if not w_obj.is_integer():
raise WrongArgType(w_obj, "Integer")
@@ -588,6 +629,8 @@
# Macro
##
class Define(W_Macro):
+ _symbol_name = "define"
+
def call(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
@@ -612,6 +655,8 @@
raise SchemeSyntaxError
class Sete(W_Macro):
+ _symbol_name = "set!"
+
def call(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
@@ -622,6 +667,8 @@
return w_val #undefined
class MacroIf(W_Macro):
+ _symbol_name = "if"
+
def call_tr(self, ctx, lst):
#if needs to be tail-recursive aware
if not isinstance(lst, W_Pair):
@@ -641,6 +688,8 @@
return (w_else, ctx)
class Lambda(W_Macro):
+ _symbol_name = "lambda"
+
def call(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError(lst, "Pair")
@@ -649,11 +698,15 @@
return W_Lambda(w_args, w_body, ctx)
class Begin(W_Macro):
+ _symbol_name = "begin"
+
def call_tr(self, ctx, lst):
#begin uses eval_body, so it is tail-recursive aware
return self.eval_body(ctx, lst)
class Let(W_Macro):
+ _symbol_name = "let"
+
def call_tr(self, ctx, lst):
#let uses eval_body, so it is tail-recursive aware
if not isinstance(lst, W_Pair):
@@ -670,6 +723,8 @@
return self.eval_body(local_ctx, lst.cdr)
class LetStar(W_Macro):
+ _symbol_name = "let*"
+
def call_tr(self, ctx, lst):
#let* uses eval_body, so it is tail-recursive aware
if not isinstance(lst, W_Pair):
@@ -686,6 +741,8 @@
return self.eval_body(local_ctx, lst.cdr)
class Letrec(W_Macro):
+ _symbol_name = "letrec"
+
def call_tr(self, ctx, lst):
"""let uses eval_body, so it is tail-recursive aware"""
if not isinstance(lst, W_Pair):
@@ -724,6 +781,8 @@
return W_Pair(W_Symbol('unquote-splicing'), W_Pair(sexpr, w_nil))
class Quote(W_Macro):
+ _symbol_name = "quote"
+
def call(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
@@ -731,6 +790,8 @@
return lst.car
class QuasiQuote(W_Macro):
+ _symbol_name = "quasiquote"
+
def call(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
@@ -809,6 +870,8 @@
return w_lst
class Delay(W_Macro):
+ _symbol_name = "delay"
+
def call(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
@@ -819,6 +882,8 @@
# DerivedMacros
##
class SyntaxRules(W_Macro):
+ _symbol_name = "syntax-rules"
+
def call(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
@@ -832,11 +897,9 @@
if not isinstance(w_literals.car, W_Symbol):
raise SchemeSyntaxError
+ #XXX locations here
literal_name = w_literals.car.to_string()
- try:
- w_temp = ctx.get(literal_name)
- except UnboundVariable:
- w_temp = w_literals.car
+ w_temp = ctx.get_location(literal_name)
literals_map[literal_name] = w_temp
@@ -890,10 +953,11 @@
return self.pattern.to_string() + " -> " + self.template.to_string()
def match(self, ctx, w_expr, pattern=None):
+ #we use .cdr here, because keyword should not be a macro variable
if pattern is None:
- return self.matchr(ctx, self.pattern, w_expr)
+ return self.matchr(ctx, self.pattern.cdr, w_expr.cdr)
- return self.matchr(ctx, pattern, w_expr)
+ return self.matchr(ctx, pattern.cdr, w_expr.cdr)
def matchr(self, ctx, w_patt, w_expr):
if isinstance(w_patt, W_Pair):
@@ -931,16 +995,22 @@
raise EllipsisPattern
if isinstance(w_patt, W_Symbol):
- w_literal = self.literals.get(w_patt.name, None)
- if w_literal is not None:
- try:
- w_form = ctx.get(w_expr.to_string())
- except UnboundVariable:
- w_form = w_expr
+ try:
+ w_literal = self.literals[w_patt.name]
+ if not isinstance(w_expr, W_Symbol):
+ raise MatchError
+
+ if w_patt.name != w_expr.name:
+ raise MatchError
+
+ w_form = ctx.get_location(w_expr.name)
if w_form is not w_literal:
raise MatchError
+ except KeyError:
+ pass
+
return {w_patt.name: w_expr}
if w_patt is w_nil and w_expr is w_nil:
@@ -1100,7 +1170,8 @@
w_macro = ctx.get(w_car.name)
# recursive macro expansion
if isinstance(w_macro, W_DerivedMacro):
- return w_macro.expand(ctx, w_pair)
+ if w_macro.transformer is self:
+ return w_macro.expand(ctx, w_pair)
except UnboundVariable:
pass
@@ -1161,6 +1232,8 @@
return self.transformer.expand(ctx, lst)
class DefineSyntax(W_Macro):
+ _symbol_name = "define-syntax"
+
def call(self, ctx, lst):
if not isinstance(lst, W_Pair):
raise SchemeSyntaxError
@@ -1179,6 +1252,8 @@
return w_macro #undefined
class LetSyntax(W_Macro):
+ _symbol_name = "let-syntax"
+
def call_tr(self, ctx, lst):
#let uses eval_body, so it is tail-recursive aware
if not isinstance(lst, W_Pair):
Modified: pypy/dist/pypy/lang/scheme/test/test_macro.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/test/test_macro.py (original)
+++ pypy/dist/pypy/lang/scheme/test/test_macro.py Mon Aug 6 11:56:09 2007
@@ -54,6 +54,9 @@
# w_transformer created in ctx
w_transformer = eval_(ctx, "(syntax-rules (=>) ((foo => bar) #t))")
+ w_expr = parse_("(foo 12 boo)")
+ py.test.raises(MatchError, w_transformer.match, ctx, w_expr)
+
w_expr = parse_("(foo bar boo)")
py.test.raises(MatchError, w_transformer.match, ctx, w_expr)
@@ -77,29 +80,35 @@
w_transformer = eval_(ctx, "(syntax-rules (=>) ((foo => bar) #t))")
py.test.raises(MatchError, w_transformer.match, closure, w_expr)
- # the same binding for => in ctx and closure
- # XXX
+ # the same object for => in ctx and closure, but different bindings
# <arigo> I think this should also raise MatchError. When R5RS says
# "same binding" it probably means bound to the same *location*, not
- # just that there is the same object in both locations; something like
- # this: (let ((x 42) (y 42))
- # (let-syntax ((foo (syntax-rules (x y)
- # ((foo x) 123)
- # ((foo y) 456)
- # ((foo whatever) 789))))
- # (foo y)))
- # ---> 456
- # but if we change the last line:
- # (let ((y 42)) (foo y))))
- # ---> 789
+ # just that there is the same object in both locations
ctx.put("=>", w_42)
assert ctx.get("=>") is closure.get("=>")
w_transformer = eval_(ctx, "(syntax-rules (=>) ((foo => bar) #t))")
- assert w_transformer.match(closure, w_expr)[0].to_boolean()
+ py.test.raises(MatchError, w_transformer.match, closure, w_expr)
-def test_syntax_rules_expand_simple():
+def test_literals_eval():
ctx = ExecutionContext()
+ w_result = eval_(ctx, """(let ((x 42) (y 42))
+ (let-syntax ((foo (syntax-rules (x y)
+ ((foo x) 123)
+ ((foo y) 456)
+ ((foo whatever) 789))))
+ (foo y)))""")
+ assert w_result.to_number() == 456
+
+ w_result = eval_(ctx, """(let ((x 42) (y 42))
+ (let-syntax ((foo (syntax-rules (x y)
+ ((foo x) 123)
+ ((foo y) 456)
+ ((foo whatever) 789))))
+ (let ((y x)) (foo y))))""")
+ assert w_result.to_number() == 789
+def test_syntax_rules_expand_simple():
+ ctx = ExecutionContext()
w_transformer = eval_(ctx, """(syntax-rules () ((_) #t)
((_ foo) foo))""")
@@ -264,13 +273,9 @@
((bar arg) (foo arg))))""")
w_expr = parse_("(bar 42)")
- #should expand directly (recursively) to 42
- assert ctx.get("bar").expand(ctx, w_expr).to_string() == "42"
- # XXX <arigo> no, I believe it should not expand recursively...
- # here is another example which returns (foo) in MIT-Scheme where
- # we get 42 so far:
- py.test.skip("XXX in-progress (or wrong test?)")
- ctx = ExecutionContext()
+ assert ctx.get("bar").expand(ctx, w_expr).to_string() == "(foo 42)"
+ assert eval_(ctx, "(bar 42)").to_number() == 42
+
eval_(ctx, """(define-syntax foo (syntax-rules ()
((foo) #t)))""")
eval_(ctx, """(define-syntax bar (syntax-rules ()
@@ -440,11 +445,10 @@
"(x y 1 2 3 4 + end)"
def test_cornercase1():
- py.test.skip("currently crashes")
w_result = eval_noctx("""(let-syntax ((foo (syntax-rules ()
((bar) 'bar))))
- (foo))
- """)
+ (foo)) """)
+
assert w_result.to_string() == 'bar'
# <arigo> I think that the correct answer is 'bar, according to
# the R5RS, because it says that the keyword bar in the syntax rule
@@ -461,8 +465,9 @@
def test_pitfall_3_2():
py.test.skip("(cond ...) not implemented yet")
+ #define inside macors can and sometimes can not introduce new binding
w_result = eval_noctx("""(let-syntax ((foo (syntax-rules ()
- ((_ var) (define var 1)))))
+ ((_ var) (define var 1)))))
(let ((x 2))
(begin (define foo +))
(cond (else (foo x)))
@@ -470,7 +475,6 @@
assert w_result.to_number() == 2
def test_pitfall_3_3():
- py.test.skip("currently fails")
w_result = eval_noctx("""
(let ((x 1))
(let-syntax
@@ -485,3 +489,4 @@
def test_pitfall_3_4():
w_result = eval_noctx("(let-syntax ((x (syntax-rules ()))) 1)")
assert w_result.to_number() == 1
+
More information about the Pypy-commit
mailing list