From 9ecfc0196ff926cb62774903659144b1c0529cbb Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 11 Mar 2025 00:20:56 +0800 Subject: [PATCH] ... ... ... ... ... ... ... ... ... --- .github/workflows/main.yml | 10 +- scripts/run_tests.py | 7 +- src/interpreter/ceval.c | 4 + ...7_builtin_func.py => 77_builtin_func_1.py} | 318 +----------------- tests/77_builtin_func_2.py | 243 +++++++++++++ 5 files changed, 278 insertions(+), 304 deletions(-) rename tests/{77_builtin_func.py => 77_builtin_func_1.py} (51%) create mode 100644 tests/77_builtin_func_2.py diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bac25843..ff1e691d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -92,10 +92,18 @@ jobs: uses: jirutka/setup-alpine@v1 with: arch: x86 - packages: gcc g++ make cmake libc-dev linux-headers python3 + packages: gcc g++ make cmake libc-dev linux-headers python3 gdb - name: Build and Test run: | uname -m + + python cmake_build.py Debug + # gdb_commands.txt + echo "run" > gdb_commands.txt + echo "backtrace" >> gdb_commands.txt + echo "quit" >> gdb_commands.txt + gdb -batch -x gdb_commands.txt --args ./main tests/77_builtin_func_1.py + python cmake_build.py python scripts/run_tests.py python scripts/run_tests.py benchmark diff --git a/scripts/run_tests.py b/scripts/run_tests.py index 83f323de..9232c7e7 100644 --- a/scripts/run_tests.py +++ b/scripts/run_tests.py @@ -8,9 +8,12 @@ def test_file(filepath, cpython=False): if cpython: return os.system("python " + filepath) == 0 if sys.platform == 'win32': - return os.system("main.exe " + filepath) == 0 + code = os.system("main.exe " + filepath) else: - return os.system("./main " + filepath) == 0 + code = os.system("./main " + filepath) + if code != 0: + print('Return code:', code) + return code == 0 def test_dir(path): print("Testing directory:", path) diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 56a67518..5b42f3b3 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -90,6 +90,10 @@ FrameResult VM__run_top_frame(VM* self) { py_exception(tp_RecursionError, "maximum recursion depth exceeded"); goto __ERROR; } + if(self->stack.sp >= self->stack.end) { + c11__abort( + "Stack overflow! Please increase PK_VM_STACK_SIZE or reduce the max recursion limit."); + } codes = frame->co->codes.data; frame->ip++; diff --git a/tests/77_builtin_func.py b/tests/77_builtin_func_1.py similarity index 51% rename from tests/77_builtin_func.py rename to tests/77_builtin_func_1.py index 49abed1a..cf7c4ba3 100644 --- a/tests/77_builtin_func.py +++ b/tests/77_builtin_func_1.py @@ -57,14 +57,14 @@ class TestSuperNoBaseMethod(TestSuperBase): try: t = TestSuperNoParent() print('未能拦截错误') - exit(1) + exit(2) except: pass try: t = TestSuperNoBaseMethod() print('未能拦截错误') - exit(1) + exit(3) except: pass @@ -83,7 +83,7 @@ try: c = C() c.method() print('未能拦截错误') - exit(1) + exit(4) except: pass @@ -91,7 +91,7 @@ try: d = D() d.method() print('未能拦截错误') - exit(1) + exit(5) except: pass @@ -134,14 +134,14 @@ assert type(hash(a)) is int try: hash({1:1}) print('未能拦截错误') - exit(1) + exit(6) except: pass try: hash([1]) print('未能拦截错误') - exit(1) + exit(7) except: pass @@ -166,7 +166,7 @@ repr(A()) try: range(1,2,3,4) print('未能拦截错误, 在测试 range') - exit(1) + exit(8) except: pass @@ -174,14 +174,14 @@ except: try: int('asad') print('未能拦截错误, 在测试 int') - exit(1) + exit(9) except: pass try: int(123, 16) print('未能拦截错误, 在测试 int') - exit(1) + exit(10) except: pass @@ -192,14 +192,14 @@ assert type(11%2) is int try: float('asad') print('未能拦截错误, 在测试 float') - exit(1) + exit(11) except: pass try: float([]) print('未能拦截错误, 在测试 float') - exit(1) + exit(12) except: pass @@ -213,7 +213,7 @@ assert type('25363546'.index('63')) is int try: '25363546'.index('err') print('未能拦截错误, 在测试 str.index') - exit(1) + exit(13) except: pass @@ -228,7 +228,7 @@ assert '25363546'.find('err') == -1 try: list(1,2) print('未能拦截错误, 在测试 list') - exit(1) + exit(14) except: pass @@ -238,7 +238,7 @@ assert type([1,2,3,4,5].index(4)) is int try: [1,2,3,4,5].index(6) print('未能拦截错误, 在测试 list.index') - exit(1) + exit(15) except: pass @@ -249,7 +249,7 @@ except: try: [1,2,3,4,5].remove(6) print('未能拦截错误, 在测试 list.remove') - exit(1) + exit(16) except: pass @@ -259,7 +259,7 @@ except: try: [1,2,3,4,5].pop(1,2,3,4) print('未能拦截错误, 在测试 list.pop') - exit(1) + exit(17) except: pass @@ -275,7 +275,7 @@ assert type(12 * [12]) is list try: tuple(1,2) print('未能拦截错误, 在测试 tuple') - exit(1) + exit(18) except: pass @@ -305,287 +305,3 @@ assert type(repr(bytes([0x41, 0x42, 0x43]))) is str # /************ slice ************/ assert type(slice(0.1, 0.2, 0.3)) is slice - - -# 未完全测试准确性----------------------------------------------- -# 116: 1529: bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args){ -# #####: 1530: return CAST(Slice&, args[0]).start; -# -: 1531: }); -# 116: 1532: bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args){ -# #####: 1533: return CAST(Slice&, args[0]).stop; -# -: 1534: }); -# 116: 1535: bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args){ -# #####: 1536: return CAST(Slice&, args[0]).step; -# -: 1537: }); -s = slice(1, 2, 3) -assert type(s) is slice -assert s.start == 1 -assert s.stop == 2 -assert s.step == 3 - -# 未完全测试准确性----------------------------------------------- -# test slice.__repr__ -assert type(repr(slice(1,1,1))) is str - -# /************ namedict ************/ -# # test namedict.keys: -# class A(): -# def __init__(self): -# self.a = 10 -# def method(self): -# pass - - -# my_namedict = A().__dict__ -# assert type(my_namedict.keys()) is list - -# # test namedict.values: -# class A(): -# def __init__(self): -# self.a = 10 -# def method(self): -# pass - - -# my_namedict = A().__dict__ -# assert type(my_namedict.values()) is list - - -# class A(): -# def __init__(self): -# self.a = 10 -# def method(self): -# pass - - -# my_namedict = A().__dict__ -# assert type(len(my_namedict)) is int - - -class A(): - def __init__(self): - self.a = 10 - def method(self): - pass - - -my_namedict = A().__dict__ - -try: - hash(my_namedict) - print('未能拦截错误, 在测试 namedict.__hash__') - exit(1) -except TypeError: - pass - -a = hash(object()) # object is hashable -a = hash(A()) # A is hashable -class B: - def __eq__(self, o): return True - def __ne__(self, o): return False - -try: - hash(B()) - print('未能拦截错误, 在测试 B.__hash__') - exit(1) -except TypeError: - pass - -# 未完全测试准确性----------------------------------------------- -# test namedict.__repr__: -class A(): - def __init__(self): - self.a = 10 - def method(self): - pass - - -my_namedict = A().__dict__ -assert type(repr(my_namedict)) is str - - -# /************ dict ************/ -# 未完全测试准确性----------------------------------------------- -# test dict: -assert type(dict([(1,2)])) is dict - -try: - dict([(1, 2, 3)]) - print('未能拦截错误, 在测试 dict') - exit(1) -except: - pass - -try: - dict([(1, 2)], 1) - print('未能拦截错误, 在测试 dict') - exit(1) -except: - pass - -try: - hash(dict([(1,2)])) - print('未能拦截错误, 在测试 dict.__hash__') - exit(1) -except: - pass - -# test dict.__iter__ -for k in {1:2, 2:3, 3:4}.keys(): - assert k in [1,2,3] - -# 未完全测试准确性----------------------------------------------- -# test dict.get - -assert {1:2, 3:4}.get(1) == 2 -assert {1:2, 3:4}.get(2) is None -assert {1:2, 3:4}.get(20, 100) == 100 - -try: - {1:2, 3:4}.get(1,1, 1) - print('未能拦截错误, 在测试 dict.get') - exit(1) -except: - pass - -# 未完全测试准确性----------------------------------------------- -# test dict.__repr__ -assert type(repr({1:2, 3:4})) is str - -# /************ property ************/ -class A(): - def __init__(self): - self._name = '123' - - @property - def value(self): - return 2 - - def get_name(self): - ''' - doc string 1 - ''' - return self._name - - def set_name(self, val): - ''' - doc string 2 - ''' - self._name = val - -assert A().value == 2 - -A.name = property(A.get_name, A.set_name) - -class Vector2: - def __init__(self) -> None: - self._x = 0 - - @property - def x(self): - return self._x - - @x.setter - def x(self, val): - self._x = val - -v = Vector2() -assert v.x == 0 -v.x = 10 -assert v.x == 10 - -# function.__doc__ -def aaa(): - '12345' - pass -assert aaa.__doc__ == '12345' - -# test callable -assert callable(lambda: 1) is True # function -assert callable(1) is False # int -assert callable(object) is True # type -assert callable(object()) is False -assert callable([].append) is True # bound method -assert callable([].__getitem__) is True # bound method - -class A: - def __init__(self): - pass - - def __call__(self): - pass - -assert callable(A) is True # type -assert callable(A()) is True # instance with __call__ -assert callable(A.__call__) is True # bound method -assert callable(A.__init__) is True # bound method -assert callable(print) is True # builtin function -assert callable(isinstance) is True # builtin function - - -assert id(0) is None -assert id(2**62) is None - -# test issubclass -assert issubclass(int, int) is True -assert issubclass(int, object) is True -assert issubclass(object, int) is False -assert issubclass(object, object) is True -assert issubclass(int, type) is False -assert issubclass(type, type) is True -assert issubclass(float, int) is False - - -def f(a, b): - c = a - del a - return sum([b, c]) - -assert f(1, 2) == 3 - -# /************ module time ************/ -import time -# test time.time -assert type(time.time()) is float - -local_t = time.localtime() -assert type(local_t.tm_year) is int -assert type(local_t.tm_mon) is int -assert type(local_t.tm_mday) is int -assert type(local_t.tm_hour) is int -assert type(local_t.tm_min) is int -assert type(local_t.tm_sec) is int -assert type(local_t.tm_wday) is int -assert type(local_t.tm_yday) is int -assert type(local_t.tm_isdst) is int - -# test time.sleep -time.sleep(0.1) -# test time.localtime -assert type(time.localtime()) is time.struct_time - -# test min/max -assert min(1, 2) == 1 -assert min(1, 2, 3) == 1 -assert min([1, 2]) == 1 -assert min([1, 2], key=lambda x: -x) == 2 - -assert max(1, 2) == 2 -assert max(1, 2, 3) == 3 -assert max([1, 2]) == 2 -assert max([1, 2, 3], key=lambda x: -x) == 1 - -assert min([ - (3, 1), - (1, 2), - (1, 3), - (1, 4), -]) == (1, 2) - -assert min(1, 2) == 1 -assert max(1, 2) == 2 - -exit() - -dir_int = dir(int) -assert dir_int[:4] == ['__add__', '__and__', '__base__', '__eq__'] \ No newline at end of file diff --git a/tests/77_builtin_func_2.py b/tests/77_builtin_func_2.py new file mode 100644 index 00000000..46b28a0f --- /dev/null +++ b/tests/77_builtin_func_2.py @@ -0,0 +1,243 @@ +# 未完全测试准确性----------------------------------------------- +# 116: 1529: bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args){ +# #####: 1530: return CAST(Slice&, args[0]).start; +# -: 1531: }); +# 116: 1532: bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args){ +# #####: 1533: return CAST(Slice&, args[0]).stop; +# -: 1534: }); +# 116: 1535: bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args){ +# #####: 1536: return CAST(Slice&, args[0]).step; +# -: 1537: }); +s = slice(1, 2, 3) +assert type(s) is slice +assert s.start == 1 +assert s.stop == 2 +assert s.step == 3 + +# 未完全测试准确性----------------------------------------------- +# test slice.__repr__ +assert type(repr(slice(1,1,1))) is str + + +class A(): + def __init__(self): + self.a = 10 + def method(self): + pass + + +my_namedict = A().__dict__ + +try: + hash(my_namedict) + print('未能拦截错误, 在测试 namedict.__hash__') + exit(1) +except TypeError: + pass + +a = hash(object()) # object is hashable +a = hash(A()) # A is hashable +class B: + def __eq__(self, o): return True + def __ne__(self, o): return False + +try: + hash(B()) + print('未能拦截错误, 在测试 B.__hash__') + exit(1) +except TypeError: + pass + +# 未完全测试准确性----------------------------------------------- +# test namedict.__repr__: +class A(): + def __init__(self): + self.a = 10 + def method(self): + pass + + +my_namedict = A().__dict__ +assert type(repr(my_namedict)) is str + + +# /************ dict ************/ +# 未完全测试准确性----------------------------------------------- +# test dict: +assert type(dict([(1,2)])) is dict + +try: + dict([(1, 2, 3)]) + print('未能拦截错误, 在测试 dict') + exit(1) +except: + pass + +try: + dict([(1, 2)], 1) + print('未能拦截错误, 在测试 dict') + exit(1) +except: + pass + +try: + hash(dict([(1,2)])) + print('未能拦截错误, 在测试 dict.__hash__') + exit(1) +except: + pass + +# test dict.__iter__ +for k in {1:2, 2:3, 3:4}.keys(): + assert k in [1,2,3] + +# 未完全测试准确性----------------------------------------------- +# test dict.get + +assert {1:2, 3:4}.get(1) == 2 +assert {1:2, 3:4}.get(2) is None +assert {1:2, 3:4}.get(20, 100) == 100 + +try: + {1:2, 3:4}.get(1,1, 1) + print('未能拦截错误, 在测试 dict.get') + exit(1) +except: + pass + +# 未完全测试准确性----------------------------------------------- +# test dict.__repr__ +assert type(repr({1:2, 3:4})) is str + +# /************ property ************/ +class A(): + def __init__(self): + self._name = '123' + + @property + def value(self): + return 2 + + def get_name(self): + ''' + doc string 1 + ''' + return self._name + + def set_name(self, val): + ''' + doc string 2 + ''' + self._name = val + +assert A().value == 2 + +A.name = property(A.get_name, A.set_name) + +class Vector2: + def __init__(self) -> None: + self._x = 0 + + @property + def x(self): + return self._x + + @x.setter + def x(self, val): + self._x = val + +v = Vector2() +assert v.x == 0 +v.x = 10 +assert v.x == 10 + +# function.__doc__ +def aaa(): + '12345' + pass +assert aaa.__doc__ == '12345' + +# test callable +assert callable(lambda: 1) is True # function +assert callable(1) is False # int +assert callable(object) is True # type +assert callable(object()) is False +assert callable([].append) is True # bound method +assert callable([].__getitem__) is True # bound method + +class A: + def __init__(self): + pass + + def __call__(self): + pass + +assert callable(A) is True # type +assert callable(A()) is True # instance with __call__ +assert callable(A.__call__) is True # bound method +assert callable(A.__init__) is True # bound method +assert callable(print) is True # builtin function +assert callable(isinstance) is True # builtin function + + +assert id(0) is None +assert id(2**62) is None + +# test issubclass +assert issubclass(int, int) is True +assert issubclass(int, object) is True +assert issubclass(object, int) is False +assert issubclass(object, object) is True +assert issubclass(int, type) is False +assert issubclass(type, type) is True +assert issubclass(float, int) is False + + +def f(a, b): + c = a + del a + return sum([b, c]) + +assert f(1, 2) == 3 + +# /************ module time ************/ +import time +# test time.time +assert type(time.time()) is float + +local_t = time.localtime() +assert type(local_t.tm_year) is int +assert type(local_t.tm_mon) is int +assert type(local_t.tm_mday) is int +assert type(local_t.tm_hour) is int +assert type(local_t.tm_min) is int +assert type(local_t.tm_sec) is int +assert type(local_t.tm_wday) is int +assert type(local_t.tm_yday) is int +assert type(local_t.tm_isdst) is int + +# test time.sleep +time.sleep(0.1) +# test time.localtime +assert type(time.localtime()) is time.struct_time + +# test min/max +assert min(1, 2) == 1 +assert min(1, 2, 3) == 1 +assert min([1, 2]) == 1 +assert min([1, 2], key=lambda x: -x) == 2 + +assert max(1, 2) == 2 +assert max(1, 2, 3) == 3 +assert max([1, 2]) == 2 +assert max([1, 2, 3], key=lambda x: -x) == 1 + +assert min([ + (3, 1), + (1, 2), + (1, 3), + (1, 4), +]) == (1, 2) + +assert min(1, 2) == 1 +assert max(1, 2) == 2