From d6b6d6105a2a56b97ae6bee0e6e8ba306f970d19 Mon Sep 17 00:00:00 2001 From: ChUrl Date: Mon, 9 Aug 2021 16:36:55 +0200 Subject: [PATCH] vorgabe tests --- test/test_builtin.py | 86 ++++++++++++++++ test/test_bytecode.py | 206 ++++++++++++++++++++++++++++++++++++++ test/test_interpreter.py | 123 +++++++++++++++++++++++ test/test_method.py | 82 +++++++++++++++ test/test_objmodel.py | 38 +++++++ test/test_parent.py | 205 +++++++++++++++++++++++++++++++++++++ test/test_primitive.py | 42 ++++++++ test/test_simplelexer.py | 100 ++++++++++++++++++ test/test_simpleparser.py | 149 +++++++++++++++++++++++++++ 9 files changed, 1031 insertions(+) create mode 100644 test/test_builtin.py create mode 100644 test/test_bytecode.py create mode 100644 test/test_interpreter.py create mode 100644 test/test_method.py create mode 100644 test/test_objmodel.py create mode 100644 test/test_parent.py create mode 100644 test/test_primitive.py create mode 100644 test/test_simplelexer.py create mode 100644 test/test_simpleparser.py diff --git a/test/test_builtin.py b/test/test_builtin.py new file mode 100644 index 0000000..305725a --- /dev/null +++ b/test/test_builtin.py @@ -0,0 +1,86 @@ +import py + +from simpleparser import parse +from objmodel import W_NormalObject +from interpreter import Interpreter + +def test_builtin_simple(): + builtincode = """ +x = 1 +object None: + 1 +def pass: + None +""" + # construct the builtin module by running builtincode within the context of + # a new empty module + interpreter = Interpreter(builtincode) + w_module = interpreter.make_module() + # the parent of a normal module is the builtin module + builtins = w_module.getparents()[0] + assert builtins.getvalue('x').value == 1 + + ast = parse(""" +tx = x +object a: + pass +ax = a x +""") + interpreter.eval(ast, w_module) + assert w_module.getvalue("ax").value == 1 + assert w_module.getvalue("tx").value == 1 + +def test_inttrait(): + builtincode = """ +object inttrait: + x = 1 + def maybe_fortytwo: + if self: + 42 + else: + x +""" + interpreter = Interpreter(builtincode) + w_module = interpreter.make_module() + # the parent of a normal module is the builtin module + builtins = w_module.getparents()[0] + inttrait = builtins.getvalue("inttrait") + + ast = parse(""" +x = 5 x # this returns 1, because it looks in the inttrait defined above +m0 = 0 maybe_fortytwo +m1 = x maybe_fortytwo +inttrait x = 2 +m2 = 0 maybe_fortytwo +tr = inttrait +""") + interpreter.eval(ast, w_module) + x = w_module.getvalue("x") + assert w_module.getvalue("tr") is inttrait + # the inttrait is defined in the builtin module, so its __parent__ is that + # module + assert inttrait.getparents() == [builtins] + assert x.value == 1 + assert x.getparents() == [inttrait] + assert w_module.getvalue("m0").value == 1 + assert w_module.getvalue("m1").value == 42 + assert w_module.getvalue("m2").value == 2 + + +def test_builtin_default(): + ast = parse(""" +def sumupto(x): + r = 0 + while x: + r = r add(x) + x = x add(-1) + r +x = sumupto(100) +""") + # the constructor is called without arguments, so the default builtins are + # used + interpreter = Interpreter() + # test that the default inttrait defines a method ``add`` + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").value == 5050 diff --git a/test/test_bytecode.py b/test/test_bytecode.py new file mode 100644 index 0000000..05eb0cb --- /dev/null +++ b/test/test_bytecode.py @@ -0,0 +1,206 @@ +import py + +from simpleparser import parse +from objmodel import W_NormalObject +from interpreter import Interpreter + +empty_builtins = """ +1 +""" + + +def test_assignment(): + ast = parse(""" +x = 1 +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").value == 1 + + +def test_negative_intliteral(): + ast = parse(""" +x = -1 +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").value == -1 + + +def test_huge_intliteral(): + ast = parse(""" +x = 10000 +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").value == 10000 + + +def test_huge_negative_intliteral(): + ast = parse(""" +x = -10000 +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").value == -10000 + + +def test_primitive(): + ast = parse(""" +x = 1 $int_add(2) +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").value == 3 + + +def test_pop(): + ast = parse(""" +x = 1 # the result of this will be popped from the stack +x = 2 +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").value == 2 + + +def test_condition(): + ast = parse(""" +x = 1 +if x: + x = 2 +else: + x = 3 +if 0: + y = 3 +else: + y = 4 +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").value == 2 + assert w_module.getvalue("y").value == 4 + + +def test_objectdefinition_simple(): + ast = parse(""" +object x: + a = 1 + b = 2 +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").getvalue("a").value == 1 + assert w_module.getvalue("x").getvalue("b").value == 2 + + +def test_objectdefinition_parents(): + ast = parse(""" +object x: + a = 1 + b = 2 +object y(parent=x): + b = 3 +a = y a +b = y b +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("a").value == 1 + assert w_module.getvalue("b").value == 3 + + +def test_objectdefinition___parent__(): + ast = parse(""" +object x: + a = 1 + b = 2 +object y(__parent__=x): + b = 3 +a = y a +b = y b +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("a").value == 1 + assert w_module.getvalue("b").value == 3 + + +def test_functiondefinition_noargs(): + ast = parse(""" +def f: + if x: + 1 + else: + 2 +x = 0 +x = f +y = f +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").value == 2 + assert w_module.getvalue("y").value == 1 + + +def test_functiondefinition_args(): + ast = parse(""" +def f(x): + if x: + 1 + else: + 2 +x = f(0) +y = f(1) +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").value == 2 + assert w_module.getvalue("y").value == 1 + + +def test_whileloop(): + ast = parse(""" +def f(x): + sum = 0 + while x: + sum = sum $int_add(x) + x = x $int_add(-1) + sum +x = f(100) +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").value == 5050 + + +def test_method_cascade(): + ast = parse(""" +object x: + a = 1 +object y: + a = 2 +x next = y +y next = x + +a = x next next next next next next a +b = x next next next next next next next a +""") + interpreter = Interpreter(empty_builtins) + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("a").value == 1 + assert w_module.getvalue("b").value == 2 diff --git a/test/test_interpreter.py b/test/test_interpreter.py new file mode 100644 index 0000000..962fb84 --- /dev/null +++ b/test/test_interpreter.py @@ -0,0 +1,123 @@ +import py + +from simpleparser import parse +from objmodel import W_NormalObject +from interpreter import Interpreter + + +# +# The Interpreter class needs a method 'eval(ast, w_context)' that is +# doing "AST visiting", as follows: +# +# def eval(self, ast, w_context): +# method = getattr(self, "eval_" + ast.__class__.__name__) +# return method(ast, w_context) +# +# This calls a method called "eval_Xxx" on self for every class +# called Xxx of the simpleast.py module. +# +def test_simplxe(): + ast = parse(""" +10 +11 +12 +""") + w_module = W_NormalObject() + interpreter = Interpreter() + interpreter.eval(ast, w_module) + + +def test_simple(): + ast = parse(""" +k = 10 +j = 11 +i = 12 +""") + w_module = W_NormalObject() + interpreter = Interpreter() + interpreter.eval(ast, w_module) + assert w_module.getvalue("i").value == 12 + assert w_module.getvalue("j").value == 11 + assert w_module.getvalue("k").value == 10 + + +def test_if(): + ast = parse(""" +k = 10 +if k: + j = 11 +else: + i = 12 +""") + w_module = W_NormalObject() + interpreter = Interpreter() + interpreter.eval(ast, w_module) + assert w_module.getvalue("i") is None + assert w_module.getvalue("j").value == 11 + assert w_module.getvalue("k").value == 10 + + +def test_def(): + ast = parse(""" +def f(x, y): + if x: + x + else: + y +i = f(6, 3) +j = f(0, 9) +""") + w_module = W_NormalObject() + interpreter = Interpreter() + interpreter.eval(ast, w_module) + assert w_module.getvalue("i").value == 6 + assert w_module.getvalue("j").value == 9 + + +def test_object(): + ast = parse(""" +object x: + i = 4 + j = i + object z: + i = 5 +""") + w_module = W_NormalObject() + interpreter = Interpreter() + interpreter.eval(ast, w_module) + assert w_module.getvalue("x").getvalue("i").value == 4 + assert w_module.getvalue("x").getvalue("j").value == 4 + assert w_module.getvalue("x").getvalue("z").getvalue("i").value == 5 + + +def test_obscure_recursion(): + ast = parse(""" +object a: + def f(a): + if a: + x = 5 + a f(0) + else: + x = 7 + x +i = a f(a) +""") + w_module = W_NormalObject() + interpreter = Interpreter() + interpreter.eval(ast, w_module) + assert w_module.getvalue("i").value == 5 + + +def test_assign(): + ast = parse(""" +object a: + b = 5 + def set(n): + self b = n +a set(7) +i = a b +""") + w_module = W_NormalObject() + interpreter = Interpreter() + interpreter.eval(ast, w_module) + assert w_module.getvalue("i").value == 7 diff --git a/test/test_method.py b/test/test_method.py new file mode 100644 index 0000000..843fbf5 --- /dev/null +++ b/test/test_method.py @@ -0,0 +1,82 @@ +import py + +from simpleparser import parse +from objmodel import W_NormalObject +from interpreter import Interpreter + +def test_assign(): + ast = parse(""" +object a: + b = 5 + def set(n): + self b = n +a set(7) +i = a b +""") + w_module = W_NormalObject() + interpreter = Interpreter() + interpreter.eval(ast, w_module) + assert w_module.getvalue("i").value == 7 + + +def test_method_simple(): + ast = parse(""" +object a: + x = 11 + def f: + self x +object b: + __parent__ = a + x = 22 +af = a f # a is the receiver, therefore self is a in the method +bf = b f # b is the receiver, therefore self is b in the method + +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("af").value == 11 + assert w_module.getvalue("bf").value == 22 + + +def test_method_complex(): + ast = parse(""" +k = 10 +object a: + x = 11 + y = 22 + def f(a, b): + if a: + if b: + a + else: + k + else: + if b: + self x + else: + self y +object b: + __parent__ = a + y = 55 +af11 = a f(1, 1) +af10 = a f(1, 0) +af01 = a f(0, 1) +af00 = a f(0, 0) +k = 908 +bf11 = b f(1, 1) +bf10 = b f(1, 0) +bf01 = b f(0, 1) +bf00 = b f(0, 0) +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("af11").value == 1 + assert w_module.getvalue("af10").value == 10 + assert w_module.getvalue("af01").value == 11 + assert w_module.getvalue("af00").value == 22 + assert w_module.getvalue("bf11").value == 1 + assert w_module.getvalue("bf10").value == 908 + assert w_module.getvalue("bf01").value == 11 + assert w_module.getvalue("bf00").value == 55 diff --git a/test/test_objmodel.py b/test/test_objmodel.py new file mode 100644 index 0000000..6edee41 --- /dev/null +++ b/test/test_objmodel.py @@ -0,0 +1,38 @@ +from objmodel import W_Integer, W_NormalObject + + +def test_normalobject(): + w1 = W_NormalObject() + # 'setvalue' and 'getvalue' write and read the attributes by name. + w1.setvalue('abc', W_Integer(6)) + w2 = w1.getvalue('abc') + assert isinstance(w2, W_Integer) + assert w2.value == 6 + # a missing attribute... + assert w1.getvalue('bcd') is None + + +def test_integer(): + w1 = W_Integer(5) + assert w1.value == 5 + # W_Integer objects cannot have custom attributes, + # so getvalue() returns None. + assert w1.getvalue('abc') is None + + +def test_istrue(): + assert W_Integer(5).istrue() is True + assert W_Integer(0).istrue() is False + assert W_Integer(-1).istrue() is True + # for now, only W_Integer(0) is false; all the other objects are true. + assert W_NormalObject().istrue() is True + + +def test_clone(): + w1 = W_NormalObject() + w1.setvalue('abc', W_Integer(6)) + w2 = w1.clone() + assert w2.getvalue('abc').value == 6 + w2.setvalue('abc', W_Integer(99)) + assert w2.getvalue('abc').value == 99 + assert w1.getvalue('abc').value == 6 # still the old value diff --git a/test/test_parent.py b/test/test_parent.py new file mode 100644 index 0000000..30c1240 --- /dev/null +++ b/test/test_parent.py @@ -0,0 +1,205 @@ +import py + +from simpleparser import parse +from objmodel import W_NormalObject +from interpreter import Interpreter + + +def test_implicit_parent(): + ast = parse(""" +k = 10 +object a: + z = k +az = a z +""") + interpreter = Interpreter() + # make_module creates a new empty W_NormalObject for now + # this will change later + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("a").getvalue('__parent__') is w_module + assert w_module.getvalue("a").getparents() == [w_module] + assert w_module.getvalue("az").value == 10 + + +def test_implicit_parent_method(): + ast = parse(""" +k = 10 +def f(x): + if x: + k + else: + 1 +f1 = f(1) +f0 = f(0) +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("f1").value == 10 + assert w_module.getvalue("f0").value == 1 + + +def test_shadow_parent_attribute(): + ast = parse(""" +k = 10 +def f(x): + if x: + k = 41 + k +f1 = f(1) +f0 = f(0) + +object a: + k = 11 + +ak = a k +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("f1").value == 41 + assert w_module.getvalue("f0").value == 10 + assert w_module.getvalue("ak").value == 11 + assert w_module.getvalue("k").value == 10 + + +def test_capture(): + ast = parse(""" +k = 10 +object a: + j = k +k = 11 +aj = a j +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("aj").value == 10 + + +def test_override__parent__(): + ast = parse(""" +k = 10 +object a: + x = 1 + y = 2 + z = k +object b: + __parent__ = a + y = 5 + z = y + +ax = a x +ay = a y +az = a z +bx = b x +by = b y +bz = b z +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + a = w_module.getvalue("a") + assert a.getvalue('__parent__') is w_module + assert w_module.getvalue("b").getvalue('__parent__') is a + assert w_module.getvalue("b").getparents() == [a] + assert w_module.getvalue("ax").value == 1 + assert w_module.getvalue("ay").value == 2 + assert w_module.getvalue("az").value == 10 + assert w_module.getvalue("bx").value == 1 + assert w_module.getvalue("by").value == 5 + assert w_module.getvalue("bz").value == 5 + + +def test_parent_syntax(): + ast = parse(""" +object a: + x = 11 +object b(parent=a): + x = 22 +af = a x +bf = b x +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + a = w_module.getvalue("a") + b = w_module.getvalue("b") + assert a.getvalue('__parent__') is w_module + assert b.getvalue('__parent__') is w_module + assert b.getvalue('parent') is a + assert a.getparents() == [w_module] + assert b.getparents() == [a, w_module] + assert w_module.getvalue("af").value == 11 + assert w_module.getvalue("bf").value == 22 + + +def test_parent_syntax_multiple(): + ast = parse(""" +a = 1 +b = 2 +c = 3 +d = 4 +object x: + b = 5 + c = 6 + d = 7 +object y: + c = 8 + d = 9 +object z(p1=y, p2=x): + d = 10 +za = z a +zb = z b +zc = z c +zd = z d +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + x = w_module.getvalue("x") + y = w_module.getvalue("y") + z = w_module.getvalue("z") + assert x.getvalue('__parent__') is w_module + assert y.getvalue('__parent__') is w_module + assert z.getvalue('__parent__') is w_module + assert z.getvalue('p1') is y + assert z.getvalue('p2') is x + assert x.getparents() == [w_module] + assert y.getparents() == [w_module] + assert z.getparents() == [y, x, w_module] + assert w_module.getvalue("za").value == 1 + assert w_module.getvalue("zb").value == 5 + assert w_module.getvalue("zc").value == 8 + assert w_module.getvalue("zd").value == 10 + + +def test_wrong_hierarchy_error(): + ast = parse(""" +object base: + x = 1 +object sub(p1=base): + x = 2 +def mayhem: + object bad(p1=base, p2=sub): + x = 3 + bad x +result = mayhem +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + py.test.raises(TypeError, interpreter.eval, ast, w_module) + + +def test_duplicate_base_error(): + ast = parse(""" +object base: + x = 1 +object sub(p1=base, p2=base): + x = 2 +y = sub x +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + py.test.raises(TypeError, interpreter.eval, ast, w_module) diff --git a/test/test_primitive.py b/test/test_primitive.py new file mode 100644 index 0000000..49c2be4 --- /dev/null +++ b/test/test_primitive.py @@ -0,0 +1,42 @@ +import py + +from simpleparser import parse +from objmodel import W_NormalObject +from interpreter import Interpreter + + +def test_primitive(): + ast = parse(""" +k = 10 $int_add(31) +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("k").value == 41 + + +def test_primitive_error(): + ast = parse(""" +k = 10 $int_add(31, 12) +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + with py.test.raises(TypeError): + interpreter.eval(ast, w_module) + + +def test_loop(): + ast = parse(""" +def f(x): + r = 0 + while x: + r = r $int_add(x) + x = x $int_add(-1) + r +y = f(100) +""") + interpreter = Interpreter() + w_module = interpreter.make_module() + interpreter.eval(ast, w_module) + assert w_module.getvalue("y").value == 5050 + diff --git a/test/test_simplelexer.py b/test/test_simplelexer.py new file mode 100644 index 0000000..1e0ae4c --- /dev/null +++ b/test/test_simplelexer.py @@ -0,0 +1,100 @@ +from simplelexer import lex + +# Every insturction ends with an newline +def test_single_quoted_string(): + for s in ["""'abc'""", + """'ab"c'""", + """'ab\\'c'""", + ]: + tokens = lex(s) + token, newline, eof = tokens + assert token.name == 'String' + assert newline.name == 'Newline' + assert eof.name == 'EOF' + +def test_number(): + for s in ["0", + "+1", + "-1", + "-1123123", + ]: + tokens = lex(s) + token, newline, eof = tokens + assert tokens[0].name == 'Number' + assert token.name == 'Number' + assert newline.name == 'Newline' + assert eof.name == 'EOF' + +def test_name(): + for s in ["abc", + "_", + "a_0", + "_0", + ]: + tokens = lex(s) + token, newline, eof = tokens + assert tokens[0].name == 'Name' + assert token.name == 'Name' + assert newline.name == 'Newline' + assert eof.name == 'EOF' + +def test_primitvename(): + for s in ["$abc", + "$_", + "$a_0", + "$_0", + ]: + tokens = lex(s) + token, newline, eof = tokens + assert tokens[0].name == 'PrimitiveName' + assert token.name == 'PrimitiveName' + assert newline.name == 'Newline' + assert eof.name == 'EOF' + +def test_long(): + for s, numtoken in [ + ("if x:\n print x", 10), + ("if x:#foo\n x abc = 7", 12), + ("1 a \\\n 2", 5) + ]: + tokens = lex(s) + assert len(tokens) == numtoken + +def test_indentation(): + s = """a +b + c + d + + #some comment + e + f + """ + tokens = lex(s) + assert [t.name for t in tokens] == ["Name", "Newline", "Name", "Newline", + "Indent", "Name", "Newline", "Indent", + "Name", "Newline", "Dedent", "Name", + "Newline", "Indent", "Name", "Newline", + "Dedent", "Dedent", "EOF"] + +# This is only one line! The \ is used for line continuation +def test_linecont(): + s = "a a \\\n b" + tokens = lex(s) + assert [t.name for t in tokens] == ["Name", "Name", "Name", "Newline", + "EOF"] + +# newline token between brackets are ignored ... +def test_parenthesis(): + s = "(a = \n b)" + tokens = lex(s) + assert [t.name for t in tokens] == ["OpenBracket", "Name", "Assign", "Name", + "CloseBracket", "Newline", "EOF"] + +# ... unless you insert a comment +def test_comment(): + s = "(a = # foo this is a comment \n b)" + tokens = lex(s) + assert [t.name for t in tokens] == ["OpenBracket", "Name", "Assign", "Name", + "CloseBracket", "Newline", "EOF"] + diff --git a/test/test_simpleparser.py b/test/test_simpleparser.py new file mode 100644 index 0000000..43ba5db --- /dev/null +++ b/test/test_simpleparser.py @@ -0,0 +1,149 @@ +import py + +from simpleparser import ParseError, parse +from simplelexer import lex +from simpleast import * + +def raisesparserror(source): + with py.test.raises(ParseError) as excinfo: + parse(source) + print(excinfo.value.nice_error_message()) + + +def test_expression(): + ast = parse("a b c") + ast1 = MethodCall(MethodCall(MethodCall(ImplicitSelf(), "a"), "b"), "c") + assert ast == Program([ExprStatement(ast1)]) + ast = parse("a f(1, a b c, 3,)") + ast2 = Program([ExprStatement(MethodCall(MethodCall(ImplicitSelf(), "a"), "f", [ + IntLiteral(1), ast1, IntLiteral(3)]))]) + assert ast == ast2 + + +def test_expression2(): + ast = parse("$a $b $c") + ast1 = PrimitiveMethodCall(PrimitiveMethodCall( + PrimitiveMethodCall(ImplicitSelf(), "$a"), "$b"), "$c") + assert ast == Program([ExprStatement(ast1)]) + ast = parse("$a $f(1, $a $b $c, 3,)") + assert ast == Program([ExprStatement(PrimitiveMethodCall( + PrimitiveMethodCall(ImplicitSelf(), "$a"), "$f", [ + IntLiteral(1), ast1, IntLiteral(3)]))]) + + +def test_simplestatement(): + ast = parse("a\n") + ast1 = Program([ExprStatement(MethodCall(ImplicitSelf(), "a"))]) + assert ast == ast1 + ast = parse("a = 4 b\n") + ast1 = Program([Assignment(ImplicitSelf(), "a", MethodCall(IntLiteral(4), "b"))]) + assert ast == ast1 + ast = raisesparserror("a(1) = 4 b\n") + ast = raisesparserror("1 = 4 b\n") + +def test_error(): + ast = raisesparserror("a add 2\n") + + + +def test_if(): + ast = parse("""if a and(b): + a b +""") + ast1 = Program([IfStatement(MethodCall(MethodCall(ImplicitSelf(), "a"), "and", + [MethodCall(ImplicitSelf(), "b")]), + Program([ExprStatement( + MethodCall(MethodCall(ImplicitSelf(), "a"), + "b"))]))]) + assert ast1 == ast + + ast = parse("""if a and(b): + a b +else: + b +""") + ast1 = Program([IfStatement(MethodCall(MethodCall(ImplicitSelf(), "a"), "and", + [MethodCall(ImplicitSelf(), "b")]), + Program([ExprStatement( + MethodCall(MethodCall(ImplicitSelf(), "a"), + "b"))]), + Program([ExprStatement( + MethodCall(ImplicitSelf(), "b"))]))]) + assert ast1 == ast + +def test_while(): + ast = parse(""" +while i: + i = i sub(1) +""") + ast1 = Program([WhileStatement(MethodCall(ImplicitSelf(), "i"), + Program([Assignment(ImplicitSelf(), "i", + MethodCall(MethodCall(ImplicitSelf(), "i"), + "sub", + [IntLiteral(1)]))]))]) + assert ast1 == ast + +def test_object(): + ast = parse(""" +object a: + i = 1 + if i: + j = 2 +""") + ast1 = Program([ObjectDefinition("a", Program([ + Assignment(ImplicitSelf(), "i", IntLiteral(1)), + IfStatement(MethodCall(ImplicitSelf(), "i"), Program([ + Assignment(ImplicitSelf(), "j", IntLiteral(2)), + ])) + ]))]) + assert ast1 == ast + + ast = parse(""" +object a(parent=1): + i = 1 + if i: + j = 2 +""") + ast1 = Program([ObjectDefinition("a", Program([ + Assignment(ImplicitSelf(), "i", IntLiteral(1)), + IfStatement(MethodCall(ImplicitSelf(), "i"), Program([ + Assignment(ImplicitSelf(), "j", IntLiteral(2)), + ])) + ]), + ["parent"], + [IntLiteral(1)])]) + assert ast1 == ast + + +def test_def(): + ast = parse(""" +def f(x, y, z): + i = 1 + if i: + j = 2 +""") + ast1 = Program([FunctionDefinition("f", ["x", "y", "z"], Program([ + Assignment(ImplicitSelf(), "i", IntLiteral(1)), + IfStatement(MethodCall(ImplicitSelf(), "i"), Program([ + Assignment(ImplicitSelf(), "j", IntLiteral(2)), + ])) + ]))]) + assert ast1 == ast + + +def test_object2(): + ast = parse(""" +object None: + 1 +""") + ast = parse(""" +def pass: + None +""") + ast = parse(""" +object None: + 1 + +def pass: + None +""")