This commit is contained in:
blueloveTH 2023-01-29 22:59:40 +08:00
parent 968ac29652
commit 2cc47b9574
4 changed files with 82 additions and 359 deletions

View File

@ -26,15 +26,7 @@ class _Bindings
static final pkpy_delete = _lib.lookupFunction<ffi.Void Function(ffi.Pointer p), void Function(ffi.Pointer p)>("pkpy_delete"); static final pkpy_delete = _lib.lookupFunction<ffi.Void Function(ffi.Pointer p), void Function(ffi.Pointer p)>("pkpy_delete");
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.Void Function(ffi.Pointer r, ffi.Pointer<Utf8> line), void 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_repl_last_input_result = _lib.lookupFunction<ffi.Int32 Function(ffi.Pointer r), int Function(ffi.Pointer r)>("pkpy_repl_last_input_result");
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.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_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_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_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.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_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");
@ -43,116 +35,6 @@ class _Bindings
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");
} }
class _Str {
static final Finalizer<ffi.Pointer<Utf8>> finalizer = Finalizer((p) => malloc.free(p));
late final ffi.Pointer<Utf8> _p;
_Str(String s) {
_p = s.toNativeUtf8();
finalizer.attach(this, _p);
}
ffi.Pointer<Utf8> get p => _p;
}
class VM {
late final ffi.Pointer pointer;
VM() {
if (this is ThreadedVM) {
pointer = _Bindings.pkpy_new_tvm(false);
} else {
pointer = _Bindings.pkpy_new_vm(false);
}
}
void dispose() {
_Bindings.pkpy_delete(pointer);
}
PyOutput read_output() {
var _o = _Bindings.pkpy_vm_read_output(pointer);
String _j = _o.toDartString();
var ret = PyOutput.fromJson(cvt.jsonDecode(_j));
_Bindings.pkpy_delete(_o);
return ret;
}
/// Add a source module into a virtual machine.
void add_module(String name, String source)
{
_Bindings.pkpy_vm_add_module(pointer, _Str(name).p, _Str(source).p);
}
/// Evaluate an expression. Return a json representing the result. If there is any error, return `nullptr`.
String? eval(String source)
{
var ret = _Bindings.pkpy_vm_eval(pointer, _Str(source).p);
if (ret == ffi.nullptr) return null;
String s = ret.toDartString();
_Bindings.pkpy_delete(ret);
return s;
}
/// Run a given source on a virtual machine.
void exec(String source)
{
_Bindings.pkpy_vm_exec(pointer, _Str(source).p);
}
/// Get a global variable of a virtual machine. Return a json representing the result. If the variable is not found, return `nullptr`.
String? get_global(String name)
{
var ret = _Bindings.pkpy_vm_get_global(pointer, _Str(name).p);
if (ret == ffi.nullptr) return null;
String s = ret.toDartString();
_Bindings.pkpy_delete(ret);
return s;
}
}
enum ThreadState { ready, running, suspended, finished }
class ThreadedVM extends VM {
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.
void exec_async(String source)
{
_Bindings.pkpy_tvm_exec_async(pointer, _Str(source).p);
}
/// Read the current JSONRPC request from shared string buffer.
String? read_jsonrpc_request()
{
var ret = _Bindings.pkpy_tvm_read_jsonrpc_request(pointer);
if (ret == ffi.nullptr) return null;
String s = ret.toDartString();
_Bindings.pkpy_delete(ret);
return s;
}
/// Set the state of a threaded virtual machine to `THREAD_READY`. The current state should be `THREAD_FINISHED`.
void reset_state()
{
_Bindings.pkpy_tvm_reset_state(pointer);
}
/// Emit a KeyboardInterrupt signal to stop a running threaded virtual machine.
void terminate()
{
_Bindings.pkpy_tvm_terminate(pointer);
}
/// Write a JSONRPC response to shared string buffer.
void write_jsonrpc_response(String value)
{
_Bindings.pkpy_tvm_write_jsonrpc_response(pointer, _Str(value).p);
}
}
class REPL { class REPL {
late final ffi.Pointer pointer; late final ffi.Pointer pointer;
@ -166,15 +48,9 @@ class REPL {
} }
/// Input a source line to an interactive console. /// Input a source line to an interactive console.
void input(String line) int input(String line)
{ {
_Bindings.pkpy_repl_input(pointer, _Str(line).p); var ret = _Bindings.pkpy_repl_input(pointer, _Str(line).p);
}
/// Check if the REPL needs more lines.
int last_input_result()
{
var ret = _Bindings.pkpy_repl_last_input_result(pointer);
return ret; return ret;
} }

View File

@ -3,132 +3,20 @@ import 'dart:convert' as cvt;
import 'package:js/js.dart'; import 'package:js/js.dart';
import 'common.dart'; import 'common.dart';
@JS()
@anonymous
class Opt {
external bool get async;
external factory Opt({bool async});
}
@JS("Module.ccall") @JS("Module.ccall")
external dynamic ccall(String name, String? returnType, List<String> argTypes, List<dynamic> args, Opt opt); external dynamic ccall(String name, String? returnType, List<String> argTypes, List<dynamic> args);
class _Bindings class _Bindings
{ {
static final pkpy_delete = (dynamic p) => ccall("pkpy_delete", null, ["number"], [p], Opt(async: false)); static final pkpy_delete = (dynamic p) => ccall("pkpy_delete", null, ["number"], [p]);
static final pkpy_new_repl = (dynamic vm) => ccall("pkpy_new_repl", "number", ["number"], [vm], Opt(async: false)); 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", null, ["number", "string"], [r, line], Opt(async: true)); static final pkpy_repl_input = (dynamic r, String line) => ccall("pkpy_repl_input", "number", ["number", "string"], [r, line]);
static final pkpy_repl_last_input_result = (dynamic r) => ccall("pkpy_repl_last_input_result", "number", ["number"], [r], Opt(async: false)); static final pkpy_new_vm = (bool use_stdio) => ccall("pkpy_new_vm", "number", ["boolean"], [use_stdio]);
static final pkpy_new_tvm = (bool use_stdio) => ccall("pkpy_new_tvm", "number", ["boolean"], [use_stdio], Opt(async: false)); 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_tvm_exec_async = (dynamic vm, String source) => ccall("pkpy_tvm_exec_async", null, ["number", "string"], [vm, source], Opt(async: true)); static final pkpy_vm_eval = (dynamic vm, String source) => ccall("pkpy_vm_eval", "string", ["number", "string"], [vm, source]);
static final pkpy_tvm_get_state = (dynamic vm) => ccall("pkpy_tvm_get_state", "number", ["number"], [vm], Opt(async: false)); static final pkpy_vm_exec = (dynamic vm, String source) => ccall("pkpy_vm_exec", null, ["number", "string"], [vm, source]);
static final pkpy_tvm_read_jsonrpc_request = (dynamic vm) => ccall("pkpy_tvm_read_jsonrpc_request", "string", ["number"], [vm], Opt(async: false)); static final pkpy_vm_get_global = (dynamic vm, String name) => ccall("pkpy_vm_get_global", "string", ["number", "string"], [vm, name]);
static final pkpy_tvm_reset_state = (dynamic vm) => ccall("pkpy_tvm_reset_state", null, ["number"], [vm], Opt(async: false)); static final pkpy_vm_read_output = (dynamic vm) => ccall("pkpy_vm_read_output", "string", ["number"], [vm]);
static final pkpy_tvm_terminate = (dynamic vm) => ccall("pkpy_tvm_terminate", null, ["number"], [vm], Opt(async: false));
static final pkpy_tvm_write_jsonrpc_response = (dynamic vm, String value) => ccall("pkpy_tvm_write_jsonrpc_response", null, ["number", "string"], [vm, value], Opt(async: false));
static final pkpy_new_vm = (bool use_stdio) => ccall("pkpy_new_vm", "number", ["boolean"], [use_stdio], Opt(async: false));
static final pkpy_vm_add_module = (dynamic vm, String name, String source) => ccall("pkpy_vm_add_module", null, ["number", "string", "string"], [vm, name, source], Opt(async: false));
static final pkpy_vm_eval = (dynamic vm, String source) => ccall("pkpy_vm_eval", "string", ["number", "string"], [vm, source], Opt(async: false));
static final pkpy_vm_exec = (dynamic vm, String source) => ccall("pkpy_vm_exec", null, ["number", "string"], [vm, source], Opt(async: false));
static final pkpy_vm_get_global = (dynamic vm, String name) => ccall("pkpy_vm_get_global", "string", ["number", "string"], [vm, name], Opt(async: false));
static final pkpy_vm_read_output = (dynamic vm) => ccall("pkpy_vm_read_output", "string", ["number"], [vm], Opt(async: false));
}
class VM {
late final dynamic pointer;
VM() {
if (this is ThreadedVM) {
pointer = _Bindings.pkpy_new_tvm(false);
} else {
pointer = _Bindings.pkpy_new_vm(false);
}
}
void dispose() {
_Bindings.pkpy_delete(pointer);
}
PyOutput read_output() {
var _o = _Bindings.pkpy_vm_read_output(pointer);
String _j = _o;
var ret = PyOutput.fromJson(cvt.jsonDecode(_j));
return ret;
}
/// Add a source module into a virtual machine.
void add_module(String name, String source)
{
_Bindings.pkpy_vm_add_module(pointer, name, source);
}
/// Evaluate an expression. Return a json representing the result. If there is any error, return `nullptr`.
String? eval(String source)
{
var ret = _Bindings.pkpy_vm_eval(pointer, source);
return ret;
}
/// Run a given source on a virtual machine.
void exec(String source)
{
_Bindings.pkpy_vm_exec(pointer, source);
}
/// Get a global variable of a virtual machine. Return a json representing the result. If the variable is not found, return `nullptr`.
String? get_global(String name)
{
var ret = _Bindings.pkpy_vm_get_global(pointer, name);
return ret;
}
}
enum ThreadState { ready, running, suspended, finished }
class ThreadedVM extends VM {
ThreadState get state => ThreadState.values[_Bindings.pkpy_tvm_get_state(pointer)];
@override
void dispose() {
terminate();
Future.delayed(Duration(milliseconds: 150)).then((_) => _Bindings.pkpy_delete(pointer));
}
/// Run a given source on a threaded virtual machine. The excution will be started in a new thread.
void exec_async(String source)
{
_Bindings.pkpy_tvm_exec_async(pointer, source);
}
/// Read the current JSONRPC request from shared string buffer.
String? read_jsonrpc_request()
{
var ret = _Bindings.pkpy_tvm_read_jsonrpc_request(pointer);
return ret;
}
/// Set the state of a threaded virtual machine to `THREAD_READY`. The current state should be `THREAD_FINISHED`.
void reset_state()
{
_Bindings.pkpy_tvm_reset_state(pointer);
}
/// Emit a KeyboardInterrupt signal to stop a running threaded virtual machine.
void terminate()
{
_Bindings.pkpy_tvm_terminate(pointer);
}
/// Write a JSONRPC response to shared string buffer.
void write_jsonrpc_response(String value)
{
_Bindings.pkpy_tvm_write_jsonrpc_response(pointer, value);
}
} }
class REPL { class REPL {
@ -143,15 +31,9 @@ class REPL {
} }
/// Input a source line to an interactive console. /// Input a source line to an interactive console.
void input(String line) int input(String line)
{ {
_Bindings.pkpy_repl_input(pointer, line); var ret = _Bindings.pkpy_repl_input(pointer, line);
}
/// Check if the REPL needs more lines.
int last_input_result()
{
var ret = _Bindings.pkpy_repl_last_input_result(pointer);
return ret; return ret;
} }

View File

@ -1879,20 +1879,16 @@ namespace pkpy{
} }
shared_ptr& operator=(const shared_ptr& other) { shared_ptr& operator=(const shared_ptr& other) {
if (this != &other) { _dec_counter();
_dec_counter(); counter = other.counter;
counter = other.counter; _inc_counter();
_inc_counter();
}
return *this; return *this;
} }
shared_ptr& operator=(shared_ptr&& other) noexcept { shared_ptr& operator=(shared_ptr&& other) noexcept {
if (this != &other) { _dec_counter();
_dec_counter(); counter = other.counter;
counter = other.counter; other.counter = nullptr;
other.counter = nullptr;
}
return *this; return *this;
} }
@ -2161,12 +2157,12 @@ public:
typedef emhash8::HashMap<_Str, PyVar> PyVarDict; typedef emhash8::HashMap<_Str, PyVar> PyVarDict;
namespace pkpy { namespace pkpy {
const uint8_t MAX_POOLING_N = 10; const int MAX_POOLING_N = 10;
static thread_local std::vector<PyVar*>* _poolArgList = new std::vector<PyVar*>[MAX_POOLING_N]; static thread_local std::vector<PyVar*>* _poolArgList = new std::vector<PyVar*>[MAX_POOLING_N];
class ArgList { class ArgList {
PyVar* _args; PyVar* _args;
uint8_t _size; int _size;
void __tryAlloc(size_t n){ void __tryAlloc(size_t n){
if(n == 0){ if(n == 0){
@ -2174,7 +2170,6 @@ namespace pkpy {
this->_size = 0; this->_size = 0;
return; return;
} }
if(n > 255) UNREACHABLE();
if(n >= MAX_POOLING_N || _poolArgList[n].empty()){ if(n >= MAX_POOLING_N || _poolArgList[n].empty()){
this->_args = new PyVar[n]; this->_args = new PyVar[n];
this->_size = n; this->_size = n;
@ -2190,7 +2185,7 @@ namespace pkpy {
if(_size >= MAX_POOLING_N || _poolArgList[_size].size() > 32){ if(_size >= MAX_POOLING_N || _poolArgList[_size].size() > 32){
delete[] _args; delete[] _args;
}else{ }else{
for(uint8_t i = 0; i < _size; i++) _args[i].reset(); for(int i = 0; i < _size; i++) _args[i].reset();
_poolArgList[_size].push_back(_args); _poolArgList[_size].push_back(_args);
} }
} }
@ -2202,7 +2197,7 @@ namespace pkpy {
ArgList(const ArgList& other){ ArgList(const ArgList& other){
__tryAlloc(other._size); __tryAlloc(other._size);
for(uint8_t i=0; i<_size; i++) _args[i] = other._args[i]; for(int i=0; i<_size; i++) _args[i] = other._args[i];
} }
ArgList(ArgList&& other) noexcept { ArgList(ArgList&& other) noexcept {
@ -2214,39 +2209,36 @@ namespace pkpy {
ArgList(PyVarList&& other) noexcept { ArgList(PyVarList&& other) noexcept {
__tryAlloc(other.size()); __tryAlloc(other.size());
for(uint8_t i=0; i<_size; i++){ for(int i=0; i<_size; i++){
_args[i] = std::move(other[i]); _args[i] = std::move(other[i]);
} }
other.clear(); other.clear();
} }
PyVar& operator[](uint8_t i){ return _args[i]; } PyVar& operator[](int i){ return _args[i]; }
const PyVar& operator[](uint8_t i) const { return _args[i]; } const PyVar& operator[](int i) const { return _args[i]; }
// overload = for &&
ArgList& operator=(ArgList&& other) noexcept { ArgList& operator=(ArgList&& other) noexcept {
if(this != &other){ __tryRelease();
__tryRelease(); this->_args = other._args;
this->_args = other._args; this->_size = other._size;
this->_size = other._size; other._args = nullptr;
other._args = nullptr; other._size = 0;
other._size = 0;
}
return *this; return *this;
} }
inline uint8_t size() const { return _size; } inline int size() const { return _size; }
PyVarList toList() const { PyVarList toList() const {
PyVarList ret(_size); PyVarList ret(_size);
for(uint8_t i=0; i<_size; i++) ret[i] = _args[i]; for(int i=0; i<_size; i++) ret[i] = _args[i];
return ret; return ret;
} }
void extend_self(const PyVar& self){ void extend_self(const PyVar& self){
static_assert(std::is_standard_layout_v<PyVar>); static_assert(std::is_standard_layout_v<PyVar>);
PyVar* old_args = _args; PyVar* old_args = _args;
uint8_t old_size = _size; int old_size = _size;
__tryAlloc(old_size+1); __tryAlloc(old_size+1);
_args[0] = self; _args[0] = self;
if(old_size == 0) return; if(old_size == 0) return;
@ -3734,8 +3726,8 @@ public:
PyVar _module; PyVar _module;
pkpy::shared_ptr<PyVarDict> _locals; pkpy::shared_ptr<PyVarDict> _locals;
inline PyVarDict& f_locals(){ return *_locals; } inline PyVarDict& f_locals() noexcept { return *_locals; }
inline PyVarDict& f_globals(){ return _module->attribs; } inline PyVarDict& f_globals() noexcept { return _module->attribs; }
Frame(const _Code code, PyVar _module, pkpy::shared_ptr<PyVarDict> _locals) Frame(const _Code code, PyVar _module, pkpy::shared_ptr<PyVarDict> _locals)
: code(code), _module(_module), _locals(_locals) { : code(code), _module(_module), _locals(_locals) {
@ -3823,12 +3815,6 @@ public:
return v; return v;
} }
PyVarList pop_n_values_reversed_unlimited(VM* vm, int n){
PyVarList v(n);
for(int i=n-1; i>=0; i--) v[i] = pop_value(vm);
return v;
}
pkpy::ArgList pop_n_reversed(int n){ pkpy::ArgList pop_n_reversed(int n){
pkpy::ArgList v(n); pkpy::ArgList v(n);
for(int i=n-1; i>=0; i--) v[i] = pop(); for(int i=n-1; i>=0; i--) v[i] = pop();
@ -3855,7 +3841,6 @@ public:
class VM { class VM {
std::vector<PyVar> _small_integers; // [-5, 256] std::vector<PyVar> _small_integers; // [-5, 256]
emhash8::HashMap<_Str, _Str> _lazy_modules; // lazy loaded modules
protected: protected:
std::deque< std::unique_ptr<Frame> > callstack; std::deque< std::unique_ptr<Frame> > callstack;
PyVar __py2py_call_signal; PyVar __py2py_call_signal;
@ -4032,12 +4017,12 @@ protected:
case OP_BUILD_LIST: case OP_BUILD_LIST:
{ {
frame->push(PyList( frame->push(PyList(
frame->pop_n_values_reversed_unlimited(this, byte.arg) frame->pop_n_values_reversed(this, byte.arg).toList()
)); ));
} break; } break;
case OP_BUILD_MAP: case OP_BUILD_MAP:
{ {
PyVarList items = frame->pop_n_values_reversed_unlimited(this, byte.arg*2); pkpy::ArgList items = frame->pop_n_values_reversed(this, byte.arg*2);
PyVar obj = call(builtins->attribs["dict"]); PyVar obj = call(builtins->attribs["dict"]);
for(int i=0; i<items.size(); i+=2){ for(int i=0; i<items.size(); i+=2){
call(obj, __setitem__, pkpy::twoArgs(items[i], items[i+1])); call(obj, __setitem__, pkpy::twoArgs(items[i], items[i+1]));
@ -4047,7 +4032,7 @@ protected:
case OP_BUILD_SET: case OP_BUILD_SET:
{ {
PyVar list = PyList( PyVar list = PyList(
frame->pop_n_values_reversed_unlimited(this, byte.arg) frame->pop_n_values_reversed(this, byte.arg).toList()
); );
PyVar obj = call(builtins->attribs["set"], pkpy::oneArg(list)); PyVar obj = call(builtins->attribs["set"], pkpy::oneArg(list));
frame->push(obj); frame->push(obj);
@ -4143,7 +4128,7 @@ protected:
}else{ }else{
const _Str& source = it2->second; const _Str& source = it2->second;
_Code code = compile(source, name, EXEC_MODE); _Code code = compile(source, name, EXEC_MODE);
PyVar _m = newModule(name); PyVar _m = new_module(name);
_exec(code, _m, pkpy::make_shared<PyVarDict>()); _exec(code, _m, pkpy::make_shared<PyVarDict>());
frame->push(_m); frame->push(_m);
_lazy_modules.erase(it2); _lazy_modules.erase(it2);
@ -4173,6 +4158,7 @@ protected:
public: public:
PyVarDict _types; PyVarDict _types;
PyVarDict _modules; // loaded modules PyVarDict _modules; // loaded modules
emhash8::HashMap<_Str, _Str> _lazy_modules; // lazy loaded modules
PyVar None, True, False, Ellipsis; PyVar None, True, False, Ellipsis;
bool use_stdio; bool use_stdio;
@ -4222,8 +4208,8 @@ public:
} }
const PyVar& asBool(const PyVar& obj){ const PyVar& asBool(const PyVar& obj){
if(obj == None) return False;
if(obj->is_type(_tp_bool)) return obj; if(obj->is_type(_tp_bool)) return obj;
if(obj == None) return False;
if(obj->is_type(_tp_int)) return PyBool(PyInt_AS_C(obj) != 0); if(obj->is_type(_tp_int)) return PyBool(PyInt_AS_C(obj) != 0);
if(obj->is_type(_tp_float)) return PyBool(PyFloat_AS_C(obj) != 0.0); if(obj->is_type(_tp_float)) return PyBool(PyFloat_AS_C(obj) != 0.0);
PyVarOrNull len_fn = getattr(obj, __len__, false); PyVarOrNull len_fn = getattr(obj, __len__, false);
@ -4431,17 +4417,13 @@ public:
return new_object(T::_tp(this), T(std::forward<Args>(args)...)); return new_object(T::_tp(this), T(std::forward<Args>(args)...));
} }
PyVar newModule(_Str name) { PyVar new_module(_Str name) {
PyVar obj = new_object(_tp_module, (i64)-2); PyVar obj = new_object(_tp_module, DUMMY_VAL);
setattr(obj, __name__, PyStr(name)); setattr(obj, __name__, PyStr(name));
_modules[name] = obj; _modules[name] = obj;
return obj; return obj;
} }
void addLazyModule(_Str name, _Str source){
_lazy_modules[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) {
PyVarDict::iterator it; PyVarDict::iterator it;
PyObject* cls; PyObject* cls;
@ -4481,15 +4463,11 @@ public:
return nullptr; return nullptr;
} }
template<typename T>
void setattr(PyObject* obj, const _Str& name, T&& value) {
while(obj->is_type(_tp_super)) obj = ((Py_<PyVar>*)obj)->_valueT.get();
obj->attribs[name] = value;
}
template<typename T> template<typename T>
inline void setattr(PyVar& obj, const _Str& name, T&& value) { inline void setattr(PyVar& obj, const _Str& name, T&& value) {
setattr(obj.get(), name, value); PyObject* p = obj.get();
while(p->is_type(_tp_super)) p = ((Py_<PyVar>*)p)->_valueT.get();
p->attribs[name] = std::forward<T>(value);
} }
template<int ARGC> template<int ARGC>
@ -4523,14 +4501,6 @@ public:
bindFunc<ARGC>(builtins, funcName, fn); bindFunc<ARGC>(builtins, funcName, fn);
} }
inline bool is_int_or_float(const PyVar& obj) const{
return obj->is_type(_tp_int) || obj->is_type(_tp_float);
}
inline bool is_int_or_float(const PyVar& obj1, const PyVar& obj2) const{
return is_int_or_float(obj1) && is_int_or_float(obj2);
}
inline f64 num_to_float(const PyVar& obj){ inline f64 num_to_float(const PyVar& obj){
if (obj->is_type(_tp_int)){ if (obj->is_type(_tp_int)){
return (f64)PyInt_AS_C(obj); return (f64)PyInt_AS_C(obj);
@ -4693,8 +4663,8 @@ public:
this->Ellipsis = new_object(_types["ellipsis"], DUMMY_VAL); this->Ellipsis = new_object(_types["ellipsis"], DUMMY_VAL);
this->True = new_object(_tp_bool, true); this->True = new_object(_tp_bool, true);
this->False = new_object(_tp_bool, false); this->False = new_object(_tp_bool, false);
this->builtins = newModule("builtins"); this->builtins = new_module("builtins");
this->_main = newModule("__main__"); this->_main = new_module("__main__");
setattr(_tp_type, __base__, _tp_object); setattr(_tp_type, __base__, _tp_object);
_tp_type->_type = _tp_type; _tp_type->_type = _tp_type;
@ -5018,6 +4988,7 @@ public:
break; break;
} }
buff.push_back(c); buff.push_back(c);
continue;
} else { } else {
break; break;
} }
@ -6036,16 +6007,13 @@ __NOT_ENOUGH_LINES:
} }
try{ try{
vm->compile(line, "<stdin>", mode); vm->exec(line, "<stdin>", mode);
}catch(NeedMoreLines& ne){ }catch(NeedMoreLines& ne){
buffer += line; buffer += line;
buffer += '\n'; buffer += '\n';
need_more_lines = ne.isClassDef ? 3 : 2; need_more_lines = ne.isClassDef ? 3 : 2;
if (need_more_lines) return NEED_MORE_LINES; if (need_more_lines) return NEED_MORE_LINES;
}catch(...){
// do nothing
} }
vm->exec(line, "<stdin>", mode);
return EXEC_STARTED; return EXEC_STARTED;
} }
}; };
@ -6063,21 +6031,23 @@ _Code VM::compile(_Str source, _Str filename, CompileMode mode) {
} }
#define BIND_NUM_ARITH_OPT(name, op) \ #define BIND_NUM_ARITH_OPT(name, op) \
_vm->bindMethodMulti<1>({"int","float"}, #name, [](VM* vm, const pkpy::ArgList& args){ \ _vm->bindMethodMulti<1>({"int","float"}, #name, [](VM* vm, const pkpy::ArgList& args){ \
if(args[0]->is_type(vm->_tp_int) && args[1]->is_type(vm->_tp_int)){ \ if(args[0]->is_type(vm->_tp_int) && args[1]->is_type(vm->_tp_int)){ \
return vm->PyInt(vm->PyInt_AS_C(args[0]) op vm->PyInt_AS_C(args[1])); \ return vm->PyInt(vm->PyInt_AS_C(args[0]) op vm->PyInt_AS_C(args[1])); \
}else{ \ }else{ \
return vm->PyFloat(vm->num_to_float(args[0]) op vm->num_to_float(args[1])); \ return vm->PyFloat(vm->num_to_float(args[0]) op vm->num_to_float(args[1])); \
} \ } \
}); });
#define BIND_NUM_LOGICAL_OPT(name, op, is_eq) \ #define BIND_NUM_LOGICAL_OPT(name, op, is_eq) \
_vm->bindMethodMulti<1>({"int","float"}, #name, [](VM* vm, const pkpy::ArgList& args){ \ _vm->bindMethodMulti<1>({"int","float"}, #name, [](VM* vm, const pkpy::ArgList& args){ \
if(!vm->is_int_or_float(args[0], args[1])){ \ bool _0 = args[0]->is_type(vm->_tp_int) || args[0]->is_type(vm->_tp_float); \
bool _1 = args[1]->is_type(vm->_tp_int) || args[1]->is_type(vm->_tp_float); \
if(!_0 || !_1){ \
if constexpr(is_eq) return vm->PyBool(args[0] == args[1]); \ if constexpr(is_eq) return vm->PyBool(args[0] == args[1]); \
vm->typeError("unsupported operand type(s) for " #op ); \ vm->typeError("unsupported operand type(s) for " #op ); \
} \ } \
return vm->PyBool(vm->num_to_float(args[0]) op vm->num_to_float(args[1])); \ return vm->PyBool(vm->num_to_float(args[0]) op vm->num_to_float(args[1])); \
}); });
@ -6107,14 +6077,12 @@ void __initializeBuiltinFunctions(VM* _vm) {
}); });
_vm->bindBuiltinFunc<1>("eval", [](VM* vm, const pkpy::ArgList& args) { _vm->bindBuiltinFunc<1>("eval", [](VM* vm, const pkpy::ArgList& args) {
const _Str& expr = vm->PyStr_AS_C(args[0]); _Code code = vm->compile(vm->PyStr_AS_C(args[0]), "<eval>", EVAL_MODE);
_Code code = vm->compile(expr, "<eval>", EVAL_MODE);
return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals); return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
}); });
_vm->bindBuiltinFunc<1>("exec", [](VM* vm, const pkpy::ArgList& args) { _vm->bindBuiltinFunc<1>("exec", [](VM* vm, const pkpy::ArgList& args) {
const _Str& expr = vm->PyStr_AS_C(args[0]); _Code code = vm->compile(vm->PyStr_AS_C(args[0]), "<exec>", EXEC_MODE);
_Code code = vm->compile(expr, "<exec>", EXEC_MODE);
vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals); vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
return vm->None; return vm->None;
}); });
@ -6135,22 +6103,19 @@ void __initializeBuiltinFunctions(VM* _vm) {
return vm->PyInt((i64)s[0]); return vm->PyInt((i64)s[0]);
}); });
_vm->bindBuiltinFunc<0>("globals", [](VM* vm, const pkpy::ArgList& args) { _vm->bindBuiltinFunc<2>("hasattr", [](VM* vm, const pkpy::ArgList& args) {
const auto& d = vm->top_frame()->f_globals(); return vm->PyBool(vm->getattr(args[0], vm->PyStr_AS_C(args[1]), false) != nullptr);
PyVar obj = vm->call(vm->builtins->attribs["dict"]);
for (const auto& [k, v] : d) {
vm->call(obj, __setitem__, pkpy::twoArgs(vm->PyStr(k), v));
}
return obj;
}); });
_vm->bindBuiltinFunc<0>("locals", [](VM* vm, const pkpy::ArgList& args) { _vm->bindBuiltinFunc<3>("setattr", [](VM* vm, const pkpy::ArgList& args) {
const auto& d = vm->top_frame()->f_locals(); PyVar obj = args[0];
PyVar obj = vm->call(vm->builtins->attribs["dict"]); vm->setattr(obj, vm->PyStr_AS_C(args[1]), args[2]);
for (const auto& [k, v] : d) { return vm->None;
vm->call(obj, __setitem__, pkpy::twoArgs(vm->PyStr(k), v)); });
}
return obj; _vm->bindBuiltinFunc<2>("getattr", [](VM* vm, const pkpy::ArgList& args) {
_Str name = vm->PyStr_AS_C(args[1]);
return vm->getattr(args[0], name);
}); });
_vm->bindBuiltinFunc<1>("hex", [](VM* vm, const pkpy::ArgList& args) { _vm->bindBuiltinFunc<1>("hex", [](VM* vm, const pkpy::ArgList& args) {
@ -6554,7 +6519,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
void __addModuleTime(VM* vm){ void __addModuleTime(VM* vm){
PyVar mod = vm->newModule("time"); PyVar mod = vm->new_module("time");
vm->bindFunc<0>(mod, "time", [](VM* vm, const pkpy::ArgList& args) { vm->bindFunc<0>(mod, "time", [](VM* vm, const pkpy::ArgList& args) {
auto now = std::chrono::high_resolution_clock::now(); auto now = std::chrono::high_resolution_clock::now();
return vm->PyFloat(std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count() / 1000000.0); return vm->PyFloat(std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count() / 1000000.0);
@ -6562,7 +6527,7 @@ void __addModuleTime(VM* vm){
} }
void __addModuleSys(VM* vm){ void __addModuleSys(VM* vm){
PyVar mod = vm->newModule("sys"); PyVar mod = vm->new_module("sys");
vm->bindFunc<1>(mod, "getrefcount", [](VM* vm, const pkpy::ArgList& args) { vm->bindFunc<1>(mod, "getrefcount", [](VM* vm, const pkpy::ArgList& args) {
return vm->PyInt(args[0].use_count()); return vm->PyInt(args[0].use_count());
}); });
@ -6580,7 +6545,7 @@ void __addModuleSys(VM* vm){
} }
void __addModuleJson(VM* vm){ void __addModuleJson(VM* vm){
PyVar mod = vm->newModule("json"); PyVar mod = vm->new_module("json");
vm->bindFunc<1>(mod, "loads", [](VM* vm, const pkpy::ArgList& args) { vm->bindFunc<1>(mod, "loads", [](VM* vm, const pkpy::ArgList& args) {
const _Str& expr = vm->PyStr_AS_C(args[0]); const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = vm->compile(expr, "<json>", JSON_MODE); _Code code = vm->compile(expr, "<json>", JSON_MODE);
@ -6593,7 +6558,7 @@ void __addModuleJson(VM* vm){
} }
void __addModuleMath(VM* vm){ void __addModuleMath(VM* vm){
PyVar mod = vm->newModule("math"); PyVar mod = vm->new_module("math");
vm->setattr(mod, "pi", vm->PyFloat(3.1415926535897932384)); vm->setattr(mod, "pi", vm->PyFloat(3.1415926535897932384));
vm->setattr(mod, "e" , vm->PyFloat(2.7182818284590452354)); vm->setattr(mod, "e" , vm->PyFloat(2.7182818284590452354));
@ -6692,7 +6657,7 @@ PyVar __regex_search(const _Str& pattern, const _Str& string, bool fromStart, VM
}; };
void __addModuleRe(VM* vm){ void __addModuleRe(VM* vm){
PyVar mod = vm->newModule("re"); PyVar mod = vm->new_module("re");
ReMatch::_bind(vm); ReMatch::_bind(vm);
vm->bindFunc<2>(mod, "match", [](VM* vm, const pkpy::ArgList& args) { vm->bindFunc<2>(mod, "match", [](VM* vm, const pkpy::ArgList& args) {
@ -6828,7 +6793,7 @@ 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){ void pkpy_vm_add_module(VM* vm, const char* name, const char* source){
vm->addLazyModule(name, source); vm->_lazy_modules[name] = source;
} }
void __vm_init(VM* vm){ void __vm_init(VM* vm){

@ -1 +1 @@
Subproject commit 4bbbb85979391fd8b1aa349ad81d6527db069ab2 Subproject commit 67715ff019df22dc7a99a73352515eb7106b33b9