From a333cc854f6937c885c8946417b6c4ae5603668d Mon Sep 17 00:00:00 2001 From: pikastech Date: Mon, 1 May 2023 21:48:33 +0800 Subject: [PATCH] support max(), min() builtin --- package/PikaStdLib/PikaStdData_Tuple.c | 3 + package/PikaStdLib/PikaStdLib.pyi | 8 ++ package/PikaStdLib/PikaStdLib_SysObj.c | 88 +++++++++++++++++++ port/linux/.vscode/launch.json | 2 +- port/linux/package/pikascript/PikaStdLib.pyi | 8 ++ .../PikaStdLib/PikaStdData_Tuple.c | 3 + .../PikaStdLib/PikaStdLib_SysObj.c | 88 +++++++++++++++++++ src/PikaObj.c | 1 + test/builtin-test.cpp | 2 + test/compile-test.cpp | 22 ++++- test/python/builtin/max_min.py | 13 +++ 11 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 test/python/builtin/max_min.py diff --git a/package/PikaStdLib/PikaStdData_Tuple.c b/package/PikaStdLib/PikaStdData_Tuple.c index 77c2e2070..f7b6a5c32 100644 --- a/package/PikaStdLib/PikaStdData_Tuple.c +++ b/package/PikaStdLib/PikaStdData_Tuple.c @@ -43,6 +43,9 @@ Arg* PikaStdData_Tuple___getitem__(PikaObj* self, Arg* __key) { } void PikaStdData_Tuple___del__(PikaObj* self) { + if (0 == obj_getInt(self, "needfree")) { + return; + } Args* list = obj_getPtr(self, "list"); args_deinit(list); } diff --git a/package/PikaStdLib/PikaStdLib.pyi b/package/PikaStdLib/PikaStdLib.pyi index 9ad0b1e87..31eccdd29 100644 --- a/package/PikaStdLib/PikaStdLib.pyi +++ b/package/PikaStdLib/PikaStdLib.pyi @@ -126,6 +126,14 @@ class SysObj: @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") def abs(val: any) -> any: ... + @staticmethod + @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") + def max(*val) -> any: ... + + @staticmethod + @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") + def min(*val) -> any: ... + @staticmethod @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") def help(name: str): ... diff --git a/package/PikaStdLib/PikaStdLib_SysObj.c b/package/PikaStdLib/PikaStdLib_SysObj.c index 72ddadf64..acae67a01 100644 --- a/package/PikaStdLib/PikaStdLib_SysObj.c +++ b/package/PikaStdLib/PikaStdLib_SysObj.c @@ -707,3 +707,91 @@ Arg* PikaStdLib_SysObj_abs(PikaObj* self, Arg* val) { obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM); return NULL; } + +PikaObj* New_PikaStdData_Tuple(Args* args); +/* clang-format off */ +PIKA_PYTHON( +@res_max = @list[0] +for @item in @list: + if @item > @res_max: + @res_max = @item +) +/* clang-format on */ +const uint8_t bc_max[] = { + 0x4c, 0x00, 0x00, 0x00, /* instruct array size */ + 0x10, 0x81, 0x01, 0x00, 0x10, 0x05, 0x07, 0x00, 0x00, 0x1d, 0x00, 0x00, + 0x00, 0x04, 0x09, 0x00, 0x10, 0x81, 0x01, 0x00, 0x00, 0x02, 0x12, 0x00, + 0x00, 0x04, 0x17, 0x00, 0x00, 0x82, 0x1b, 0x00, 0x00, 0x04, 0x28, 0x00, + 0x00, 0x0d, 0x28, 0x00, 0x00, 0x07, 0x2e, 0x00, 0x11, 0x81, 0x28, 0x00, + 0x11, 0x01, 0x09, 0x00, 0x01, 0x08, 0x30, 0x00, 0x01, 0x07, 0x32, 0x00, + 0x02, 0x81, 0x28, 0x00, 0x02, 0x04, 0x09, 0x00, 0x00, 0x86, 0x34, 0x00, + 0x00, 0x8c, 0x17, 0x00, /* instruct array */ + 0x37, 0x00, 0x00, 0x00, /* const pool size */ + 0x00, 0x40, 0x6c, 0x69, 0x73, 0x74, 0x00, 0x30, 0x00, 0x40, 0x72, 0x65, + 0x73, 0x5f, 0x6d, 0x61, 0x78, 0x00, 0x69, 0x74, 0x65, 0x72, 0x00, 0x24, + 0x6c, 0x30, 0x00, 0x24, 0x6c, 0x30, 0x2e, 0x5f, 0x5f, 0x6e, 0x65, 0x78, + 0x74, 0x5f, 0x5f, 0x00, 0x40, 0x69, 0x74, 0x65, 0x6d, 0x00, 0x32, 0x00, + 0x3e, 0x00, 0x31, 0x00, 0x2d, 0x31, 0x00, /* const pool */ +}; + +/* clang-format off */ +PIKA_PYTHON( +@res_max = @list[0] +for @item in @list: + if @item < @res_max: + @res_max = @item + +) +/* clang-format on */ +const uint8_t bc_min[] = { + 0x4c, 0x00, 0x00, 0x00, /* instruct array size */ + 0x10, 0x81, 0x01, 0x00, 0x10, 0x05, 0x07, 0x00, 0x00, 0x1d, 0x00, 0x00, + 0x00, 0x04, 0x09, 0x00, 0x10, 0x81, 0x01, 0x00, 0x00, 0x02, 0x12, 0x00, + 0x00, 0x04, 0x17, 0x00, 0x00, 0x82, 0x1b, 0x00, 0x00, 0x04, 0x28, 0x00, + 0x00, 0x0d, 0x28, 0x00, 0x00, 0x07, 0x2e, 0x00, 0x11, 0x81, 0x28, 0x00, + 0x11, 0x01, 0x09, 0x00, 0x01, 0x08, 0x30, 0x00, 0x01, 0x07, 0x32, 0x00, + 0x02, 0x81, 0x28, 0x00, 0x02, 0x04, 0x09, 0x00, 0x00, 0x86, 0x34, 0x00, + 0x00, 0x8c, 0x17, 0x00, /* instruct array */ + 0x37, 0x00, 0x00, 0x00, /* const pool size */ + 0x00, 0x40, 0x6c, 0x69, 0x73, 0x74, 0x00, 0x30, 0x00, 0x40, 0x72, 0x65, + 0x73, 0x5f, 0x6d, 0x61, 0x78, 0x00, 0x69, 0x74, 0x65, 0x72, 0x00, 0x24, + 0x6c, 0x30, 0x00, 0x24, 0x6c, 0x30, 0x2e, 0x5f, 0x5f, 0x6e, 0x65, 0x78, + 0x74, 0x5f, 0x5f, 0x00, 0x40, 0x69, 0x74, 0x65, 0x6d, 0x00, 0x32, 0x00, + 0x3c, 0x00, 0x31, 0x00, 0x2d, 0x31, 0x00, /* const pool */ +}; + +Arg* _max_min(PikaObj* self, PikaTuple* val, uint8_t* bc) { + int size = pikaTuple_getSize(val); + if (size == 0) { + obj_setSysOut(self, "TypeError: max expected 1 arguments, got 0"); + obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM); + return NULL; + } + if (size == 1) { + ArgType type = arg_getType(pikaTuple_getArg(val, 0)); + if ((!argType_isObject(type) && (type != ARG_TYPE_STRING) && + (type != ARG_TYPE_BYTES))) { + obj_setSysOut(self, "TypeError: object is not iterable"); + obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM); + return NULL; + } + obj_setArg(self, "@list", pikaTuple_getArg(val, 0)); + return pikaVM_runByteCodeReturn(self, (uint8_t*)bc, "@res_max"); + } + PikaObj* oTuple = newNormalObj(New_PikaStdData_Tuple); + obj_setPtr(oTuple, "list", val); + obj_setInt(oTuple, "needfree", 0); + Arg* aTuple = arg_newObj(oTuple); + obj_setArg(self, "@list", aTuple); + Arg* aRet = pikaVM_runByteCodeReturn(self, (uint8_t*)bc, "@res_max"); + arg_deinit(aTuple); + return aRet; +} + +Arg* PikaStdLib_SysObj_max(PikaObj* self, PikaTuple* val) { + return _max_min(self, val, (uint8_t*)bc_max); +} + +Arg* PikaStdLib_SysObj_min(PikaObj* self, PikaTuple* val) { + return _max_min(self, val, (uint8_t*)bc_min); +} diff --git a/port/linux/.vscode/launch.json b/port/linux/.vscode/launch.json index 7bdf4ec36..45ea0c4b3 100644 --- a/port/linux/.vscode/launch.json +++ b/port/linux/.vscode/launch.json @@ -20,7 +20,7 @@ // "--gtest_filter=eventloop.test1" // "--gtest_filter=parser.tuple_single" // "--gtest_filter=parser.*" - "--gtest_filter=pikaMain.REPL_key_down_over" + "--gtest_filter=builtin.max_min" ], "stopAtEntry": false, "cwd": "${workspaceFolder}", diff --git a/port/linux/package/pikascript/PikaStdLib.pyi b/port/linux/package/pikascript/PikaStdLib.pyi index 9ad0b1e87..31eccdd29 100644 --- a/port/linux/package/pikascript/PikaStdLib.pyi +++ b/port/linux/package/pikascript/PikaStdLib.pyi @@ -126,6 +126,14 @@ class SysObj: @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") def abs(val: any) -> any: ... + @staticmethod + @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") + def max(*val) -> any: ... + + @staticmethod + @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") + def min(*val) -> any: ... + @staticmethod @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") def help(name: str): ... diff --git a/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdData_Tuple.c b/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdData_Tuple.c index 77c2e2070..f7b6a5c32 100644 --- a/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdData_Tuple.c +++ b/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdData_Tuple.c @@ -43,6 +43,9 @@ Arg* PikaStdData_Tuple___getitem__(PikaObj* self, Arg* __key) { } void PikaStdData_Tuple___del__(PikaObj* self) { + if (0 == obj_getInt(self, "needfree")) { + return; + } Args* list = obj_getPtr(self, "list"); args_deinit(list); } diff --git a/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdLib_SysObj.c b/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdLib_SysObj.c index 72ddadf64..acae67a01 100644 --- a/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdLib_SysObj.c +++ b/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdLib_SysObj.c @@ -707,3 +707,91 @@ Arg* PikaStdLib_SysObj_abs(PikaObj* self, Arg* val) { obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM); return NULL; } + +PikaObj* New_PikaStdData_Tuple(Args* args); +/* clang-format off */ +PIKA_PYTHON( +@res_max = @list[0] +for @item in @list: + if @item > @res_max: + @res_max = @item +) +/* clang-format on */ +const uint8_t bc_max[] = { + 0x4c, 0x00, 0x00, 0x00, /* instruct array size */ + 0x10, 0x81, 0x01, 0x00, 0x10, 0x05, 0x07, 0x00, 0x00, 0x1d, 0x00, 0x00, + 0x00, 0x04, 0x09, 0x00, 0x10, 0x81, 0x01, 0x00, 0x00, 0x02, 0x12, 0x00, + 0x00, 0x04, 0x17, 0x00, 0x00, 0x82, 0x1b, 0x00, 0x00, 0x04, 0x28, 0x00, + 0x00, 0x0d, 0x28, 0x00, 0x00, 0x07, 0x2e, 0x00, 0x11, 0x81, 0x28, 0x00, + 0x11, 0x01, 0x09, 0x00, 0x01, 0x08, 0x30, 0x00, 0x01, 0x07, 0x32, 0x00, + 0x02, 0x81, 0x28, 0x00, 0x02, 0x04, 0x09, 0x00, 0x00, 0x86, 0x34, 0x00, + 0x00, 0x8c, 0x17, 0x00, /* instruct array */ + 0x37, 0x00, 0x00, 0x00, /* const pool size */ + 0x00, 0x40, 0x6c, 0x69, 0x73, 0x74, 0x00, 0x30, 0x00, 0x40, 0x72, 0x65, + 0x73, 0x5f, 0x6d, 0x61, 0x78, 0x00, 0x69, 0x74, 0x65, 0x72, 0x00, 0x24, + 0x6c, 0x30, 0x00, 0x24, 0x6c, 0x30, 0x2e, 0x5f, 0x5f, 0x6e, 0x65, 0x78, + 0x74, 0x5f, 0x5f, 0x00, 0x40, 0x69, 0x74, 0x65, 0x6d, 0x00, 0x32, 0x00, + 0x3e, 0x00, 0x31, 0x00, 0x2d, 0x31, 0x00, /* const pool */ +}; + +/* clang-format off */ +PIKA_PYTHON( +@res_max = @list[0] +for @item in @list: + if @item < @res_max: + @res_max = @item + +) +/* clang-format on */ +const uint8_t bc_min[] = { + 0x4c, 0x00, 0x00, 0x00, /* instruct array size */ + 0x10, 0x81, 0x01, 0x00, 0x10, 0x05, 0x07, 0x00, 0x00, 0x1d, 0x00, 0x00, + 0x00, 0x04, 0x09, 0x00, 0x10, 0x81, 0x01, 0x00, 0x00, 0x02, 0x12, 0x00, + 0x00, 0x04, 0x17, 0x00, 0x00, 0x82, 0x1b, 0x00, 0x00, 0x04, 0x28, 0x00, + 0x00, 0x0d, 0x28, 0x00, 0x00, 0x07, 0x2e, 0x00, 0x11, 0x81, 0x28, 0x00, + 0x11, 0x01, 0x09, 0x00, 0x01, 0x08, 0x30, 0x00, 0x01, 0x07, 0x32, 0x00, + 0x02, 0x81, 0x28, 0x00, 0x02, 0x04, 0x09, 0x00, 0x00, 0x86, 0x34, 0x00, + 0x00, 0x8c, 0x17, 0x00, /* instruct array */ + 0x37, 0x00, 0x00, 0x00, /* const pool size */ + 0x00, 0x40, 0x6c, 0x69, 0x73, 0x74, 0x00, 0x30, 0x00, 0x40, 0x72, 0x65, + 0x73, 0x5f, 0x6d, 0x61, 0x78, 0x00, 0x69, 0x74, 0x65, 0x72, 0x00, 0x24, + 0x6c, 0x30, 0x00, 0x24, 0x6c, 0x30, 0x2e, 0x5f, 0x5f, 0x6e, 0x65, 0x78, + 0x74, 0x5f, 0x5f, 0x00, 0x40, 0x69, 0x74, 0x65, 0x6d, 0x00, 0x32, 0x00, + 0x3c, 0x00, 0x31, 0x00, 0x2d, 0x31, 0x00, /* const pool */ +}; + +Arg* _max_min(PikaObj* self, PikaTuple* val, uint8_t* bc) { + int size = pikaTuple_getSize(val); + if (size == 0) { + obj_setSysOut(self, "TypeError: max expected 1 arguments, got 0"); + obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM); + return NULL; + } + if (size == 1) { + ArgType type = arg_getType(pikaTuple_getArg(val, 0)); + if ((!argType_isObject(type) && (type != ARG_TYPE_STRING) && + (type != ARG_TYPE_BYTES))) { + obj_setSysOut(self, "TypeError: object is not iterable"); + obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM); + return NULL; + } + obj_setArg(self, "@list", pikaTuple_getArg(val, 0)); + return pikaVM_runByteCodeReturn(self, (uint8_t*)bc, "@res_max"); + } + PikaObj* oTuple = newNormalObj(New_PikaStdData_Tuple); + obj_setPtr(oTuple, "list", val); + obj_setInt(oTuple, "needfree", 0); + Arg* aTuple = arg_newObj(oTuple); + obj_setArg(self, "@list", aTuple); + Arg* aRet = pikaVM_runByteCodeReturn(self, (uint8_t*)bc, "@res_max"); + arg_deinit(aTuple); + return aRet; +} + +Arg* PikaStdLib_SysObj_max(PikaObj* self, PikaTuple* val) { + return _max_min(self, val, (uint8_t*)bc_max); +} + +Arg* PikaStdLib_SysObj_min(PikaObj* self, PikaTuple* val) { + return _max_min(self, val, (uint8_t*)bc_min); +} diff --git a/src/PikaObj.c b/src/PikaObj.c index 333f699df..30f3055b8 100644 --- a/src/PikaObj.c +++ b/src/PikaObj.c @@ -1344,6 +1344,7 @@ ShellHistory* shHistory_create(int max_size) { self->current = -1; self->count = 0; self->last_offset = 0; + self->cached_current = 0; self->history = (char**)pikaMalloc(max_size * sizeof(char*)); return self; } diff --git a/test/builtin-test.cpp b/test/builtin-test.cpp index 19ab2957b..712aa2d0f 100644 --- a/test/builtin-test.cpp +++ b/test/builtin-test.cpp @@ -200,6 +200,8 @@ TEST_RUN_SINGLE_FILE_PASS(builtin, fn_default_tuple, "test/python/builtin/fn_default_tuple.py") +TEST_RUN_SINGLE_FILE_PASS(builtin, max_min, "test/python/builtin/max_min.py") + #endif TEST_END \ No newline at end of file diff --git a/test/compile-test.cpp b/test/compile-test.cpp index e40320625..277c505b8 100644 --- a/test/compile-test.cpp +++ b/test/compile-test.cpp @@ -755,11 +755,29 @@ TEST(compiler, str_join) { } TEST(compiler, thread_void_arg) { - char* lines = - "thread()"; + char* lines = "thread()"; pika_lines2Array(lines); EXPECT_EQ(pikaMemNow(), 0); } +TEST(compiler, max) { + char* lines = + "@res_max = @list[0]\n" + "for @item in @list:\n" + " if @item > @res_max:\n" + " @res_max = @item\n"; + pika_lines2Array(lines); + EXPECT_EQ(pikaMemNow(), 0); +} + +TEST(compiler, min) { + char* lines = + "@res_max = @list[0]\n" + "for @item in @list:\n" + " if @item < @res_max:\n" + " @res_max = @item\n"; + pika_lines2Array(lines); + EXPECT_EQ(pikaMemNow(), 0); +} TEST_END \ No newline at end of file diff --git a/test/python/builtin/max_min.py b/test/python/builtin/max_min.py new file mode 100644 index 000000000..7b2b2d6dc --- /dev/null +++ b/test/python/builtin/max_min.py @@ -0,0 +1,13 @@ +# 测试 max() 函数 +assert max(1, 2, 3) == 3, "max() 函数错误: max(1, 2, 3) 应返回 3" +assert max(-1, -2, -3) == -1, "max() 函数错误: max(-1, -2, -3) 应返回 -1" +assert max(5, 5) == 5, "max() 函数错误: max(5, 5) 应返回 5" +assert max([1, 2, 3, 4]) == 4, "max() 函数错误: max([1, 2, 3, 4]) 应返回 4" + +# 测试 min() 函数 +assert min(1, 2, 3) == 1, "min() 函数错误: min(1, 2, 3) 应返回 1" +assert min(-1, -2, -3) == -3, "min() 函数错误: min(-1, -2, -3) 应返回 -3" +assert min(5, 5) == 5, "min() 函数错误: min(5, 5) 应返回 5" +assert min([1, 2, 3, 4]) == 1, "min() 函数错误: min([1, 2, 3, 4]) 应返回 1" + +print('PASS')