[pypy-svn] r45400 - in pypy/dist/pypy/lang/scheme: . test
jlg at codespeak.net
jlg at codespeak.net
Fri Jul 27 13:43:09 CEST 2007
Author: jlg
Date: Fri Jul 27 13:43:08 2007
New Revision: 45400
Modified:
pypy/dist/pypy/lang/scheme/object.py
pypy/dist/pypy/lang/scheme/test/test_macro.py
Log:
macro recursive expansion; expand, expand_eval, match, substitute takes as 2nd arg ctx
Modified: pypy/dist/pypy/lang/scheme/object.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/object.py (original)
+++ pypy/dist/pypy/lang/scheme/object.py Fri Jul 27 13:43:08 2007
@@ -865,7 +865,7 @@
def __str__(self):
return self.pattern.to_string() + " -> " + self.template.to_string()
- def match(self, w_expr, ctx, pattern=None):
+ def match(self, ctx, w_expr, pattern=None):
if pattern is None:
w_patt = self.pattern
else:
@@ -890,7 +890,7 @@
if not isinstance(w_exprcar, W_Pair):
return (False, {})
- (matched, match_nested) = self.match(w_exprcar, ctx, w_pattcar)
+ (matched, match_nested) = self.match(ctx, w_exprcar, w_pattcar)
if not matched:
return (False, {})
@@ -925,12 +925,9 @@
self.match_dict = {}
self.closure = ctx
- def match(self, w_expr, ctx=None):
- if ctx is None:
- ctx = self.closure
-
+ def match(self, ctx, w_expr):
for rule in self.syntax_lst:
- (matched, temp_dict) = rule.match(w_expr, ctx)
+ (matched, temp_dict) = rule.match(ctx, w_expr)
if matched:
self.match_dict = temp_dict
return rule.template
@@ -938,41 +935,67 @@
self.match_dict = {}
return None
- def expand(self, w_expr, ctx):
- template = self.match(w_expr, ctx)
+ def expand(self, ctx, w_expr):
+ template = self.match(ctx, w_expr)
if template is None :
raise SchemeSyntaxError
- return self.substitute(template, ctx)
+ return self.substitute(ctx, template)
- def substitute(self, sexpr, ctx):
+ def substitute(self, ctx, sexpr):
if isinstance(sexpr, W_Symbol):
- w_sub = self.match_dict.get(sexpr.to_string(), None)
+ w_sub = self.match_dict.get(sexpr.name, None)
if w_sub is not None:
# Hygenic macros close their input forms in the syntactic
# enviroment at the point of use
+
+ #not always needed, because w_sub can have no W_Symbols inside
return SyntacticClosure(ctx, w_sub)
return sexpr
elif isinstance(sexpr, W_Pair):
- return W_Pair(self.substitute(sexpr.car, ctx),
- self.substitute(sexpr.cdr, ctx))
+ w_pair = W_Pair(self.substitute(ctx, sexpr.car),
+ self.substitute(ctx, sexpr.cdr))
+
+ w_paircar = w_pair.car
+ if isinstance(w_paircar, W_Symbol):
+ try:
+ w_macro = ctx.get(w_paircar.name)
+ # recursive macro expansion
+ if isinstance(w_macro, W_DerivedMacro):
+ return w_macro.expand(ctx, w_pair)
+ except UnboundVariable:
+ pass
+
+ elif isinstance(w_paircar, SyntacticClosure) and \
+ isinstance(w_paircar.sexpr, W_Symbol):
+ try:
+ #ops, which context?
+ w_macro = ctx.get(w_paircar.sexpr.name)
+
+ # recursive macro expansion
+ if isinstance(w_macro, W_DerivedMacro):
+ return w_macro.expand(ctx, w_pair)
+ except UnboundVariable:
+ pass
+
+ return w_pair
return sexpr
- def expand_eval(self, sexpr, ctx):
+ def expand_eval(self, ctx, sexpr):
#we have lexical scopes:
# 1. in which macro was defined - self.closure
# 2. in which macro is called - ctx
# 3. in which macro is expanded, can introduce new bindings - expand_ctx
- expanded = self.expand(sexpr, ctx)
+ expanded = self.expand(ctx, sexpr)
expand_ctx = self.closure.copy()
return expanded.eval(expand_ctx)
def procedure(self, ctx, lst):
- return self.expand_eval(lst[0], ctx)
+ return self.expand_eval(ctx, lst[0])
class DefineSyntax(W_Macro):
def call(self, ctx, lst):
@@ -996,5 +1019,12 @@
self.name = name
self.transformer = transformer
+ def to_string(self):
+ return "#<derived-macro %s>" % (self.name,)
+
def call(self, ctx, lst):
- return self.transformer.expand_eval(W_Pair(W_Symbol(self.name), lst), ctx)
+ return self.transformer.expand_eval(ctx, W_Pair(W_Symbol(self.name), lst))
+
+ def expand(self, ctx, lst):
+ return self.transformer.expand(ctx, lst)
+
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 Fri Jul 27 13:43:08 2007
@@ -10,36 +10,37 @@
return parse(expr)[0].eval(ExecutionContext())
def test_syntax_rules_match():
+ ctx = ExecutionContext()
py.test.raises(SchemeSyntaxError, eval_noctx, "(syntax-rules 1)")
py.test.raises(SchemeSyntaxError, eval_noctx, "(syntax-rules () 1)")
w_transformer = eval_noctx("(syntax-rules ())")
w_expr = parse("(foo)")[0]
- assert not w_transformer.match(w_expr)
+ assert not w_transformer.match(ctx, w_expr)
w_transformer = eval_noctx("(syntax-rules () ((foo) #t))")
w_expr = parse("(bar)")[0]
- assert w_transformer.match(w_expr)
+ assert w_transformer.match(ctx, w_expr)
w_expr = parse("(foo bar)")[0]
- assert not w_transformer.match(w_expr)
+ assert not w_transformer.match(ctx, w_expr)
w_transformer = eval_noctx("""(syntax-rules () ((_) #t)
((_ foo) foo))""")
w_expr = parse("(foo)")[0]
- assert w_transformer.match(w_expr).to_boolean()
+ assert w_transformer.match(ctx, w_expr).to_boolean()
w_expr = parse("(foo bar)")[0]
- assert w_transformer.match(w_expr).to_string() == "foo"
+ assert w_transformer.match(ctx, w_expr).to_string() == "foo"
assert w_transformer.match_dict["foo"].to_string() == "bar"
w_expr = parse("(foo bar boo)")[0]
- assert not w_transformer.match(w_expr)
+ assert not w_transformer.match(ctx, w_expr)
assert w_transformer.match_dict == {}
w_transformer = eval_noctx("(syntax-rules () ((foo (bar)) bar))")
w_expr = parse("(_ fuzz)")[0]
- assert not w_transformer.match(w_expr)
+ assert not w_transformer.match(ctx, w_expr)
w_expr = parse("(_ (fuzz))")[0]
- assert w_transformer.match(w_expr)
+ assert w_transformer.match(ctx, w_expr)
assert w_transformer.match_dict["bar"].to_string() == "fuzz"
def test_syntax_rules_literals():
@@ -50,13 +51,13 @@
w_transformer = eval_(ctx, "(syntax-rules (=>) ((foo => bar) #t))")
w_expr = parse("(foo bar boo)")[0]
- assert not w_transformer.match(w_expr, ctx)
+ assert not w_transformer.match(ctx, w_expr)
# exact match
w_expr = parse("(foo => boo)")[0]
# within the same context
- assert w_transformer.match(w_expr, ctx)
+ assert w_transformer.match(ctx, w_expr)
w_42 = W_Number(42)
@@ -64,19 +65,19 @@
closure = ctx.copy()
closure.put("=>", w_42)
w_transformer = eval_(ctx, "(syntax-rules (=>) ((foo => bar) #t))")
- assert not w_transformer.match(w_expr, closure)
+ assert not w_transformer.match(closure, w_expr)
# different lexical scope, not the same bindings for => in ctx and closure
ctx.put("=>", W_Number(12))
assert ctx.get("=>") is not closure.get("=>")
w_transformer = eval_(ctx, "(syntax-rules (=>) ((foo => bar) #t))")
- assert not w_transformer.match(w_expr, closure)
+ assert not w_transformer.match(closure, w_expr)
# the same binding for => in ctx and closure
ctx.put("=>", w_42)
assert ctx.get("=>") is closure.get("=>")
w_transformer = eval_(ctx, "(syntax-rules (=>) ((foo => bar) #t))")
- assert w_transformer.match(w_expr, closure)
+ assert w_transformer.match(closure, w_expr)
def test_syntax_rules_expand_simple():
ctx = ExecutionContext()
@@ -85,12 +86,12 @@
((_ foo) foo))""")
w_expr = parse("(foo)")[0]
- w_expanded = w_transformer.expand(w_expr, ctx)
+ w_expanded = w_transformer.expand(ctx, w_expr)
assert isinstance(w_expanded, W_Boolean)
assert w_expanded.to_boolean() == True
w_expr = parse("(foo bar)")[0]
- w_expanded = w_transformer.expand(w_expr, ctx)
+ w_expanded = w_transformer.expand(ctx, w_expr)
assert w_expanded.to_string() == "bar"
w_transformer = eval_(ctx, """(syntax-rules ()
@@ -98,7 +99,7 @@
(let ((var val)) body)))""")
w_expr = parse("(let1 var 12 (+ 1 var))")[0]
- w_expanded = w_transformer.expand(w_expr, ctx)
+ w_expanded = w_transformer.expand(ctx, w_expr)
assert isinstance(w_expanded, W_Pair)
assert w_expanded.to_string() == "(let ((var 12)) (+ 1 var))"
@@ -107,7 +108,7 @@
(let ((var val)) body)))""")
w_expr = parse("(let1 (var 12) (+ 1 var))")[0]
- w_expanded = w_transformer.expand(w_expr, ctx)
+ w_expanded = w_transformer.expand(ctx, w_expr)
assert isinstance(w_expanded, W_Pair)
assert w_expanded.to_string() == "(let ((var 12)) (+ 1 var))"
@@ -119,25 +120,25 @@
(let ((temp 1)) (+ var temp))))""")
w_expr = parse("(_ 12)")[0]
- w_expanded = w_transformer.expand(w_expr, ctx)
+ w_expanded = w_transformer.expand(ctx, w_expr)
assert w_expanded.to_string() == "(let ((temp 1)) (+ 12 temp))"
- assert w_transformer.expand_eval(w_expr, ctx).to_number() == 13
+ assert w_transformer.expand_eval(ctx, w_expr).to_number() == 13
#transparency
eval_(ctx, "(define temp 12)")
w_expr = parse("(_ temp)")[0]
- w_expanded = w_transformer.expand(w_expr, ctx)
+ w_expanded = w_transformer.expand(ctx, w_expr)
assert w_expanded.to_string() == "(let ((temp 1)) (+ temp temp))"
- assert w_transformer.expand_eval(w_expr, ctx).to_number() == 13
+ assert w_transformer.expand_eval(ctx, w_expr).to_number() == 13
#define in closure, should not affect macro eval
closure = ctx.copy()
eval_(closure, "(define + -)")
- assert w_transformer.expand_eval(w_expr, closure).to_number() == 13
+ assert w_transformer.expand_eval(closure, w_expr).to_number() == 13
#define in top level - should affect macro eval
eval_(ctx, "(define + -)")
- assert w_transformer.expand_eval(w_expr, ctx).to_number() == 11
+ assert w_transformer.expand_eval(ctx, w_expr).to_number() == 11
def test_syntax_rules_hygenic_expansion():
ctx = ExecutionContext()
@@ -154,11 +155,11 @@
(loop count))))""")
w_expr = parse("(dotimes 5 (set! counter (+ counter 1)))")[0]
- py.test.raises(UnboundVariable, w_transformer.expand_eval, w_expr, ctx)
+ py.test.raises(UnboundVariable, w_transformer.expand_eval, ctx, w_expr)
eval_(ctx, "(define counter 0)")
w_expr = parse("(dotimes 5 (set! counter (+ counter 1)))")[0]
- w_transformer.expand_eval(w_expr, ctx)
+ w_transformer.expand_eval(ctx, w_expr)
assert ctx.get("counter").to_number() == 5
def test_shadow():
@@ -169,10 +170,10 @@
(let ((used-arg 5)) body)))""")
w_expr = parse("(shadow test test)")[0]
- assert w_transformer.expand_eval(w_expr, ctx).to_number() == 5
+ assert w_transformer.expand_eval(ctx, w_expr).to_number() == 5
eval_(ctx, "(define test 7)")
- assert w_transformer.expand_eval(w_expr, ctx).to_number() == 5
+ assert w_transformer.expand_eval(ctx, w_expr).to_number() == 5
def test_transformer_eval():
ctx = ExecutionContext()
@@ -180,20 +181,37 @@
((_) #t)
((_ bar) bar)))""")
- w_foo = eval_(ctx, "(foo '(_))")
- assert w_foo.to_boolean()
-
- w_foobar = eval_(ctx, """(foo '(_ 42))""")
- assert w_foobar.to_number() == 42
+ assert eval_(ctx, "(foo '(_))").to_boolean()
+ assert eval_(ctx, "(foo '(_ 42))").to_number() == 42
def test_define_syntax():
ctx = ExecutionContext()
- eval_(ctx, """(define-syntax foo (syntax-rules ()
- ((_) #t)
- ((_ bar) bar)))""")
- w_foo = eval_(ctx, """(foo)""")
- assert w_foo.to_boolean()
-
- w_foobar = eval_(ctx, """(foo 42)""")
- assert w_foobar.to_number() == 42
+ eval_(ctx, """(define-syntax foo
+ (syntax-rules ()
+ ((_) #t)
+ ((_ bar) bar)))""")
+
+ assert eval_(ctx, "(foo)").to_boolean()
+ assert eval_(ctx, "(foo 42)").to_number() == 42
+
+def test_recursive_macro():
+ ctx = ExecutionContext()
+ eval_(ctx, """(define-syntax my-or
+ (syntax-rules ()
+ ((my-or) #f)
+ ((my-or arg) arg)
+ ((my-or arg1 arg2)
+ (if arg1
+ arg1
+ (my-or arg2)))))""")
+
+ assert eval_(ctx, "(my-or)").to_boolean() is False
+ assert eval_(ctx, "(my-or 12)").to_number() == 12
+
+ #should expand recursively and after that eval, how to check it?
+ w_expr = parse("(my-or 12 42)")[0]
+ assert ctx.get("my-or").expand(ctx, w_expr).to_string() == \
+ "(if 12 12 42)"
+ assert eval_(ctx, "(my-or 12 42)").to_number() == 12
+ assert eval_(ctx, "(my-or #f 42)").to_number() == 42
More information about the Pypy-commit
mailing list