def Can_append_item_to_a_nonempty_list(): assert_that(evald("first(append(list2(1, 2), 3));"), equals(evald("1;"))) assert_that(evald("first(second(append(list2(1, 2), 3)));"), equals(evald("2;"))) assert_that(evald("first(second(second(append(list2(1, 2), 3))));"), equals(evald("3;"))) assert_that(evald("second(second(second(append(list2(1, 2), 3))));"), equals(evald("None;")))
def Can_construct_a_nonempty_value_class_using_positional_args(): @valueclass("mem1", "mem2") class MyClass: pass b = MyClass(3, 4) assert_that(b.mem1, equals(3)) assert_that(b.mem2, equals(4))
def Can_construct_a_nonempty_value_class_using_keyword_args(): @valueclass("mem1", "mem2") class MyClass: pass b = MyClass(mem1=3, mem2=4) assert_that(b.mem1, equals(3)) assert_that(b.mem2, equals(4))
def Readline_reads_up_to_a_newline(): pipe = Pipe() pipe.write("ab") pipe.write("c\nd") pipe.write("e") pipe.write("\nghi") pipe.close() assert_that(pipe.readline(), equals("abc\n")) assert_that(pipe.readline(), equals("de\n")) assert_that(pipe.readline(), equals("ghi"))
def Pipe_can_tell_you_whether_it_has_output_pending(): with Pipe() as p1: assert_that(p1.pending(), equals(False)) p1.write("xxx") assert_that(p1.pending(), equals(True)) p1.read(3) assert_that(p1.pending(), equals(False)) p1.write("xx") p1.close() assert_that(p1.pending(), equals(True)) p1.read() assert_that(p1.pending(), equals(False))
def Function_arguments_are_independent(): assert_that( evald(""" fn = {:(x) {x;};}; a = fn("a"); b = fn("b"); a(); """), equals(evald("'a';"))) assert_that( evald(""" fn = {:(x) {x;};}; a = fn("a"); b = fn("b"); b(); """), equals(evald("'b';")))
def Function_definition_with_params_and_commands_gets_parsed(): assert_that( parsed('{:(x,yy)print(3-4); a = "x"; print(a);};'), equals( [ ( "function", [ ("symbol", "x"), ("symbol", "yy") ], [ ( "call", ("symbol", 'print'), [ ( "operation", '-', ("number", '3'), ("number", '4') ) ] ), ("assignment", ("symbol", 'a'), ("string", 'x')), ("call", ("symbol", 'print'), [("symbol", 'a')]) ] ) ] ) )
def Function_definition_containing_commands_gets_parsed(): assert_that( parsed('{print(3-4); a = "x"; print(a);};'), equals( [ ( "function", [], [ ( "call", ("symbol", 'print'), [ ( "operation", '-', ("number", '3'), ("number", '4') ) ] ), ("assignment", ("symbol", 'a'), ("string", 'x')), ("call", ("symbol", 'print'), [("symbol", 'a')]) ] ) ] ) )
def Multiple_commands_parse_into_multiple_expressions(): program = """ x = 3; func = {:(a) print(a);}; func(x); """ assert_that( parsed(program), equals( [ ("assignment", ("symbol", 'x'), ("number", '3')), ( "assignment", ("symbol", 'func'), ( "function", [("symbol", 'a')], [ ("call", ("symbol", 'print'), [("symbol", 'a')]) ] ) ), ("call", ("symbol", 'func'), [("symbol", 'x')]) ] ) )
def Multiple_function_calls_with_various_args_get_parsed(): assert_that( parsed("print( 'a', 3, 4 / 12 )(512)();"), equals( [ ( "call", ( "call", ( "call", ("symbol", "print"), [ ("string", "a"), ("number", "3"), ( "operation", "/", ("number", "4"), ("number", "12") ) ] ), [ ("number", "512") ] ), [] ) ] ) )
def A_native_function_can_edit_the_environment(): def mx3(env): env.set("x", ("number", 3)) env = Env() env.set("make_x_three", ("native", mx3)) assert_that(evald("x=1;make_x_three();x;", env), equals(("number", 3)))
def A_closure_holds_updateable_values(): def dumb_set(env, sym, val): env.parent.parent.parent.set(sym[1], val) def dumb_if_equal(env, val1, val2, then_fn, else_fn): if val1 == val2: ret = then_fn else: ret = else_fn return eval_expr(("call", ret, []), env) env = Env() env.set("dumb_set", ("native", dumb_set)) env.set("dumb_if_equal", ("native", dumb_if_equal)) assert_that( evald( """ counter = { x = 0; {:(meth) dumb_if_equal(meth, "get", {x;}, {dumb_set("x", x + 1);} ); } }(); counter("inc"); counter("inc"); counter("get"); """, env), equals(("number", 2)))
def A_closure_holds_updateable_values(): def dumb_set(env, sym, val): env.parent.parent.parent.set(sym[1], val) def dumb_if_equal(env, val1, val2, then_fn, else_fn): if val1 == val2: ret = then_fn else: ret = else_fn return eval_expr(("call", ret, []), env) env = Env() env.set("dumb_set", ("native", dumb_set)) env.set("dumb_if_equal", ("native", dumb_if_equal)) assert_that( evald( """ counter = { x = 0; {:(meth) dumb_if_equal(meth, "get", {x;}, {dumb_set("x", x + 1);} ); } }(); counter("inc"); counter("inc"); counter("get"); """, env ), equals(("number", 2)) )
def A_symbol_within_a_function_has_the_local_value(): assert_that( evald(""" foo = 3; bar = {foo = 77;foo;}(); bar; """), equals(("number", 77)))
def The_str_of_a_value_is_its_repr(): @valueclass("m1", "m2", "m3") class MyClass: pass x = MyClass(3, '4', 5) assert_that(str(x), equals(repr(x)))
def All_examples_evaluate(): from pycell.run import run for example in all_examples(): with StringIO() as stdin, StringIO() as stdout: run(example, stdin, stdout, stdout) with open(example[:-5] + ".output.txt") as outputfile: assert_that(stdout.getvalue(), equals(outputfile.read()))
def Native_function_gets_called(): def native_fn(env, x, y): return ("number", x[1] + y[1]) env = Env() env.set("native_fn", ("native", native_fn)) assert_that(evald("native_fn( 2, 8 );", env), equals(("number", 10)))
def Multiple_token_types_can_be_combined(): assert_that( lexed('frobnicate( "Hello" + name, 4 / 5.0);'), equals([("symbol", "frobnicate"), ("(", ""), ("string", "Hello"), ("operation", "+"), ("symbol", "name"), (",", ""), ("number", "4"), ("operation", "/"), ("number", "5.0"), (")", ""), (";", "")]))
def Can_hold_a_reference_to_a_function_and_call_it(): assert_that( evald(""" add = {:(x, y) x + y;}; add(20, 2.2); """), equals(("number", 22.2)) )
def Defining_function_with_js_keyword_name_mangles_it(): assert_that( compiled("for = {7 + 3;};for();"), equals("""var for__ = (function() { return 7 + 3; }); for__(); """))
def Multiplication_of_symbols_is_parsed_as_expression(): assert_that( parsed("foo * bar;"), equals( [ ("operation", "*", ("symbol", "foo"), ("symbol", "bar")) ] ) )
def Defining_function_with_js_keyword_name_mangles_it(): assert_that( compiled("for = {7 + 3;};for();"), equals("""var for__ = (function() { return 7 + 3; }); for__(); """) )
def A_symbol_within_a_function_has_the_local_value(): assert_that( evald(""" foo = 3; bar = {foo = 77;foo;}(); bar; """), equals(("number", 77)) )
def The_repr_of_an_empty_value_can_be_used_to_make_an_equal_one(): @valueclass() class MyClass: pass x = MyClass() x_repr = repr(x) y = eval(x_repr) assert_that(x, equals(y))
def The_repr_of_a_nonempty_value_can_be_used_to_make_an_equal_one(): @valueclass("m1", "m2", "m3") class MyClass: pass x = MyClass(3, '4', 5) x_repr = repr(x) y = eval(x_repr) assert_that(x, equals(y))
def Function_call_with_no_args_gets_parsed(): assert_that( parsed("print();"), equals( [ ("call", ("symbol", "print"), []) ] ) )
def A_native_function_can_edit_the_environment(): def mx3(env): env.set("x", ("number", 3)) env = Env() env.set("make_x_three", ("native", mx3)) assert_that( evald("x=1;make_x_three();x;", env), equals(("number", 3)) )
def Missing_param_definition_with_colon_is_an_error(): try: parsed("{:print(x););") fail("Should throw") except Exception as e: assert_that( str(e), equals("':' must be followed by '(' in a function.") )
def Assigning_to_an_expression_is_an_error(): try: parsed("x(4) = 5;") fail("Should throw") except Exception as e: assert_that( str(e), equals("You can't assign to anything except a symbol.") )
def Empty_function_definition_gets_parsed(): assert_that( parsed("{};"), equals( [ ("function", [], []) ] ) )
def Variable_assignment_gets_parsed(): assert_that( parsed("x = 3;"), equals( [ ("assignment", ("symbol", "x"), ("number", "3")) ] ) )
def Sum_of_numbers_is_parsed_as_expression(): assert_that( parsed("32 + 44;"), equals( [ ("operation", "+", ("number", "32"), ("number", "44")) ] ) )
def Difference_of_symbol_and_number_is_parsed_as_expression(): assert_that( parsed("foo - 44;"), equals( [ ("operation", "-", ("symbol", "foo"), ("number", "44")) ] ) )
def Multiple_function_calls_with_no_args_get_parsed(): assert_that( parsed("print()();"), equals( [ ("call", ("call", ("symbol", "print"), []), []) ] ) )
def Chars_in_deals_well_with_empty_string(): stdout = StringIO() evald(""" for(chars_in(""), {:(ch) print(ch); }); """, stdout=stdout) assert_that(stdout.getvalue(), equals(""))
def Chars_in_allows_iterating_over_the_characters_of_a_string(): stdout = StringIO() evald(""" for(chars_in("abc"), {:(ch) print(ch); }); """, stdout=stdout) assert_that(stdout.getvalue(), equals("a\nb\nc\n"))
def Set_changes_value_of_symbol_in_outer_scope(): assert_that( evald(""" foo = "bar"; fn = { set("foo", "baz"); }; fn(); foo; """), equals(evald('"baz";')))
def Items_separated_by_newlines_become_separate_tokens(): assert_that( lexed("foo\nbar"), equals( [ ("symbol", "foo"), ("symbol", "bar") ] ) )
def Symbols_may_contain_numbers_and_underscores(): assert_that( lexed("foo2_bar ( "), equals( [ ("symbol", "foo2_bar"), ("(", "") ] ) )
def For_loops_through_nothing_when_given_empty_list(): stdout = StringIO() evald(""" for(list0(), {:(ch) print(ch); }); """, stdout=stdout) assert_that(stdout.getvalue(), equals(""))
def For_loops_through_everything_in_a_list(): stdout = StringIO() evald(""" for(list3("a", "b", "c"), {:(ch) print(ch); }); """, stdout=stdout) assert_that(stdout.getvalue(), equals("a\nb\nc\n"))
def All_examples_evaluate(): from pycell.run import run for example in all_examples(): try: with StringIO() as stdin, StringIO() as stdout: run(example, stdin, stdout, stdout) with open(example[:-5] + ".output.txt") as outputfile: assert_that(stdout.getvalue(), equals(outputfile.read())) except Exception as e: raise Exception("%s: %s" % (example, str(e)))
def Compiling_use_of_if_renders_immediately_called_function(): assert_that( compiled("if(1, {'true'}, {'false'});"), equals("""(function() { if( 1 !== 0 ) { return 'true'; } else { return 'false'; } })();\n"""))
def Symbols_may_start_with_underscores(): assert_that( lexed("_foo2_bar ( "), equals( [ ("symbol", "_foo2_bar"), ("(", "") ] ) )
def Compiling_use_of_if_renders_immediately_called_function(): assert_that( compiled("if(1, {'true'}, {'false'});"), equals("""(function() { if( 1 !== 0 ) { return 'true'; } else { return 'false'; } })();\n""") )