blueloveTH преди 1 година
родител
ревизия
b99c3ed220
променени са 2 файла, в които са добавени 89 реда и са изтрити 2 реда
  1. 24 0
      include/pocketpy/pocketpy.h
  2. 65 2
      src/public/modules.c

+ 24 - 0
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, "<string>", 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.

+ 65 - 2
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 <ctype.h>
 #include <math.h>
 
 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, "<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) {
     PY_CHECK_ARGC(3);
     for(int i = 0; i < 3; i++) {