This commit is contained in:
blueloveTH 2022-12-30 19:45:00 +08:00
parent eb58389945
commit 1515ef277e
6 changed files with 100 additions and 100 deletions

View File

@ -1,3 +1,7 @@
## 0.6.0+1
+ Break change
## 0.5.2+3 ## 0.5.2+3
+ Add web support + Add web support

View File

@ -28,16 +28,16 @@ class _Bindings
static final pkpy_new_repl = _lib.lookupFunction<ffi.Pointer Function(ffi.Pointer vm), ffi.Pointer Function(ffi.Pointer vm)>("pkpy_new_repl"); static final pkpy_new_repl = _lib.lookupFunction<ffi.Pointer Function(ffi.Pointer vm), ffi.Pointer Function(ffi.Pointer vm)>("pkpy_new_repl");
static final pkpy_repl_input = _lib.lookupFunction<ffi.Int32 Function(ffi.Pointer r, ffi.Pointer<Utf8> line), int Function(ffi.Pointer r, ffi.Pointer<Utf8> line)>("pkpy_repl_input"); static final pkpy_repl_input = _lib.lookupFunction<ffi.Int32 Function(ffi.Pointer r, ffi.Pointer<Utf8> line), int Function(ffi.Pointer r, ffi.Pointer<Utf8> line)>("pkpy_repl_input");
static final pkpy_new_tvm = _lib.lookupFunction<ffi.Pointer Function(ffi.Bool use_stdio), ffi.Pointer Function(bool use_stdio)>("pkpy_new_tvm"); static final pkpy_new_tvm = _lib.lookupFunction<ffi.Pointer Function(ffi.Bool use_stdio), ffi.Pointer Function(bool use_stdio)>("pkpy_new_tvm");
static final pkpy_tvm_exec_async = _lib.lookupFunction<ffi.Bool Function(ffi.Pointer vm, ffi.Pointer<Utf8> source), bool Function(ffi.Pointer vm, ffi.Pointer<Utf8> source)>("pkpy_tvm_exec_async"); static final pkpy_tvm_exec_async = _lib.lookupFunction<ffi.Void Function(ffi.Pointer vm, ffi.Pointer<Utf8> source), void Function(ffi.Pointer vm, ffi.Pointer<Utf8> source)>("pkpy_tvm_exec_async");
static final pkpy_tvm_get_state = _lib.lookupFunction<ffi.Int32 Function(ffi.Pointer vm), int Function(ffi.Pointer vm)>("pkpy_tvm_get_state"); static final pkpy_tvm_get_state = _lib.lookupFunction<ffi.Int32 Function(ffi.Pointer vm), int Function(ffi.Pointer vm)>("pkpy_tvm_get_state");
static final pkpy_tvm_read_jsonrpc_request = _lib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer vm), ffi.Pointer<Utf8> Function(ffi.Pointer vm)>("pkpy_tvm_read_jsonrpc_request"); static final pkpy_tvm_read_jsonrpc_request = _lib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer vm), ffi.Pointer<Utf8> Function(ffi.Pointer vm)>("pkpy_tvm_read_jsonrpc_request");
static final pkpy_tvm_reset_state = _lib.lookupFunction<ffi.Void Function(ffi.Pointer vm), void Function(ffi.Pointer vm)>("pkpy_tvm_reset_state"); static final pkpy_tvm_reset_state = _lib.lookupFunction<ffi.Void Function(ffi.Pointer vm), void Function(ffi.Pointer vm)>("pkpy_tvm_reset_state");
static final pkpy_tvm_terminate = _lib.lookupFunction<ffi.Void Function(ffi.Pointer vm), void Function(ffi.Pointer vm)>("pkpy_tvm_terminate"); static final pkpy_tvm_terminate = _lib.lookupFunction<ffi.Void Function(ffi.Pointer vm), void Function(ffi.Pointer vm)>("pkpy_tvm_terminate");
static final pkpy_tvm_write_jsonrpc_response = _lib.lookupFunction<ffi.Void Function(ffi.Pointer vm, ffi.Pointer<Utf8> value), void Function(ffi.Pointer vm, ffi.Pointer<Utf8> value)>("pkpy_tvm_write_jsonrpc_response"); static final pkpy_tvm_write_jsonrpc_response = _lib.lookupFunction<ffi.Void Function(ffi.Pointer vm, ffi.Pointer<Utf8> value), void Function(ffi.Pointer vm, ffi.Pointer<Utf8> value)>("pkpy_tvm_write_jsonrpc_response");
static final pkpy_new_vm = _lib.lookupFunction<ffi.Pointer Function(ffi.Bool use_stdio), ffi.Pointer Function(bool use_stdio)>("pkpy_new_vm"); static final pkpy_new_vm = _lib.lookupFunction<ffi.Pointer Function(ffi.Bool use_stdio), ffi.Pointer Function(bool use_stdio)>("pkpy_new_vm");
static final pkpy_vm_add_module = _lib.lookupFunction<ffi.Bool Function(ffi.Pointer vm, ffi.Pointer<Utf8> name, ffi.Pointer<Utf8> source), bool Function(ffi.Pointer vm, ffi.Pointer<Utf8> name, ffi.Pointer<Utf8> source)>("pkpy_vm_add_module"); static final pkpy_vm_add_module = _lib.lookupFunction<ffi.Void Function(ffi.Pointer vm, ffi.Pointer<Utf8> name, ffi.Pointer<Utf8> source), void Function(ffi.Pointer vm, ffi.Pointer<Utf8> name, ffi.Pointer<Utf8> source)>("pkpy_vm_add_module");
static final pkpy_vm_eval = _lib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> source), ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> source)>("pkpy_vm_eval"); static final pkpy_vm_eval = _lib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> source), ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> source)>("pkpy_vm_eval");
static final pkpy_vm_exec = _lib.lookupFunction<ffi.Bool Function(ffi.Pointer vm, ffi.Pointer<Utf8> source), bool Function(ffi.Pointer vm, ffi.Pointer<Utf8> source)>("pkpy_vm_exec"); static final pkpy_vm_exec = _lib.lookupFunction<ffi.Void Function(ffi.Pointer vm, ffi.Pointer<Utf8> source), void Function(ffi.Pointer vm, ffi.Pointer<Utf8> source)>("pkpy_vm_exec");
static final pkpy_vm_get_global = _lib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> name), ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> name)>("pkpy_vm_get_global"); static final pkpy_vm_get_global = _lib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> name), ffi.Pointer<Utf8> Function(ffi.Pointer vm, ffi.Pointer<Utf8> name)>("pkpy_vm_get_global");
static final pkpy_vm_read_output = _lib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer vm), ffi.Pointer<Utf8> Function(ffi.Pointer vm)>("pkpy_vm_read_output"); static final pkpy_vm_read_output = _lib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer vm), ffi.Pointer<Utf8> Function(ffi.Pointer vm)>("pkpy_vm_read_output");
} }
@ -76,11 +76,10 @@ class VM {
return ret; return ret;
} }
/// Add a source module into a virtual machine. Return `true` if there is no complie error. /// Add a source module into a virtual machine.
bool add_module(String name, String source) void add_module(String name, String source)
{ {
var ret = _Bindings.pkpy_vm_add_module(pointer, _Str(name).p, _Str(source).p); _Bindings.pkpy_vm_add_module(pointer, _Str(name).p, _Str(source).p);
return ret;
} }
/// Evaluate an expression. Return a json representing the result. If there is any error, return `nullptr`. /// Evaluate an expression. Return a json representing the result. If there is any error, return `nullptr`.
@ -93,11 +92,10 @@ class VM {
return s; return s;
} }
/// Run a given source on a virtual machine. Return `true` if there is no compile error. /// Run a given source on a virtual machine.
bool exec(String source) void exec(String source)
{ {
var ret = _Bindings.pkpy_vm_exec(pointer, _Str(source).p); _Bindings.pkpy_vm_exec(pointer, _Str(source).p);
return ret;
} }
/// Get a global variable of a virtual machine. Return a json representing the result. If the variable is not found, return `nullptr`. /// Get a global variable of a virtual machine. Return a json representing the result. If the variable is not found, return `nullptr`.
@ -117,11 +115,10 @@ enum ThreadState { ready, running, suspended, finished }
class ThreadedVM extends VM { class ThreadedVM extends VM {
ThreadState get state => ThreadState.values[_Bindings.pkpy_tvm_get_state(pointer)]; ThreadState get state => ThreadState.values[_Bindings.pkpy_tvm_get_state(pointer)];
/// Run a given source on a threaded virtual machine. The excution will be started in a new thread. Return `true` if there is no compile error. /// Run a given source on a threaded virtual machine. The excution will be started in a new thread.
bool exec_async(String source) void exec_async(String source)
{ {
var ret = _Bindings.pkpy_tvm_exec_async(pointer, _Str(source).p); _Bindings.pkpy_tvm_exec_async(pointer, _Str(source).p);
return ret;
} }
/// Read the current JSONRPC request from shared string buffer. /// Read the current JSONRPC request from shared string buffer.

View File

@ -12,16 +12,16 @@ class _Bindings
static final pkpy_new_repl = (dynamic vm) => ccall("pkpy_new_repl", "number", ["number"], [vm]); static final pkpy_new_repl = (dynamic vm) => ccall("pkpy_new_repl", "number", ["number"], [vm]);
static final pkpy_repl_input = (dynamic r, String line) => ccall("pkpy_repl_input", "number", ["number", "string"], [r, line]); static final pkpy_repl_input = (dynamic r, String line) => ccall("pkpy_repl_input", "number", ["number", "string"], [r, line]);
static final pkpy_new_tvm = (bool use_stdio) => ccall("pkpy_new_tvm", "number", ["boolean"], [use_stdio]); static final pkpy_new_tvm = (bool use_stdio) => ccall("pkpy_new_tvm", "number", ["boolean"], [use_stdio]);
static final pkpy_tvm_exec_async = (dynamic vm, String source) => ccall("pkpy_tvm_exec_async", "boolean", ["number", "string"], [vm, source]); static final pkpy_tvm_exec_async = (dynamic vm, String source) => ccall("pkpy_tvm_exec_async", null, ["number", "string"], [vm, source]);
static final pkpy_tvm_get_state = (dynamic vm) => ccall("pkpy_tvm_get_state", "number", ["number"], [vm]); static final pkpy_tvm_get_state = (dynamic vm) => ccall("pkpy_tvm_get_state", "number", ["number"], [vm]);
static final pkpy_tvm_read_jsonrpc_request = (dynamic vm) => ccall("pkpy_tvm_read_jsonrpc_request", "string", ["number"], [vm]); static final pkpy_tvm_read_jsonrpc_request = (dynamic vm) => ccall("pkpy_tvm_read_jsonrpc_request", "string", ["number"], [vm]);
static final pkpy_tvm_reset_state = (dynamic vm) => ccall("pkpy_tvm_reset_state", null, ["number"], [vm]); static final pkpy_tvm_reset_state = (dynamic vm) => ccall("pkpy_tvm_reset_state", null, ["number"], [vm]);
static final pkpy_tvm_terminate = (dynamic vm) => ccall("pkpy_tvm_terminate", null, ["number"], [vm]); static final pkpy_tvm_terminate = (dynamic vm) => ccall("pkpy_tvm_terminate", null, ["number"], [vm]);
static final pkpy_tvm_write_jsonrpc_response = (dynamic vm, String value) => ccall("pkpy_tvm_write_jsonrpc_response", null, ["number", "string"], [vm, value]); static final pkpy_tvm_write_jsonrpc_response = (dynamic vm, String value) => ccall("pkpy_tvm_write_jsonrpc_response", null, ["number", "string"], [vm, value]);
static final pkpy_new_vm = (bool use_stdio) => ccall("pkpy_new_vm", "number", ["boolean"], [use_stdio]); static final pkpy_new_vm = (bool use_stdio) => ccall("pkpy_new_vm", "number", ["boolean"], [use_stdio]);
static final pkpy_vm_add_module = (dynamic vm, String name, String source) => ccall("pkpy_vm_add_module", "boolean", ["number", "string", "string"], [vm, name, source]); static final pkpy_vm_add_module = (dynamic vm, String name, String source) => ccall("pkpy_vm_add_module", null, ["number", "string", "string"], [vm, name, source]);
static final pkpy_vm_eval = (dynamic vm, String source) => ccall("pkpy_vm_eval", "string", ["number", "string"], [vm, source]); static final pkpy_vm_eval = (dynamic vm, String source) => ccall("pkpy_vm_eval", "string", ["number", "string"], [vm, source]);
static final pkpy_vm_exec = (dynamic vm, String source) => ccall("pkpy_vm_exec", "boolean", ["number", "string"], [vm, source]); static final pkpy_vm_exec = (dynamic vm, String source) => ccall("pkpy_vm_exec", null, ["number", "string"], [vm, source]);
static final pkpy_vm_get_global = (dynamic vm, String name) => ccall("pkpy_vm_get_global", "string", ["number", "string"], [vm, name]); static final pkpy_vm_get_global = (dynamic vm, String name) => ccall("pkpy_vm_get_global", "string", ["number", "string"], [vm, name]);
static final pkpy_vm_read_output = (dynamic vm) => ccall("pkpy_vm_read_output", "string", ["number"], [vm]); static final pkpy_vm_read_output = (dynamic vm) => ccall("pkpy_vm_read_output", "string", ["number"], [vm]);
} }
@ -49,11 +49,10 @@ class VM {
return ret; return ret;
} }
/// Add a source module into a virtual machine. Return `true` if there is no complie error. /// Add a source module into a virtual machine.
bool add_module(String name, String source) void add_module(String name, String source)
{ {
var ret = _Bindings.pkpy_vm_add_module(pointer, name, source); _Bindings.pkpy_vm_add_module(pointer, name, source);
return ret;
} }
/// Evaluate an expression. Return a json representing the result. If there is any error, return `nullptr`. /// Evaluate an expression. Return a json representing the result. If there is any error, return `nullptr`.
@ -63,11 +62,10 @@ class VM {
return ret; return ret;
} }
/// Run a given source on a virtual machine. Return `true` if there is no compile error. /// Run a given source on a virtual machine.
bool exec(String source) void exec(String source)
{ {
var ret = _Bindings.pkpy_vm_exec(pointer, source); _Bindings.pkpy_vm_exec(pointer, source);
return ret;
} }
/// Get a global variable of a virtual machine. Return a json representing the result. If the variable is not found, return `nullptr`. /// Get a global variable of a virtual machine. Return a json representing the result. If the variable is not found, return `nullptr`.
@ -84,11 +82,10 @@ enum ThreadState { ready, running, suspended, finished }
class ThreadedVM extends VM { class ThreadedVM extends VM {
ThreadState get state => ThreadState.values[_Bindings.pkpy_tvm_get_state(pointer)]; ThreadState get state => ThreadState.values[_Bindings.pkpy_tvm_get_state(pointer)];
/// Run a given source on a threaded virtual machine. The excution will be started in a new thread. Return `true` if there is no compile error. /// Run a given source on a threaded virtual machine. The excution will be started in a new thread.
bool exec_async(String source) void exec_async(String source)
{ {
var ret = _Bindings.pkpy_tvm_exec_async(pointer, source); _Bindings.pkpy_tvm_exec_async(pointer, source);
return ret;
} }
/// Read the current JSONRPC request from shared string buffer. /// Read the current JSONRPC request from shared string buffer.

View File

@ -1,6 +1,6 @@
name: pocketpy name: pocketpy
description: A lightweight Python interpreter for game engines. description: A lightweight Python interpreter for game engines.
version: 0.5.2+3 version: 0.6.0+1
homepage: https://pocketpy.dev homepage: https://pocketpy.dev
repository: https://github.com/blueloveth/pocketpy repository: https://github.com/blueloveth/pocketpy

View File

@ -27,7 +27,6 @@
#include <iomanip> #include <iomanip>
#include <map> #include <map>
#include <thread>
#include <atomic> #include <atomic>
#include <iostream> #include <iostream>
@ -37,7 +36,13 @@
#define UNREACHABLE() throw std::runtime_error( __FILE__ + std::string(":") + std::to_string(__LINE__) + " UNREACHABLE()!"); #define UNREACHABLE() throw std::runtime_error( __FILE__ + std::string(":") + std::to_string(__LINE__) + " UNREACHABLE()!");
#endif #endif
#define PK_VERSION "0.5.2" #ifdef __EMSCRIPTEN__
#include <emscripten.h>
#else
#include <thread>
#endif
#define PK_VERSION "0.6.0"
//#define PKPY_NO_TYPE_CHECK //#define PKPY_NO_TYPE_CHECK
//#define PKPY_NO_INDEX_CHECK //#define PKPY_NO_INDEX_CHECK
@ -3921,7 +3926,7 @@ class VM {
protected: protected:
std::deque< pkpy::unique_ptr<Frame> > callstack; std::deque< pkpy::unique_ptr<Frame> > callstack;
PyVarDict _modules; // loaded modules PyVarDict _modules; // loaded modules
std::map<_Str, _Code> _lazyModules; // lazy loaded modules std::map<_Str, _Str> _lazyModules; // lazy loaded modules
PyVar __py2py_call_signal; PyVar __py2py_call_signal;
void _checkStopFlag(){ void _checkStopFlag(){
@ -4208,7 +4213,8 @@ protected:
if(it2 == _lazyModules.end()){ if(it2 == _lazyModules.end()){
_error("ImportError", "module '" + name + "' not found"); _error("ImportError", "module '" + name + "' not found");
}else{ }else{
_Code code = it2->second; const _Str& source = it2->second;
_Code code = compile(source.c_str(), name, EXEC_MODE);
PyVar _m = newModule(name); PyVar _m = newModule(name);
_exec(code, _m, {}); _exec(code, _m, {});
frame->push(_m); frame->push(_m);
@ -4272,9 +4278,14 @@ public:
void sleepForSecs(_Float sec){ void sleepForSecs(_Float sec){
_Int ms = (_Int)(sec * 1000); _Int ms = (_Int)(sec * 1000);
for(_Int i=0; i<ms; i+=20){ const _Int step = 20;
for(_Int i=0; i<ms; i+=step){
_checkStopFlag(); _checkStopFlag();
std::this_thread::sleep_for(std::chrono::milliseconds(20)); #ifdef __EMSCRIPTEN__
emscripten_sleep(step);
#else
std::this_thread::sleep_for(std::chrono::milliseconds(step));
#endif
} }
} }
@ -4441,9 +4452,10 @@ public:
// repl mode is only for setting `frame->id` to 0 // repl mode is only for setting `frame->id` to 0
virtual PyVarOrNull exec(const _Code& code, PyVar _module=nullptr){ virtual PyVarOrNull exec(const char* source, _Str filename, CompileMode mode, PyVar _module=nullptr){
if(_module == nullptr) _module = _main; if(_module == nullptr) _module = _main;
try { try {
_Code code = compile(source, filename, mode);
return _exec(code, _module, {}); return _exec(code, _module, {});
}catch (const _Error& e){ }catch (const _Error& e){
*_stderr << e.what() << '\n'; *_stderr << e.what() << '\n';
@ -4454,8 +4466,8 @@ public:
return nullptr; return nullptr;
} }
virtual void execAsync(const _Code& code) { virtual void execAsync(const char* source, _Str filename, CompileMode mode) {
exec(code); exec(source, filename, mode);
} }
Frame* __pushNewFrame(const _Code& code, PyVar _module, PyVarDict&& locals){ Frame* __pushNewFrame(const _Code& code, PyVar _module, PyVarDict&& locals){
@ -4524,8 +4536,8 @@ public:
return obj; return obj;
} }
void addLazyModule(_Str name, _Code code){ void addLazyModule(_Str name, const char* source){
_lazyModules[name] = code; _lazyModules[name] = source;
} }
PyVarOrNull getAttr(const PyVar& obj, const _Str& name, bool throw_err=true) { PyVarOrNull getAttr(const PyVar& obj, const _Str& name, bool throw_err=true) {
@ -4844,6 +4856,8 @@ public:
delete _stderr; delete _stderr;
} }
} }
_Code compile(const char* source, _Str filename, CompileMode mode);
}; };
/***** Pointers' Impl *****/ /***** Pointers' Impl *****/
@ -4972,10 +4986,11 @@ enum ThreadState {
}; };
class ThreadedVM : public VM { class ThreadedVM : public VM {
std::thread* _thread = nullptr;
std::atomic<ThreadState> _state = THREAD_READY; std::atomic<ThreadState> _state = THREAD_READY;
_Str _sharedStr = ""; _Str _sharedStr = "";
#ifndef __EMSCRIPTEN__
std::thread* _thread = nullptr;
void __deleteThread(){ void __deleteThread(){
if(_thread != nullptr){ if(_thread != nullptr){
terminate(); terminate();
@ -4984,6 +4999,10 @@ class ThreadedVM : public VM {
_thread = nullptr; _thread = nullptr;
} }
} }
#else
void __deleteThread(){}
#endif
public: public:
ThreadedVM(bool use_stdio) : VM(use_stdio) { ThreadedVM(bool use_stdio) : VM(use_stdio) {
bindBuiltinFunc("__string_channel_call", [](VM* vm, const pkpy::ArgList& args){ bindBuiltinFunc("__string_channel_call", [](VM* vm, const pkpy::ArgList& args){
@ -5028,21 +5047,28 @@ public:
_state = THREAD_RUNNING; _state = THREAD_RUNNING;
} }
void execAsync(const _Code& code) override { void execAsync(const char* source, _Str filename, CompileMode mode) override {
if(_state != THREAD_READY) UNREACHABLE(); if(_state != THREAD_READY) UNREACHABLE();
__deleteThread();
_thread = new std::thread([this, code](){ #ifdef __EMSCRIPTEN__
this->_state = THREAD_RUNNING; this->_state = THREAD_RUNNING;
VM::exec(code); VM::exec(source, filename, mode);
this->_state = THREAD_FINISHED;
#else
__deleteThread();
_thread = new std::thread([=](){
this->_state = THREAD_RUNNING;
VM::exec(source, filename, mode);
this->_state = THREAD_FINISHED; this->_state = THREAD_FINISHED;
}); });
#endif
} }
PyVarOrNull exec(const _Code& code, PyVar _module = nullptr) override { PyVarOrNull exec(const char* source, _Str filename, CompileMode mode, PyVar _module=nullptr) override {
if(_state == THREAD_READY) return VM::exec(code, _module); if(_state == THREAD_READY) return VM::exec(source, filename, mode, _module);
auto callstackBackup = std::move(callstack); auto callstackBackup = std::move(callstack);
callstack.clear(); callstack.clear();
PyVarOrNull ret = VM::exec(code, _module); PyVarOrNull ret = VM::exec(source, filename, mode, _module);
callstack = std::move(callstackBackup); callstack = std::move(callstackBackup);
return ret; return ret;
} }
@ -6118,20 +6144,6 @@ __LISTCOMP:
void unexpectedError(_Str msg){ throw CompileError("UnexpectedError", msg, getLineSnapshot()); } void unexpectedError(_Str msg){ throw CompileError("UnexpectedError", msg, getLineSnapshot()); }
}; };
_Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_MODE, bool noThrow=true) {
Compiler compiler(vm, source, filename, mode);
if(!noThrow) return compiler.__fillCode();
try{
return compiler.__fillCode();
}catch(_Error& e){
(*vm->_stderr) << e.what() << '\n';
}catch(std::exception& e){
auto ce = CompileError("UnexpectedError", e.what(), compiler.getLineSnapshot());
(*vm->_stderr) << ce.what() << '\n';
}
return nullptr;
}
enum InputResult { enum InputResult {
NEED_MORE_LINES = 0, NEED_MORE_LINES = 0,
@ -6184,9 +6196,7 @@ __NOT_ENOUGH_LINES:
} }
try{ try{
_Code code = compile(vm, line.c_str(), "<stdin>", SINGLE_MODE); vm->execAsync(line.c_str(), "<stdin>", SINGLE_MODE);
if(code == nullptr) return EXEC_SKIPPED;
vm->execAsync(code);
return EXEC_DONE; return EXEC_DONE;
}catch(NeedMoreLines& ne){ }catch(NeedMoreLines& ne){
buffer += line; buffer += line;
@ -6198,6 +6208,17 @@ __NOT_ENOUGH_LINES:
}; };
_Code VM::compile(const char* source, _Str filename, CompileMode mode) {
Compiler compiler(this, source, filename, mode);
try{
return compiler.__fillCode();
}catch(_Error& e){
throw e;
}catch(std::exception& e){
throw CompileError("UnexpectedError", e.what(), compiler.getLineSnapshot());
}
}
#define BIND_NUM_ARITH_OPT(name, op) \ #define BIND_NUM_ARITH_OPT(name, op) \
_vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, const pkpy::ArgList& args){ \ _vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, const pkpy::ArgList& args){ \
if(!vm->isIntOrFloat(args[0], args[1])) \ if(!vm->isIntOrFloat(args[0], args[1])) \
@ -6249,7 +6270,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindBuiltinFunc("eval", [](VM* vm, const pkpy::ArgList& args) { _vm->bindBuiltinFunc("eval", [](VM* vm, const pkpy::ArgList& args) {
vm->__checkArgSize(args, 1); vm->__checkArgSize(args, 1);
const _Str& expr = vm->PyStr_AS_C(args[0]); const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = compile(vm, expr.c_str(), "<eval>", EVAL_MODE, false); _Code code = vm->compile(expr.c_str(), "<eval>", EVAL_MODE);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals()); return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals());
}); });
@ -6781,8 +6802,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
#define __EXPORT __declspec(dllexport) #define __EXPORT __declspec(dllexport)
#elif __APPLE__ #elif __APPLE__
#define __EXPORT __attribute__((visibility("default"))) __attribute__((used)) #define __EXPORT __attribute__((visibility("default"))) __attribute__((used))
#elif defined(__EMSCRIPTEN__) || defined(__wasm__) || defined(__wasm32__) || defined(__wasm64__) #elif __EMSCRIPTEN__
#include <emscripten.h>
#define __EXPORT EMSCRIPTEN_KEEPALIVE #define __EXPORT EMSCRIPTEN_KEEPALIVE
#define __NO_MAIN #define __NO_MAIN
#else #else
@ -6834,7 +6854,7 @@ void __addModuleJson(VM* vm){
vm->bindFunc(mod, "loads", [](VM* vm, const pkpy::ArgList& args) { vm->bindFunc(mod, "loads", [](VM* vm, const pkpy::ArgList& args) {
vm->__checkArgSize(args, 1); vm->__checkArgSize(args, 1);
const _Str& expr = vm->PyStr_AS_C(args[0]); const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = compile(vm, expr.c_str(), "<json>", JSON_MODE, false); _Code code = vm->compile(expr.c_str(), "<json>", JSON_MODE);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals()); return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals());
}); });
@ -7038,13 +7058,8 @@ extern "C" {
__EXPORT __EXPORT
/// Run a given source on a virtual machine. /// Run a given source on a virtual machine.
/// void pkpy_vm_exec(VM* vm, const char* source){
/// Return `true` if there is no compile error. vm->exec(source, "main.py", EXEC_MODE);
bool pkpy_vm_exec(VM* vm, const char* source){
_Code code = compile(vm, source, "main.py");
if(code == nullptr) return false;
vm->exec(code);
return true;
} }
__EXPORT __EXPORT
@ -7069,9 +7084,7 @@ extern "C" {
/// Return a json representing the result. /// Return a json representing the result.
/// If there is any error, return `nullptr`. /// If there is any error, return `nullptr`.
char* pkpy_vm_eval(VM* vm, const char* source){ char* pkpy_vm_eval(VM* vm, const char* source){
_Code code = compile(vm, source, "<eval>", EVAL_MODE); PyVarOrNull ret = vm->exec(source, "<eval>", EVAL_MODE);
if(code == nullptr) return nullptr;
PyVarOrNull ret = vm->exec(code);
if(ret == nullptr) return nullptr; if(ret == nullptr) return nullptr;
try{ try{
_Str _json = vm->PyStr_AS_C(vm->asJson(ret)); _Str _json = vm->PyStr_AS_C(vm->asJson(ret));
@ -7099,14 +7112,8 @@ extern "C" {
__EXPORT __EXPORT
/// Add a source module into a virtual machine. /// Add a source module into a virtual machine.
/// void pkpy_vm_add_module(VM* vm, const char* name, const char* source){
/// Return `true` if there is no complie error. vm->addLazyModule(name, source);
bool pkpy_vm_add_module(VM* vm, const char* name, const char* source){
// compile the module but don't execute it
_Code code = compile(vm, source, name + _Str(".py"));
if(code == nullptr) return false;
vm->addLazyModule(name, code);
return true;
} }
void __vm_init(VM* vm){ void __vm_init(VM* vm){
@ -7117,9 +7124,10 @@ extern "C" {
__addModuleMath(vm); __addModuleMath(vm);
__addModuleRe(vm); __addModuleRe(vm);
_Code code = compile(vm, __BUILTINS_CODE, "<builtins>"); // add builtins | no exception handler | must succeed
if(code == nullptr) exit(1); _Code code = vm->compile(__BUILTINS_CODE, "<builtins>", EXEC_MODE);
vm->_exec(code, vm->builtins, {}); vm->_exec(code, vm->builtins, {});
pkpy_vm_add_module(vm, "random", __RANDOM_CODE); pkpy_vm_add_module(vm, "random", __RANDOM_CODE);
pkpy_vm_add_module(vm, "os", __OS_CODE); pkpy_vm_add_module(vm, "os", __OS_CODE);
} }
@ -7201,14 +7209,8 @@ extern "C" {
__EXPORT __EXPORT
/// Run a given source on a threaded virtual machine. /// Run a given source on a threaded virtual machine.
/// The excution will be started in a new thread. /// The excution will be started in a new thread.
/// void pkpy_tvm_exec_async(VM* vm, const char* source){
/// Return `true` if there is no compile error. vm->execAsync(source, "main.py", EXEC_MODE);
bool pkpy_tvm_exec_async(VM* vm, const char* source){
// although this is a method of VM, it's only used in ThreadedVM
_Code code = compile(vm, source, "main.py");
if(code == nullptr) return false;
vm->execAsync(code);
return true;
} }
} }

@ -1 +1 @@
Subproject commit 43c56123929e5a203a85412c4e30cb12d742f87c Subproject commit fb90950aa1d0967579661690fb17048fa93456cf