vorgabe tests
This commit is contained in:
86
test/test_builtin.py
Normal file
86
test/test_builtin.py
Normal file
@ -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
|
206
test/test_bytecode.py
Normal file
206
test/test_bytecode.py
Normal file
@ -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
|
123
test/test_interpreter.py
Normal file
123
test/test_interpreter.py
Normal file
@ -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
|
82
test/test_method.py
Normal file
82
test/test_method.py
Normal file
@ -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
|
38
test/test_objmodel.py
Normal file
38
test/test_objmodel.py
Normal file
@ -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
|
205
test/test_parent.py
Normal file
205
test/test_parent.py
Normal file
@ -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)
|
42
test/test_primitive.py
Normal file
42
test/test_primitive.py
Normal file
@ -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
|
||||||
|
|
100
test/test_simplelexer.py
Normal file
100
test/test_simplelexer.py
Normal file
@ -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"]
|
||||||
|
|
149
test/test_simpleparser.py
Normal file
149
test/test_simpleparser.py
Normal file
@ -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
|
||||||
|
""")
|
Reference in New Issue
Block a user