add py_smartexec

This commit is contained in:
blueloveTH 2024-08-21 17:05:38 +08:00
parent cc94a382a9
commit b99c3ed220
2 changed files with 89 additions and 2 deletions

View File

@ -111,6 +111,21 @@ PK_EXPORT bool py_exec(const char* source,
/// Evaluate a source string. Equivalent to `py_exec(source, "<string>", EVAL_MODE, module)`. /// Evaluate a source string. Equivalent to `py_exec(source, "<string>", EVAL_MODE, module)`.
PK_EXPORT bool py_eval(const char* source, py_Ref module) PY_RAISE PY_RETURN; 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. /// Compile a source string into a code object.
/// Use python's `exec()` or `eval()` to execute it. /// Use python's `exec()` or `eval()` to execute it.
PK_EXPORT bool py_compile(const char* source, 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. /// Set the i-th register.
PK_EXPORT void py_setreg(int i, py_Ref val); 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. /// Get variable in the `__main__` module.
PK_EXPORT py_ItemRef py_getglobal(py_Name name); PK_EXPORT py_ItemRef py_getglobal(py_Name name);
/// Set variable in the `__main__` module. /// Set variable in the `__main__` module.

View File

@ -1,11 +1,13 @@
#include "pocketpy/common/str.h"
#include "pocketpy/objects/codeobject.h" #include "pocketpy/objects/codeobject.h"
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include "pocketpy/common/utils.h" #include "pocketpy/common/utils.h"
#include "pocketpy/objects/object.h" #include "pocketpy/objects/object.h"
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
#include "pocketpy/common/_generated.h" #include "pocketpy/common/_generated.h"
#include <ctype.h>
#include <math.h> #include <math.h>
py_Ref py_getmodule(const char* path) { 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) { void py_newglobals(py_Ref out) {
Frame* frame = pk_current_vm->top_frame; Frame* frame = pk_current_vm->top_frame;
if(!frame){ if(!frame) {
pk_mappingproxy__namedict(out, &pk_current_vm->main); pk_mappingproxy__namedict(out, &pk_current_vm->main);
return; return;
} }
@ -523,6 +525,67 @@ static bool builtins_eval(int argc, py_Ref argv) {
return _builtins_execdyn("eval", argc, argv, EVAL_MODE); 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, "<string>", 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) { static bool builtins_compile(int argc, py_Ref argv) {
PY_CHECK_ARGC(3); PY_CHECK_ARGC(3);
for(int i = 0; i < 3; i++) { for(int i = 0; i < 3; i++) {