def test_hefty1_computation(): ctx = ExecutionContext() eval_(ctx, "(define side-effects '())") eval_( ctx, """ (define (hefty-computation do-other-stuff) (letrec ((loop (lambda (n) (set! side-effects (cons (list 'hefty-a n) side-effects)) (set! do-other-stuff (call/cc do-other-stuff)) (set! side-effects (cons (list 'hefty-b n) side-effects)) (set! do-other-stuff (call/cc do-other-stuff)) (set! side-effects (cons (list 'hefty-c n) side-effects)) (set! do-other-stuff (call/cc do-other-stuff)) (if (zero? n) '() (loop (- n 1)))))) (loop 1)))""") eval_( ctx, """ (define (superfluous-computation do-other-stuff) (letrec ((loop (lambda () (set! side-effects (cons 'break side-effects)) (set! do-other-stuff (call/cc do-other-stuff)) (loop)))) (loop)))""") eval_(ctx, "(hefty-computation superfluous-computation)") assert ctx.get("side-effects").to_string() == \ """(break (hefty-c 0) break (hefty-b 0) break (hefty-a 0) break (hefty-c 1) break (hefty-b 1) break (hefty-a 1))"""
def test_lambda_call(): ctx = ExecutionContext() eval_(ctx, "(define c1 'none)") eval_(ctx, "(define c2 'none)") eval_( ctx, """(define fun (lambda (x y z) (call/cc (lambda (k) (set! c1 k))) (+ x y z)))""") assert ctx.get("c1").to_string() == "none" assert ctx.get("c2").to_string() == "none" eval_( ctx, """(fun (call/cc (lambda (k) (set! c2 k) 1)) 2 3)""") w_result = eval_(ctx, "(c1)") assert w_result.to_number() == 6 w_result = eval_(ctx, "(c2 0)") assert w_result.to_number() == 5 w_result = eval_(ctx, "(c1)") assert w_result.to_number() == 5 w_result = eval_(ctx, "(c2 5)") assert w_result.to_number() == 10 w_result = eval_(ctx, "(c1)") assert w_result.to_number() == 10
def test_syntax_rules_expand(): ctx = ExecutionContext() w_transformer = eval_( ctx, """(syntax-rules () ((_ var) (let ((temp 1)) (+ var temp))))""") w_expr = parse_("(_ 12)") w_expanded = w_transformer.expand(ctx, w_expr) assert w_expanded.to_string() == "(let ((temp 1)) (+ 12 temp))" assert w_transformer.expand_eval(ctx, w_expr).to_number() == 13 #transparency eval_(ctx, "(define temp 12)") w_expr = parse_("(_ temp)") w_expanded = w_transformer.expand(ctx, w_expr) assert w_expanded.to_string() == "(let ((temp 1)) (+ temp temp))" # the two occurrences of 'temp in (+ temp temp) are not the same symbol! 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(closure, w_expr).to_number() == 13 #define in top level - should affect macro eval eval_(ctx, "(define + -)") assert w_transformer.expand_eval(ctx, w_expr).to_number() == 11
def interactive(): print "PyPy Scheme interpreter" ctx = ExecutionContext() to_exec = "" cont = False while 1: if cont: ps = '.. ' else: ps = '-> ' sys.stdout.write(ps) to_exec += sys.stdin.readline() if to_exec == "\n": to_exec = "" elif check_parens(to_exec): try: if to_exec == "": print raise SchemeQuit print parse(to_exec)[0].eval(ctx).to_string() except SchemeQuit, e: break except ContinuationReturn, e: print e.result.to_string() except SchemeException, e: print "error: %s" % e
def test_eqv(): ctx = ExecutionContext() assert eval_(ctx, "(eqv? #t #t)").to_boolean() is True assert eval_(ctx, "(eqv? #f #f)").to_boolean() is True assert eval_(ctx, "(eqv? 'symb 'symb)").to_boolean() is True assert eval_(ctx, "(eqv? 'symb 'SYMB)").to_boolean() is True assert eval_(ctx, "(eqv? 42 42)").to_boolean() is True assert eval_(ctx, "(eqv? 42.1 42.1)").to_boolean() is True #assert eval_(ctx, "(eqv? #\a #\a)").to_boolean() is True assert eval_(ctx, "(eqv? '() '())").to_boolean() is True assert eval_( ctx, """(let ((p (cons 1 2))) (eqv? p p))""").to_boolean() is True #assert eval_(ctx, """(let ((p "a string")) # (eqv? p p))""").to_boolean() is True assert eval_( ctx, """(let ((p (lambda (x) x))) (eqv? p p))""").to_boolean() is True assert eval_(ctx, "(eqv? #t 'symb)").to_boolean() is False assert eval_(ctx, "(eqv? #f 42)").to_boolean() is False assert eval_(ctx, "(eqv? #t #f)").to_boolean() is False assert eval_(ctx, "(eqv? 'symb1 'symb2)").to_boolean() is False assert eval_(ctx, "(eqv? 42 42.0)").to_boolean() is False assert eval_(ctx, "(eqv? 42.0 42)").to_boolean() is False assert eval_(ctx, "(eqv? 42 43)").to_boolean() is False assert eval_(ctx, "(eqv? 42.1 42.2)").to_boolean() is False #assert eval_(ctx, "(eqv? #\a #\b)").to_boolean() is False assert eval_(ctx, "(eqv? (cons 1 2) (cons 1 2))").to_boolean() is False #assert eval_(ctx, """(eqv? "a string" # "a string")""").to_boolean() is False assert eval_( ctx, """(eqv? (lambda () 1) (lambda () 2))""").to_boolean() is False
def test_syntax_rules_expand_simple(): ctx = ExecutionContext() w_transformer = eval_( ctx, """(syntax-rules () ((_) #t) ((_ foo) foo))""") w_expr = parse_("(foo)") 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)") w_expanded = w_transformer.expand(ctx, w_expr) assert w_expanded.to_string() == "bar" w_transformer = eval_( ctx, """(syntax-rules () ((let1 var val body) (let ((var val)) body)))""") w_expr = parse_("(let1 var 12 (+ 1 var))") w_expanded = w_transformer.expand(ctx, w_expr) assert isinstance(w_expanded, W_Pair) assert w_expanded.to_string() == "(let ((var 12)) (+ 1 var))" w_transformer = eval_( ctx, """(syntax-rules () ((let1 (var val) body) (let ((var val)) body)))""") w_expr = parse_("(let1 (var 12) (+ 1 var))") w_expanded = w_transformer.expand(ctx, w_expr) assert isinstance(w_expanded, W_Pair) assert w_expanded.to_string() == "(let ((var 12)) (+ 1 var))"
def test_begin(): ctx = ExecutionContext() w_global = W_Integer(0) ctx.put("var", w_global) w_result = eval_(ctx, "(begin (set! var 11) (+ var 33))") assert w_result.to_number() == 44 assert ctx.get("var").to_number() == 11
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))) ((my-or arg1 arg2 arg3) (if arg1 arg1 (my-or arg2 arg3)))))""") 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 w_expr = parse_("(my-or 12 42)") assert ctx.get("my-or").expand(ctx, w_expr).to_string() == \ "(if 12 12 42)" w_expr = parse_("(my-or 12 42 82)") assert ctx.get("my-or").expand(ctx, w_expr).to_string() == \ "(if 12 12 (if 42 42 82))" assert eval_(ctx, "(my-or 12 42)").to_number() == 12 assert eval_(ctx, "(my-or #f 42)").to_number() == 42 assert eval_(ctx, "(my-or #f #f 82)").to_number() == 82
def test_letrec(): ctx = ExecutionContext() w_result = eval_( ctx, """ (letrec ((even? (lambda (n) (if (= n 0) #t (odd? (- n 1))))) (odd? (lambda (n) (if (= n 0) #f (even? (- n 1)))))) (even? 2000))""") assert w_result.to_boolean() is True w_result = eval_( ctx, """ (let ((x (lambda () 1))) (letrec ((y (lambda () (x))) (x (lambda () 2))) (y)))""") assert w_result.to_number() == 2 py.test.raises(UnboundVariable, eval_noctx, "(letrec ((y 0) (x y)) x)")
def test_ellipsis_nested_nil(): ctx = ExecutionContext() eval_( ctx, """(define-syntax or (syntax-rules () ((or) #f) ((or (e1) (e2 ...) ...) (let ((temp e1)) (if temp temp (or (e2) ... ...))))))""") assert eval_(ctx, "(or (12))").to_number() == 12 assert eval_(ctx, "(or (#f))").to_boolean() is False assert eval_(ctx, "(or (#f) (42))").to_number() == 42 assert eval_(ctx, "(or (#f) (#f) (82))").to_number() == 82 assert eval_(ctx, "(or (#f) (#f) (#f) (162))").to_number() == 162 #here scheme48 does not agree with me, it expands to: # (let ((temp #f)) # (if temp # temp # (or (#f #f 162)))) # ^ this should be (my and mzscheme opinion) # (or (#f) (#f) (162)))) assert eval_(ctx, "(or (#f) (#f #f 162))").to_number() == 162 assert eval_(ctx, "(or (#f) (#f #f) (#f #f 322))").to_number() == 322
def entry_point(argv): if len(argv) == 2: code = open_file_as_stream(argv[1]).readall() try: t = parse(code) except BacktrackException: #(line, col) = e.error.get_line_column(code) #expected = " ".join(e.error.expected) print "parse error" return 1 #this should not be necessary here assert isinstance(t, list) ctx = ExecutionContext() try: for sexpr in t: try: w_retval = sexpr.eval(ctx) print w_retval.to_string() except ContinuationReturn, e: print e.result.to_string() except SchemeQuit, e: return 0 return 0
def test_lambda_lstarg(): ctx = ExecutionContext() w_result = eval_(ctx, """((lambda x x) 1 2 3)""") assert isinstance(w_result, W_Pair) assert w_result.car.to_number() == 1 assert w_result.cdr.car.to_number() == 2 assert w_result.cdr.cdr.car.to_number() == 3
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)") py.test.raises(MatchError, w_transformer.match, ctx, w_expr) w_transformer = eval_noctx("(syntax-rules () ((foo) #t))") w_expr = parse_("(bar)") assert w_transformer.match(ctx, w_expr)[0].to_boolean() w_expr = parse_("(foo bar)") py.test.raises(MatchError, w_transformer.match, ctx, w_expr) w_transformer = eval_noctx("""(syntax-rules () ((_) #t) ((_ foo) foo))""") w_expr = parse_("(foo)") assert w_transformer.match(ctx, w_expr)[0].to_boolean() w_expr = parse_("(foo bar)") (template, match_dict) = w_transformer.match(ctx, w_expr) assert template.to_string() == "foo" assert match_dict["foo"].to_string() == "bar" w_expr = parse_("(foo bar boo)") py.test.raises(MatchError, w_transformer.match, ctx, w_expr) w_transformer = eval_noctx("(syntax-rules () ((foo (bar)) bar))") w_expr = parse_("(_ fuzz)") py.test.raises(MatchError, w_transformer.match, ctx, w_expr) w_expr = parse_("(_ (fuzz))") (template, match_dict) = w_transformer.match(ctx, w_expr) assert template.to_string() == "bar" assert match_dict["bar"].to_string() == "fuzz"
def test_loop(): ctx = ExecutionContext() eval_(ctx, "(define k 'none)") eval_(ctx, "(define num 'none)") w_result = eval_( ctx, """ (call/cc (lambda (return) (letrec ((loop (lambda (n) (if (zero? n) 0 (begin (call/cc (lambda (cc) (set! k cc) (return n))) (set! num n) (loop (- n 1))))))) (loop 10))))""") assert w_result.to_number() == 10 assert isinstance(ctx.get("k"), Continuation) assert ctx.get("num").to_string() == "none" for i in range(9, -1, -1): w_result = eval_(ctx, "(k)") assert w_result.to_number() == i assert ctx.get("num").to_number() == i + 1 w_result = eval_(ctx, "(k)") assert w_result.to_number() == 0 assert ctx.get("num").to_number() == 1
def test_setcar(): ctx = ExecutionContext() w_pair = eval_(ctx, "(define lst '(1 2 3 4))") eval_(ctx, "(set-car! lst 11)") assert w_pair is eval_(ctx, "lst") assert eval_(ctx, "(car lst)").to_number() == 11 eval_(ctx, "(set-car! (cdr lst) 12)") assert eval_(ctx, "(car (cdr lst))").to_number() == 12
def test_sete(): ctx = ExecutionContext() eval_(ctx, "(define x 42)") loc1 = ctx.get_location("x") eval_(ctx, "(set! x 43)") loc2 = ctx.get_location("x") assert ctx.get("x").to_number() == 43 assert loc1 is loc2 py.test.raises(UnboundVariable, eval_, ctx, "(set! y 42)")
def test_different_ellipsis(): ctx = ExecutionContext() eval_( ctx, """(define-syntax let2 (syntax-rules () ((_ (sym ...) (val ...) body ...) (let ((sym val) ...) body ...))))""") assert eval_(ctx, "(let2 (x y z) (1 2 3) (+ x y z))").to_number() == 6
def test_sete(): ctx = ExecutionContext() eval_(ctx, "(define a 42)") eval_( ctx, """(let-syntax ((foo (syntax-rules () ((foo var val) (set! var val))))) (foo a 0))""") assert eval_(ctx, "a").to_number() == 0
def test_ellipsis_wo_ellipsis(): ctx = ExecutionContext() eval_( ctx, """(define-syntax let-default (syntax-rules () ((_ (sym ...) val body ...) (let ((sym val) ...) body ...))))""") assert eval_(ctx, "(let-default (x y z) 1 (+ x y z))").to_number() == 3
def test_lambda_dotted_lstarg(): ctx = ExecutionContext() w_result = eval_(ctx, """((lambda (x y . z) z) 3 4)""") assert w_result is w_nil w_result = eval_(ctx, """((lambda (x y . z) z) 3 4 5 6)""") assert isinstance(w_result, W_Pair) assert w_result.car.to_number() == 5 assert w_result.cdr.car.to_number() == 6 assert w_result.cdr.cdr is w_nil
def test_list(): ctx = ExecutionContext() ctx.put("var", W_Integer(42)) w_lst = eval_(ctx, "(list 1 var (+ 2 1) 'a)") assert isinstance(w_lst, W_Pair) assert w_lst.car.to_number() == 1 assert w_lst.cdr.car.to_number() == 42 assert w_lst.cdr.cdr.car.to_number() == 3 assert w_lst.cdr.cdr.cdr.car.to_string() == "a" assert w_lst.cdr.cdr.cdr.cdr is w_nil
def test_define_syntax(): ctx = ExecutionContext() 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_lambda_noargs(): ctx = ExecutionContext() w_lambda = eval_(ctx, "(lambda () 12)") assert isinstance(w_lambda, W_Procedure) assert isinstance(w_lambda, W_Lambda) ctx.put("f1", w_lambda) w_result = eval_(ctx, "(f1)") assert isinstance(w_result, W_Integer) assert w_result.to_number() == 12
def test_let_define(): ctx = ExecutionContext() eval_( ctx, """(define oo (let ((cont (call/cc (lambda (k) k)))) cont))""") assert isinstance(ctx.get("oo"), Continuation) eval_(ctx, "(oo +)") assert ctx.get("oo") is ctx.get("+")
def test_transformer_eval(): # test direct manipulation of syntax-rules objects: # that's an extension to the R5RS ctx = ExecutionContext() eval_( ctx, """(define foo (syntax-rules () ((_) #t) ((_ bar) bar)))""") assert eval_(ctx, "(foo '(_))").to_boolean() assert eval_(ctx, "(foo '(_ 42))").to_number() == 42
def test_ctx(): w_fnum = W_Integer(12) w_symb = W_Symbol("symb") ctx = ExecutionContext() ctx.put("v1", w_fnum) ctx.put("symb", w_symb) assert w_symb is ctx.get("symb") assert w_fnum is ctx.get("v1") py.test.raises(UnboundVariable, ctx.get, "no_such_key")
def test_ctx_simple(): ctx = ExecutionContext() ctx.put("v1", W_Integer(4)) ctx.put("v2", W_Integer(5)) w_num = eval_(ctx, "(+ 1 v1 v2)") assert w_num.to_number() == 10 ctx.put("v2", W_Real(3.2)) w_num = eval_(ctx, "(+ 1 v1 v2)") assert w_num.to_number() == 8.2
def test_pitfall_3_2(): ctx = ExecutionContext() #define inside macors can and sometimes can not introduce new binding w_result = eval_( ctx, """(let-syntax ((foo (syntax-rules () ((_ var) (define var 1))))) (let ((x 2)) (begin (define foo +)) (cond (else (foo x))) x))""") assert w_result.to_number() == 2
def test_nested_ellipsis(): ctx = ExecutionContext() eval_( ctx, """(define-syntax quote-lists (syntax-rules () ((_ (obj ...) ...) (quote ((obj ...) ... end)))))""") assert eval_(ctx, """(quote-lists (x y) (1 2 3 4) (+))""").to_string() == \ "((x y) (1 2 3 4) (+) end)"
def test_reverse(): ctx = ExecutionContext() eval_( ctx, """(define-syntax reverse-order (syntax-rules () ((_ e) (reverse-order e ())) ((_ (e . rest) r) (reverse-order rest (e . r))) ((_ () r) r)))""") w_result = eval_(ctx, "(reverse-order (2 3 -))") assert w_result.to_number() == 1