diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index dcb5542f..c76fecab 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -111,6 +111,21 @@ PK_EXPORT bool py_exec(const char* source, /// Evaluate a source string. Equivalent to `py_exec(source, "", EVAL_MODE, module)`. PK_EXPORT bool py_eval(const char* source, py_Ref module) PY_RAISE PY_RETURN; +/// Run a source string with smart interpretation. +/// Example: +/// `py_newstr(py_r0(), "abc");` +/// `py_newint(py_r1(), 123);` +/// `py_smartexec("print(_1, _2)", NULL, py_r0(), py_r1());` +/// `// "abc 123" will be printed`. +PK_EXPORT bool py_smartexec(const char* source, py_Ref module, ...) PY_RAISE PY_RETURN; +/// Evaluate a source string with smart interpretation. +/// Example: +/// `py_newstr(py_r0(), "abc");` +/// `py_smarteval("len(_1)", NULL, py_r0());` +/// `int res = py_toint(py_retval());` +/// `// res will be 3`. +PK_EXPORT bool py_smarteval(const char* source, py_Ref module, ...) PY_RAISE PY_RETURN; + /// Compile a source string into a code object. /// Use python's `exec()` or `eval()` to execute it. PK_EXPORT bool py_compile(const char* source, @@ -286,6 +301,15 @@ PK_EXPORT py_GlobalRef py_getreg(int i); /// Set the i-th register. PK_EXPORT void py_setreg(int i, py_Ref val); +#define py_r0() py_getreg(0) +#define py_r1() py_getreg(1) +#define py_r2() py_getreg(2) +#define py_r3() py_getreg(3) +#define py_r4() py_getreg(4) +#define py_r5() py_getreg(5) +#define py_r6() py_getreg(6) +#define py_r7() py_getreg(7) + /// Get variable in the `__main__` module. PK_EXPORT py_ItemRef py_getglobal(py_Name name); /// Set variable in the `__main__` module. diff --git a/src/public/modules.c b/src/public/modules.c index a9b1a07c..d17c5059 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -1,11 +1,13 @@ +#include "pocketpy/common/str.h" #include "pocketpy/objects/codeobject.h" #include "pocketpy/pocketpy.h" - #include "pocketpy/common/utils.h" #include "pocketpy/objects/object.h" #include "pocketpy/common/sstream.h" #include "pocketpy/interpreter/vm.h" #include "pocketpy/common/_generated.h" + +#include #include py_Ref py_getmodule(const char* path) { @@ -437,7 +439,7 @@ static bool builtins_locals(int argc, py_Ref argv) { void py_newglobals(py_Ref out) { Frame* frame = pk_current_vm->top_frame; - if(!frame){ + if(!frame) { pk_mappingproxy__namedict(out, &pk_current_vm->main); return; } @@ -523,6 +525,67 @@ static bool builtins_eval(int argc, py_Ref argv) { return _builtins_execdyn("eval", argc, argv, EVAL_MODE); } +static bool + pk_smartexec(const char* source, py_Ref module, enum py_CompileMode mode, va_list args) { + if(module == NULL) module = &pk_current_vm->main; + pk_mappingproxy__namedict(py_pushtmp(), module); // globals + py_newdict(py_pushtmp()); // locals + bool ok = py_compile(source, "", mode, true); + if(!ok) return false; + py_push(py_retval()); + // [globals, locals, code] + CodeObject* co = py_touserdata(py_peek(-1)); + py_StackRef locals = py_peek(-2); + int max_index = 0; + c11__foreach(Bytecode, &co->codes, bc) { + if(bc->op == OP_LOAD_NAME) { + c11_sv name = py_name2sv(bc->arg); + if(name.data[0] != '_') continue; + int index; + if(name.size == 1) { + index = 1; + } else if(name.size == 2 && isdigit(name.data[1])) { + index = name.data[1] - '0'; + } else { + continue; + } + max_index = c11__max(max_index, index); + } + } + + if(max_index == 0) { return ValueError("no placeholder found in the source"); } + + for(int i = 1; i <= max_index; i++) { + py_Ref val = va_arg(args, py_Ref); + char buf[3]; + buf[0] = '_'; + buf[1] = '0' + i; + buf[2] = '\0'; + py_dict_setitem_by_str(locals, buf, val); + if(i == 1) { + // _ => _1 + py_dict_setitem_by_str(locals, "_", val); + } + } + return pk_exec(co, module); +} + +bool py_smartexec(const char* source, py_Ref module, ...) { + va_list args; + va_start(args, module); + bool ok = pk_smartexec(source, module, EXEC_MODE, args); + va_end(args); + return ok; +} + +bool py_smarteval(const char* source, py_Ref module, ...) { + va_list args; + va_start(args, module); + bool ok = pk_smartexec(source, module, EVAL_MODE, args); + va_end(args); + return ok; +} + static bool builtins_compile(int argc, py_Ref argv) { PY_CHECK_ARGC(3); for(int i = 0; i < 3; i++) {