mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
...
This commit is contained in:
parent
fb5220a925
commit
0d227f85ad
@ -30,4 +30,11 @@ Delete a virtual machine.
|
|||||||
|
|
||||||
#### `void pkpy_delete_repl(REPL* repl)`
|
#### `void pkpy_delete_repl(REPL* repl)`
|
||||||
|
|
||||||
Delete a REPL.
|
Delete a REPL.
|
||||||
|
|
||||||
|
#### `void pkpy_vm_compile(VM* vm, const char* source, const char* filename, int mode, bool* ok, char* res)`
|
||||||
|
|
||||||
|
Compile a source into bytecode and serialize it into a string.
|
||||||
|
|
||||||
|
+ `ok`: whether the compilation is successful.
|
||||||
|
+ `res`: if `ok` is true, `res` is the bytecode string, otherwise it is the error message.
|
@ -24,3 +24,7 @@ A wrapper of `OP_LOAD_ATTR` bytecode.
|
|||||||
#### `bool pkpy_setattr(pkpy_vm*, const char* name)`
|
#### `bool pkpy_setattr(pkpy_vm*, const char* name)`
|
||||||
|
|
||||||
A wrapper of `OP_STORE_ATTR` bytecode.
|
A wrapper of `OP_STORE_ATTR` bytecode.
|
||||||
|
|
||||||
|
#### `bool pkpy_eval(pkpy_vm*, const char* code)`
|
||||||
|
|
||||||
|
Evaluate the code and push the result to the top of the stack.
|
159
src/codeobject.h
159
src/codeobject.h
@ -47,6 +47,87 @@ struct CodeBlock {
|
|||||||
type(type), parent(parent), for_loop_depth(for_loop_depth), start(start), end(-1) {}
|
type(type), parent(parent), for_loop_depth(for_loop_depth), start(start), end(-1) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct CodeObjectSerializer{
|
||||||
|
std::string buffer;
|
||||||
|
int depth = 0;
|
||||||
|
|
||||||
|
std::set<StrName> names;
|
||||||
|
|
||||||
|
static const char END = '\n';
|
||||||
|
|
||||||
|
CodeObjectSerializer(){
|
||||||
|
write_str(PK_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_int(i64 v){
|
||||||
|
buffer += 'i';
|
||||||
|
buffer += std::to_string(v);
|
||||||
|
buffer += END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_float(f64 v){
|
||||||
|
buffer += 'f';
|
||||||
|
buffer += std::to_string(v);
|
||||||
|
buffer += END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_str(const Str& v){
|
||||||
|
buffer += 's';
|
||||||
|
buffer += v.escape(false).str();
|
||||||
|
buffer += END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_bool(bool v){
|
||||||
|
buffer += 'b';
|
||||||
|
buffer += v ? '1' : '0';
|
||||||
|
buffer += END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_begin_mark(){
|
||||||
|
buffer += '[';
|
||||||
|
buffer += END;
|
||||||
|
depth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_name(StrName name){
|
||||||
|
PK_ASSERT(StrName::is_valid(name.index));
|
||||||
|
buffer += 'n';
|
||||||
|
buffer += std::to_string(name.index);
|
||||||
|
buffer += END;
|
||||||
|
names.insert(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_end_mark(){
|
||||||
|
buffer += ']';
|
||||||
|
buffer += END;
|
||||||
|
depth--;
|
||||||
|
PK_ASSERT(depth >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void write_bytes(T v){
|
||||||
|
static_assert(std::is_trivially_copyable<T>::value);
|
||||||
|
buffer += 'm';
|
||||||
|
buffer.append((const char*)&v, sizeof(T));
|
||||||
|
buffer += END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_object(VM* vm, PyObject* obj);
|
||||||
|
void write_code(VM* vm, const CodeObject* co);
|
||||||
|
|
||||||
|
std::string str(){
|
||||||
|
PK_ASSERT(depth == 0);
|
||||||
|
for(auto name: names){
|
||||||
|
PK_ASSERT(StrName::is_valid(name.index));
|
||||||
|
write_name(name);
|
||||||
|
write_str(name.sv());
|
||||||
|
}
|
||||||
|
return std::move(buffer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct CodeObject {
|
struct CodeObject {
|
||||||
shared_ptr<SourceData> src;
|
shared_ptr<SourceData> src;
|
||||||
Str name;
|
Str name;
|
||||||
@ -68,6 +149,84 @@ struct CodeObject {
|
|||||||
for(PyObject* v : consts) OBJ_MARK(v);
|
for(PyObject* v : consts) OBJ_MARK(v);
|
||||||
for(auto& decl: func_decls) decl->_gc_mark();
|
for(auto& decl: func_decls) decl->_gc_mark();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void write(VM* vm, CodeObjectSerializer& ss) const{
|
||||||
|
ss.write_begin_mark(); // [
|
||||||
|
ss.write_str(src->source); // src->source
|
||||||
|
ss.write_str(src->filename); // src->filename
|
||||||
|
ss.write_int(src->mode); // src->mode
|
||||||
|
ss.write_end_mark(); // ]
|
||||||
|
ss.write_str(name); // name
|
||||||
|
ss.write_bool(is_generator); // is_generator
|
||||||
|
ss.write_begin_mark(); // [
|
||||||
|
for(Bytecode bc: codes){
|
||||||
|
if(StrName::is_valid(bc.arg)){
|
||||||
|
// std::cout << bc.arg << StrName(bc.arg).sv() << std::endl;
|
||||||
|
ss.names.insert(StrName(bc.arg));
|
||||||
|
}
|
||||||
|
ss.write_bytes(bc);
|
||||||
|
}
|
||||||
|
ss.write_end_mark(); // ]
|
||||||
|
ss.write_begin_mark(); // [
|
||||||
|
for(int line: lines){
|
||||||
|
ss.write_int(line); // line
|
||||||
|
}
|
||||||
|
ss.write_end_mark(); // ]
|
||||||
|
ss.write_begin_mark(); // [
|
||||||
|
for(PyObject* o: consts){
|
||||||
|
ss.write_object(vm, o);
|
||||||
|
}
|
||||||
|
ss.write_end_mark(); // ]
|
||||||
|
ss.write_begin_mark(); // [
|
||||||
|
for(StrName name: varnames){
|
||||||
|
ss.write_name(name); // name
|
||||||
|
}
|
||||||
|
ss.write_end_mark(); // ]
|
||||||
|
ss.write_begin_mark(); // [
|
||||||
|
for(CodeBlock block: blocks){
|
||||||
|
ss.write_bytes(block); // block
|
||||||
|
}
|
||||||
|
ss.write_end_mark(); // ]
|
||||||
|
ss.write_begin_mark(); // [
|
||||||
|
for(auto& label: labels.items()){
|
||||||
|
ss.write_name(label.first); // label.first
|
||||||
|
ss.write_int(label.second); // label.second
|
||||||
|
}
|
||||||
|
ss.write_end_mark(); // ]
|
||||||
|
ss.write_begin_mark(); // [
|
||||||
|
for(auto& decl: func_decls){
|
||||||
|
ss.write_code(vm, decl->code.get()); // decl->code
|
||||||
|
ss.write_begin_mark(); // [
|
||||||
|
for(int arg: decl->args) ss.write_int(arg);
|
||||||
|
ss.write_end_mark(); // ]
|
||||||
|
|
||||||
|
ss.write_begin_mark(); // [
|
||||||
|
for(auto kw: decl->kwargs){
|
||||||
|
ss.write_int(kw.key); // kw.key
|
||||||
|
ss.write_object(vm, kw.value); // kw.value
|
||||||
|
}
|
||||||
|
ss.write_end_mark(); // ]
|
||||||
|
|
||||||
|
ss.write_int(decl->starred_arg);
|
||||||
|
ss.write_int(decl->starred_kwarg);
|
||||||
|
ss.write_bool(decl->nested);
|
||||||
|
}
|
||||||
|
ss.write_end_mark(); // ]
|
||||||
|
}
|
||||||
|
|
||||||
|
Str serialize(VM* vm) const{
|
||||||
|
CodeObjectSerializer ss;
|
||||||
|
ss.write_code(vm, this);
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void CodeObjectSerializer::write_code(VM* vm, const CodeObject* co){
|
||||||
|
buffer += '(';
|
||||||
|
buffer += END;
|
||||||
|
co->write(vm, *this);
|
||||||
|
buffer += ')';
|
||||||
|
buffer += END;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
@ -1329,19 +1329,27 @@ inline void add_module_traceback(VM* vm){
|
|||||||
|
|
||||||
inline void add_module_dis(VM* vm){
|
inline void add_module_dis(VM* vm){
|
||||||
PyObject* mod = vm->new_module("dis");
|
PyObject* mod = vm->new_module("dis");
|
||||||
vm->bind_func<1>(mod, "dis", [](VM* vm, ArgsView args) {
|
|
||||||
if(is_type(args[0], vm->tp_str)){
|
static const auto get_code = [](VM* vm, PyObject* obj)->CodeObject_{
|
||||||
const Str& source = CAST(Str, args[0]);
|
if(is_type(obj, vm->tp_str)){
|
||||||
CodeObject_ code = vm->compile(source, "<dis>", EXEC_MODE);
|
const Str& source = CAST(Str, obj);
|
||||||
vm->_stdout(vm, vm->disassemble(code));
|
return vm->compile(source, "<dis>", EXEC_MODE);
|
||||||
return vm->None;
|
|
||||||
}
|
}
|
||||||
PyObject* f = args[0];
|
PyObject* f = obj;
|
||||||
if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, args[0]).func;
|
if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, obj).func;
|
||||||
CodeObject_ code = CAST(Function&, f).decl->code;
|
return CAST(Function&, f).decl->code;
|
||||||
|
};
|
||||||
|
|
||||||
|
vm->bind_func<1>(mod, "dis", [](VM* vm, ArgsView args) {
|
||||||
|
CodeObject_ code = get_code(vm, args[0]);
|
||||||
vm->_stdout(vm, vm->disassemble(code));
|
vm->_stdout(vm, vm->disassemble(code));
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
vm->bind_func<1>(mod, "_s", [](VM* vm, ArgsView args) {
|
||||||
|
CodeObject_ code = get_code(vm, args[0]);
|
||||||
|
return VAR(code->serialize(vm));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void add_module_gc(VM* vm){
|
inline void add_module_gc(VM* vm){
|
||||||
@ -1454,6 +1462,21 @@ extern "C" {
|
|||||||
vm->exec(source, filename, (pkpy::CompileMode)mode, mod);
|
vm->exec(source, filename, (pkpy::CompileMode)mode, mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PK_LEGACY_EXPORT
|
||||||
|
void pkpy_vm_compile(pkpy::VM* vm, const char* source, const char* filename, int mode, bool* ok, char* res){
|
||||||
|
try{
|
||||||
|
pkpy::CodeObject_ code = vm->compile(source, filename, (pkpy::CompileMode)mode);
|
||||||
|
res = code->serialize(vm).c_str_dup();
|
||||||
|
*ok = true;
|
||||||
|
}catch(pkpy::Exception& e){
|
||||||
|
*ok = false;
|
||||||
|
res = e.summary().c_str_dup();
|
||||||
|
}catch(...){
|
||||||
|
*ok = false;
|
||||||
|
res = strdup("unknown error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PK_LEGACY_EXPORT
|
PK_LEGACY_EXPORT
|
||||||
pkpy::REPL* pkpy_new_repl(pkpy::VM* vm){
|
pkpy::REPL* pkpy_new_repl(pkpy::VM* vm){
|
||||||
pkpy::REPL* p = new pkpy::REPL(vm);
|
pkpy::REPL* p = new pkpy::REPL(vm);
|
||||||
|
@ -355,6 +355,11 @@ struct StrName {
|
|||||||
return os << sn.sv();
|
return os << sn.sv();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_valid(int index) {
|
||||||
|
// check _r_interned[index-1] is valid
|
||||||
|
return index > 0 && index <= _r_interned.size();
|
||||||
|
}
|
||||||
|
|
||||||
Str escape() const {
|
Str escape() const {
|
||||||
return _r_interned[index-1].escape();
|
return _r_interned[index-1].escape();
|
||||||
}
|
}
|
||||||
|
7
src/vm.h
7
src/vm.h
@ -1564,4 +1564,11 @@ inline void Dict::_probe(PyObject *key, bool &ok, int &i) const{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void CodeObjectSerializer::write_object(VM *vm, PyObject *obj){
|
||||||
|
buffer += 'o';
|
||||||
|
PyObject* s = vm->py_repr(obj);
|
||||||
|
write_str(CAST(Str&, s));
|
||||||
|
buffer += END;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
Loading…
x
Reference in New Issue
Block a user