mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
up
This commit is contained in:
parent
981fcbc8e5
commit
730201907c
190
src/codeobject.h
190
src/codeobject.h
@ -20,7 +20,7 @@ struct Bytecode{
|
|||||||
uint8_t op;
|
uint8_t op;
|
||||||
int arg;
|
int arg;
|
||||||
int line;
|
int line;
|
||||||
uint16_t block; // the block id of this bytecode
|
uint16_t block;
|
||||||
};
|
};
|
||||||
|
|
||||||
_Str pad(const _Str& s, const int n){
|
_Str pad(const _Str& s, const int n){
|
||||||
@ -38,100 +38,69 @@ enum CodeBlockType {
|
|||||||
|
|
||||||
struct CodeBlock {
|
struct CodeBlock {
|
||||||
CodeBlockType type;
|
CodeBlockType type;
|
||||||
std::vector<int> id;
|
int parent; // parent index in blocks
|
||||||
int parent; // parent index in co_blocks
|
|
||||||
|
|
||||||
int start; // start index of this block in co_code, inclusive
|
int start; // start index of this block in co_code, inclusive
|
||||||
int end; // end index of this block in co_code, exclusive
|
int end; // end index of this block in co_code, exclusive
|
||||||
|
|
||||||
std::string to_string() const {
|
std::string to_string() const {
|
||||||
if(parent == -1) return "";
|
if(parent == -1) return "";
|
||||||
std::string s = "[";
|
return "[B:" + std::to_string(type) + "]";
|
||||||
for(int i = 0; i < id.size(); i++){
|
|
||||||
s += std::to_string(id[i]);
|
|
||||||
if(i != id.size()-1) s += "-";
|
|
||||||
}
|
|
||||||
s += ": type=";
|
|
||||||
s += std::to_string(type);
|
|
||||||
s += "]";
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const std::vector<int>& other) const{ return id == other; }
|
|
||||||
bool operator!=(const std::vector<int>& other) const{ return id != other; }
|
|
||||||
int depth() const{ return id.size(); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CodeObject {
|
struct CodeObject {
|
||||||
_Source src;
|
pkpy::shared_ptr<SourceData> src;
|
||||||
_Str name;
|
_Str name;
|
||||||
|
|
||||||
CodeObject(_Source src, _Str name) {
|
CodeObject(pkpy::shared_ptr<SourceData> src, _Str name) {
|
||||||
this->src = src;
|
this->src = src;
|
||||||
this->name = name;
|
this->name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Bytecode> co_code;
|
std::vector<Bytecode> co_code;
|
||||||
PyVarList co_consts;
|
PyVarList consts;
|
||||||
std::vector<std::pair<_Str, NameScope>> co_names;
|
std::vector<std::pair<_Str, NameScope>> names;
|
||||||
std::vector<_Str> co_global_names;
|
emhash8::HashMap<_Str, int> global_names;
|
||||||
|
std::vector<CodeBlock> blocks = { CodeBlock{NO_BLOCK, {}, -1} };
|
||||||
std::vector<CodeBlock> co_blocks = { CodeBlock{NO_BLOCK, {}, -1} };
|
emhash8::HashMap<_Str, int> labels;
|
||||||
|
|
||||||
// tmp variables
|
// tmp variables
|
||||||
int _currBlockIndex = 0;
|
int _curr_block_i = 0;
|
||||||
bool __isCurrBlockLoop() const {
|
bool __is_curr_block_loop() const {
|
||||||
return co_blocks[_currBlockIndex].type == FOR_LOOP || co_blocks[_currBlockIndex].type == WHILE_LOOP;
|
return blocks[_curr_block_i].type == FOR_LOOP || blocks[_curr_block_i].type == WHILE_LOOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __enter_block(CodeBlockType type){
|
void __enter_block(CodeBlockType type){
|
||||||
const CodeBlock& currBlock = co_blocks[_currBlockIndex];
|
const CodeBlock& currBlock = blocks[_curr_block_i];
|
||||||
std::vector<int> copy(currBlock.id);
|
blocks.push_back(CodeBlock{type, _curr_block_i, (int)co_code.size()});
|
||||||
copy.push_back(-1);
|
_curr_block_i = blocks.size()-1;
|
||||||
int t = 0;
|
|
||||||
while(true){
|
|
||||||
copy[copy.size()-1] = t;
|
|
||||||
auto it = std::find(co_blocks.begin(), co_blocks.end(), copy);
|
|
||||||
if(it == co_blocks.end()) break;
|
|
||||||
t++;
|
|
||||||
}
|
|
||||||
co_blocks.push_back(CodeBlock{type, copy, _currBlockIndex, (int)co_code.size()});
|
|
||||||
_currBlockIndex = co_blocks.size()-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __exit_block(){
|
void __exit_block(){
|
||||||
co_blocks[_currBlockIndex].end = co_code.size();
|
blocks[_curr_block_i].end = co_code.size();
|
||||||
_currBlockIndex = co_blocks[_currBlockIndex].parent;
|
_curr_block_i = blocks[_curr_block_i].parent;
|
||||||
if(_currBlockIndex < 0) UNREACHABLE();
|
if(_curr_block_i < 0) UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
// for goto use
|
bool add_label(const _Str& label){
|
||||||
// goto/label should be put at toplevel statements
|
if(labels.contains(label)) return false;
|
||||||
emhash8::HashMap<_Str, int> co_labels;
|
labels[label] = co_code.size();
|
||||||
|
return true;
|
||||||
void add_label(const _Str& label){
|
|
||||||
if(co_labels.find(label) != co_labels.end()){
|
|
||||||
_Str msg = "label '" + label + "' already exists";
|
|
||||||
throw std::runtime_error(msg.c_str());
|
|
||||||
}
|
|
||||||
co_labels[label] = co_code.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int add_name(_Str name, NameScope scope){
|
int add_name(_Str name, NameScope scope){
|
||||||
if(scope == NAME_LOCAL && std::find(co_global_names.begin(), co_global_names.end(), name) != co_global_names.end()){
|
if(scope == NAME_LOCAL && global_names.contains(name)) scope = NAME_GLOBAL;
|
||||||
scope = NAME_GLOBAL;
|
|
||||||
}
|
|
||||||
auto p = std::make_pair(name, scope);
|
auto p = std::make_pair(name, scope);
|
||||||
for(int i=0; i<co_names.size(); i++){
|
for(int i=0; i<names.size(); i++){
|
||||||
if(co_names[i] == p) return i;
|
if(names[i] == p) return i;
|
||||||
}
|
}
|
||||||
co_names.push_back(p);
|
names.push_back(p);
|
||||||
return co_names.size() - 1;
|
return names.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int add_const(PyVar v){
|
int add_const(PyVar v){
|
||||||
co_consts.push_back(v);
|
consts.push_back(v);
|
||||||
return co_consts.size() - 1;
|
return consts.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void optimize_level_1(){
|
void optimize_level_1(){
|
||||||
@ -170,63 +139,61 @@ struct CodeObject {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Frame {
|
struct Frame {
|
||||||
private:
|
std::vector<PyVar> _data;
|
||||||
std::vector<PyVar> s_data;
|
int _ip = -1;
|
||||||
int ip = -1;
|
int _next_ip = 0;
|
||||||
int next_ip = 0;
|
|
||||||
int m_id;
|
const _Code co;
|
||||||
public:
|
|
||||||
const _Code code;
|
|
||||||
PyVar _module;
|
PyVar _module;
|
||||||
pkpy::shared_ptr<PyVarDict> _locals;
|
pkpy::shared_ptr<PyVarDict> _locals;
|
||||||
|
i64 _id;
|
||||||
|
|
||||||
inline PyVarDict& f_locals() noexcept { return *_locals; }
|
inline PyVarDict& f_locals() noexcept { return *_locals; }
|
||||||
inline PyVarDict& f_globals() noexcept { return _module->attribs; }
|
inline PyVarDict& f_globals() noexcept { return _module->attribs; }
|
||||||
|
|
||||||
inline i64 id() const noexcept { return m_id; }
|
Frame(const _Code co, PyVar _module, pkpy::shared_ptr<PyVarDict> _locals)
|
||||||
|
: co(co), _module(_module), _locals(_locals) {
|
||||||
Frame(const _Code code, PyVar _module, pkpy::shared_ptr<PyVarDict> _locals)
|
static thread_local i64 kGlobalId = 0;
|
||||||
: code(code), _module(_module), _locals(_locals) {
|
_id = kGlobalId++;
|
||||||
static thread_local i64 _id = 0;
|
|
||||||
m_id = _id++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const Bytecode& next_bytecode() {
|
inline const Bytecode& next_bytecode() {
|
||||||
ip = next_ip;
|
_ip = _next_ip;
|
||||||
next_ip = ip + 1;
|
_next_ip = _ip + 1;
|
||||||
return code->co_code[ip];
|
return co->co_code[_ip];
|
||||||
}
|
}
|
||||||
|
|
||||||
_Str curr_snapshot(){
|
_Str curr_snapshot(){
|
||||||
int line = code->co_code[ip].line;
|
int line = co->co_code[_ip].line;
|
||||||
return code->src->snapshot(line);
|
return co->src->snapshot(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int stack_size() const{ return s_data.size(); }
|
|
||||||
_Str stack_info(){
|
_Str stack_info(){
|
||||||
_StrStream ss;
|
_StrStream ss;
|
||||||
ss << "[";
|
ss << "[";
|
||||||
for(int i=0; i<s_data.size(); i++){
|
for(int i=0; i<_data.size(); i++){
|
||||||
ss << UNION_TP_NAME(s_data[i]);
|
ss << UNION_TP_NAME(_data[i]);
|
||||||
if(i != s_data.size()-1) ss << ", ";
|
if(i != _data.size()-1) ss << ", ";
|
||||||
}
|
}
|
||||||
ss << "]";
|
ss << "]";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool has_next_bytecode() const{ return next_ip < code->co_code.size(); }
|
inline bool has_next_bytecode() const {
|
||||||
|
return _next_ip < co->co_code.size();
|
||||||
|
}
|
||||||
|
|
||||||
inline PyVar pop(){
|
inline PyVar pop(){
|
||||||
if(s_data.empty()) throw std::runtime_error("s_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
PyVar v = std::move(s_data.back());
|
PyVar v = std::move(_data.back());
|
||||||
s_data.pop_back();
|
_data.pop_back();
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void __pop(){
|
inline void __pop(){
|
||||||
if(s_data.empty()) throw std::runtime_error("s_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
s_data.pop_back();
|
_data.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void try_deref(VM*, PyVar&);
|
inline void try_deref(VM*, PyVar&);
|
||||||
@ -244,73 +211,68 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar& top(){
|
inline PyVar& top(){
|
||||||
if(s_data.empty()) throw std::runtime_error("s_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
return s_data.back();
|
return _data.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar top_value_offset(VM* vm, int n){
|
inline PyVar top_value_offset(VM* vm, int n){
|
||||||
PyVar value = s_data[s_data.size() + n];
|
PyVar value = _data[_data.size() + n];
|
||||||
try_deref(vm, value);
|
try_deref(vm, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void push(T&& obj){ s_data.push_back(std::forward<T>(obj)); }
|
inline void push(T&& obj){ _data.push_back(std::forward<T>(obj)); }
|
||||||
|
|
||||||
inline void jump_abs(int i){ next_ip = i; }
|
inline void jump_abs(int i){ _next_ip = i; }
|
||||||
inline void jump_rel(int i){ next_ip += i; }
|
inline void jump_rel(int i){ _next_ip += i; }
|
||||||
|
|
||||||
std::stack<std::pair<int, std::vector<PyVar>>> s_try_block;
|
std::stack<std::pair<int, std::vector<PyVar>>> s_try_block;
|
||||||
|
|
||||||
inline void on_try_block_enter(){
|
inline void on_try_block_enter(){
|
||||||
s_try_block.push(std::make_pair(code->co_code[ip].block, s_data));
|
s_try_block.push(std::make_pair(co->co_code[_ip].block, _data));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void on_try_block_exit(){
|
inline void on_try_block_exit(){
|
||||||
s_try_block.pop();
|
s_try_block.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int get_ip() const{ return ip; }
|
|
||||||
|
|
||||||
bool jump_to_exception_handler(){
|
bool jump_to_exception_handler(){
|
||||||
if(s_try_block.empty()) return false;
|
if(s_try_block.empty()) return false;
|
||||||
PyVar obj = pop();
|
PyVar obj = pop();
|
||||||
auto& p = s_try_block.top();
|
auto& p = s_try_block.top();
|
||||||
s_data = std::move(p.second);
|
_data = std::move(p.second);
|
||||||
s_data.push_back(obj);
|
_data.push_back(obj);
|
||||||
next_ip = code->co_blocks[p.first].end;
|
_next_ip = co->blocks[p.first].end;
|
||||||
on_try_block_exit();
|
on_try_block_exit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void jump_abs_safe(int target){
|
void jump_abs_safe(int target){
|
||||||
const Bytecode& prev = code->co_code[ip];
|
const Bytecode& prev = co->co_code[_ip];
|
||||||
int i = prev.block;
|
int i = prev.block;
|
||||||
next_ip = target;
|
_next_ip = target;
|
||||||
if(next_ip >= code->co_code.size()){
|
if(_next_ip >= co->co_code.size()){
|
||||||
while(i>=0){
|
while(i>=0){
|
||||||
if(code->co_blocks[i].type == FOR_LOOP) pop();
|
if(co->blocks[i].type == FOR_LOOP) pop();
|
||||||
i = code->co_blocks[i].parent;
|
i = co->blocks[i].parent;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
const Bytecode& next = code->co_code[target];
|
const Bytecode& next = co->co_code[target];
|
||||||
while(i>=0 && i!=next.block){
|
while(i>=0 && i!=next.block){
|
||||||
if(code->co_blocks[i].type == FOR_LOOP) pop();
|
if(co->blocks[i].type == FOR_LOOP) pop();
|
||||||
i = code->co_blocks[i].parent;
|
i = co->blocks[i].parent;
|
||||||
}
|
}
|
||||||
if(i!=next.block) throw std::runtime_error("invalid jump");
|
if(i!=next.block) throw std::runtime_error("invalid jump");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pkpy::Args pop_n_values_reversed(VM* vm, int n){
|
pkpy::Args pop_n_values_reversed(VM* vm, int n){
|
||||||
int new_size = s_data.size() - n;
|
|
||||||
if(new_size < 0) throw std::runtime_error("stack_size() < n");
|
|
||||||
pkpy::Args v(n);
|
pkpy::Args v(n);
|
||||||
for(int i=n-1; i>=0; i--){
|
for(int i=n-1; i>=0; i--){
|
||||||
v[i] = std::move(s_data[new_size + i]);
|
v[i] = pop();
|
||||||
try_deref(vm, v[i]);
|
try_deref(vm, v[i]);
|
||||||
}
|
}
|
||||||
s_data.resize(new_size);
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +17,7 @@ struct GrammarRule{
|
|||||||
|
|
||||||
enum StringType { NORMAL_STRING, RAW_STRING, F_STRING };
|
enum StringType { NORMAL_STRING, RAW_STRING, F_STRING };
|
||||||
|
|
||||||
class Compiler {
|
struct Compiler {
|
||||||
public:
|
|
||||||
std::unique_ptr<Parser> parser;
|
std::unique_ptr<Parser> parser;
|
||||||
std::stack<_Code> codes;
|
std::stack<_Code> codes;
|
||||||
bool isCompilingClass = false;
|
bool isCompilingClass = false;
|
||||||
@ -32,7 +31,7 @@ public:
|
|||||||
Compiler(VM* vm, const char* source, _Str filename, CompileMode mode){
|
Compiler(VM* vm, const char* source, _Str filename, CompileMode mode){
|
||||||
this->vm = vm;
|
this->vm = vm;
|
||||||
this->parser = std::make_unique<Parser>(
|
this->parser = std::make_unique<Parser>(
|
||||||
pkpy::make_shared<SourceMetadata>(source, filename, mode)
|
pkpy::make_shared<SourceData>(source, filename, mode)
|
||||||
);
|
);
|
||||||
|
|
||||||
// http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
|
// http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
|
||||||
@ -665,7 +664,7 @@ __LISTCOMP:
|
|||||||
int emit(Opcode opcode, int arg=-1, bool keepline=false) {
|
int emit(Opcode opcode, int arg=-1, bool keepline=false) {
|
||||||
int line = parser->prev.line;
|
int line = parser->prev.line;
|
||||||
co()->co_code.push_back(
|
co()->co_code.push_back(
|
||||||
Bytecode{(uint8_t)opcode, arg, line, (uint16_t)co()->_currBlockIndex}
|
Bytecode{(uint8_t)opcode, arg, line, (uint16_t)co()->_curr_block_i}
|
||||||
);
|
);
|
||||||
int i = co()->co_code.size() - 1;
|
int i = co()->co_code.size() - 1;
|
||||||
if(keepline && i>=1) co()->co_code[i].line = co()->co_code[i-1].line;
|
if(keepline && i>=1) co()->co_code[i].line = co()->co_code[i-1].line;
|
||||||
@ -808,31 +807,34 @@ __LISTCOMP:
|
|||||||
emit(OP_TRY_BLOCK_ENTER);
|
emit(OP_TRY_BLOCK_ENTER);
|
||||||
compileBlockBody();
|
compileBlockBody();
|
||||||
emit(OP_TRY_BLOCK_EXIT);
|
emit(OP_TRY_BLOCK_EXIT);
|
||||||
int patch = emit(OP_JUMP_ABSOLUTE);
|
std::vector<int> patches = { emit(OP_JUMP_ABSOLUTE) };
|
||||||
co()->__exit_block();
|
co()->__exit_block();
|
||||||
consume(TK("except"));
|
|
||||||
if(match(TK("@id"))){
|
do {
|
||||||
int name_idx = co()->add_name(parser->prev.str(), NAME_SPECIAL);
|
consume(TK("except"));
|
||||||
emit(OP_EXCEPTION_MATCH, name_idx);
|
if(match(TK("@id"))){
|
||||||
}else{
|
int name_idx = co()->add_name(parser->prev.str(), NAME_SPECIAL);
|
||||||
emit(OP_LOAD_TRUE);
|
emit(OP_EXCEPTION_MATCH, name_idx);
|
||||||
}
|
}else{
|
||||||
int patch_2 = emit(OP_POP_JUMP_IF_FALSE);
|
emit(OP_LOAD_TRUE);
|
||||||
emit(OP_POP_TOP); // pop the exception on match
|
}
|
||||||
compileBlockBody();
|
int patch = emit(OP_POP_JUMP_IF_FALSE);
|
||||||
emit(OP_JUMP_RELATIVE, 1);
|
emit(OP_POP_TOP); // pop the exception on match
|
||||||
patch_jump(patch_2);
|
compileBlockBody();
|
||||||
|
patches.push_back(emit(OP_JUMP_ABSOLUTE));
|
||||||
|
patch_jump(patch);
|
||||||
|
}while(peek() == TK("except"));
|
||||||
emit(OP_RE_RAISE); // no match, re-raise
|
emit(OP_RE_RAISE); // no match, re-raise
|
||||||
patch_jump(patch);
|
for (int patch : patches) patch_jump(patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compileStatement() {
|
void compileStatement() {
|
||||||
if (match(TK("break"))) {
|
if (match(TK("break"))) {
|
||||||
if (!co()->__isCurrBlockLoop()) syntaxError("'break' outside loop");
|
if (!co()->__is_curr_block_loop()) syntaxError("'break' outside loop");
|
||||||
consumeEndStatement();
|
consumeEndStatement();
|
||||||
emit(OP_LOOP_BREAK);
|
emit(OP_LOOP_BREAK);
|
||||||
} else if (match(TK("continue"))) {
|
} else if (match(TK("continue"))) {
|
||||||
if (!co()->__isCurrBlockLoop()) syntaxError("'continue' not properly in loop");
|
if (!co()->__is_curr_block_loop()) syntaxError("'continue' not properly in loop");
|
||||||
consumeEndStatement();
|
consumeEndStatement();
|
||||||
emit(OP_LOOP_CONTINUE);
|
emit(OP_LOOP_CONTINUE);
|
||||||
} else if (match(TK("return"))) {
|
} else if (match(TK("return"))) {
|
||||||
@ -875,7 +877,9 @@ __LISTCOMP:
|
|||||||
} else if(match(TK("label"))){
|
} else if(match(TK("label"))){
|
||||||
if(mode() != EXEC_MODE) syntaxError("'label' is only available in EXEC_MODE");
|
if(mode() != EXEC_MODE) syntaxError("'label' is only available in EXEC_MODE");
|
||||||
consume(TK(".")); consume(TK("@id"));
|
consume(TK(".")); consume(TK("@id"));
|
||||||
co()->add_label(parser->prev.str());
|
_Str label = parser->prev.str();
|
||||||
|
bool ok = co()->add_label(label);
|
||||||
|
if(!ok) syntaxError("label '" + label + "' already exists");
|
||||||
consumeEndStatement();
|
consumeEndStatement();
|
||||||
} else if(match(TK("goto"))){ // https://entrian.com/goto/
|
} else if(match(TK("goto"))){ // https://entrian.com/goto/
|
||||||
if(mode() != EXEC_MODE) syntaxError("'goto' is only available in EXEC_MODE");
|
if(mode() != EXEC_MODE) syntaxError("'goto' is only available in EXEC_MODE");
|
||||||
@ -899,7 +903,7 @@ __LISTCOMP:
|
|||||||
} else if(match(TK("global"))){
|
} else if(match(TK("global"))){
|
||||||
do {
|
do {
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
co()->co_global_names.push_back(parser->prev.str());
|
co()->global_names[parser->prev.str()] = 1;
|
||||||
} while (match(TK(",")));
|
} while (match(TK(",")));
|
||||||
consumeEndStatement();
|
consumeEndStatement();
|
||||||
} else if(match(TK("pass"))){
|
} else if(match(TK("pass"))){
|
||||||
|
@ -17,7 +17,7 @@ enum CompileMode {
|
|||||||
JSON_MODE,
|
JSON_MODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SourceMetadata {
|
struct SourceData {
|
||||||
const char* source;
|
const char* source;
|
||||||
_Str filename;
|
_Str filename;
|
||||||
std::vector<const char*> lineStarts;
|
std::vector<const char*> lineStarts;
|
||||||
@ -33,7 +33,7 @@ struct SourceMetadata {
|
|||||||
return {_start, i};
|
return {_start, i};
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceMetadata(const char* source, _Str filename, CompileMode mode) {
|
SourceData(const char* source, _Str filename, CompileMode mode) {
|
||||||
source = strdup(source);
|
source = strdup(source);
|
||||||
// Skip utf8 BOM if there is any.
|
// Skip utf8 BOM if there is any.
|
||||||
if (strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3;
|
if (strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3;
|
||||||
@ -62,13 +62,11 @@ struct SourceMetadata {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
~SourceMetadata(){
|
~SourceData(){
|
||||||
free((void*)source);
|
free((void*)source);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef pkpy::shared_ptr<SourceMetadata> _Source;
|
|
||||||
|
|
||||||
class _Exception {
|
class _Exception {
|
||||||
_Str type;
|
_Str type;
|
||||||
_Str msg;
|
_Str msg;
|
||||||
|
@ -75,13 +75,13 @@ typedef pkpy::shared_ptr<Function> _Func;
|
|||||||
typedef pkpy::shared_ptr<BaseIterator> _Iterator;
|
typedef pkpy::shared_ptr<BaseIterator> _Iterator;
|
||||||
|
|
||||||
struct PyObject {
|
struct PyObject {
|
||||||
PyVar _type;
|
PyVar type;
|
||||||
PyVarDict attribs;
|
PyVarDict attribs;
|
||||||
|
|
||||||
inline bool is_type(const PyVar& type) const noexcept{ return this->_type == type; }
|
inline bool is_type(const PyVar& type) const noexcept{ return this->type == type; }
|
||||||
inline virtual void* value() = 0;
|
inline virtual void* value() = 0;
|
||||||
|
|
||||||
PyObject(const PyVar& type) : _type(type) {}
|
PyObject(const PyVar& type) : type(type) {}
|
||||||
virtual ~PyObject() = default;
|
virtual ~PyObject() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -95,4 +95,4 @@ struct Py_ : PyObject {
|
|||||||
|
|
||||||
#define UNION_GET(T, obj) (((Py_<T>*)((obj).get()))->_valueT)
|
#define UNION_GET(T, obj) (((Py_<T>*)((obj).get()))->_valueT)
|
||||||
#define UNION_NAME(obj) UNION_GET(_Str, (obj)->attribs[__name__])
|
#define UNION_NAME(obj) UNION_GET(_Str, (obj)->attribs[__name__])
|
||||||
#define UNION_TP_NAME(obj) UNION_GET(_Str, (obj)->_type->attribs[__name__])
|
#define UNION_TP_NAME(obj) UNION_GET(_Str, (obj)->type->attribs[__name__])
|
@ -42,7 +42,6 @@ OPCODE(JUMP_IF_TRUE_OR_POP)
|
|||||||
OPCODE(JUMP_IF_FALSE_OR_POP)
|
OPCODE(JUMP_IF_FALSE_OR_POP)
|
||||||
|
|
||||||
OPCODE(GOTO)
|
OPCODE(GOTO)
|
||||||
OPCODE(JUMP_RELATIVE)
|
|
||||||
|
|
||||||
OPCODE(LOAD_CONST)
|
OPCODE(LOAD_CONST)
|
||||||
OPCODE(LOAD_NONE)
|
OPCODE(LOAD_NONE)
|
||||||
|
@ -90,7 +90,7 @@ enum Precedence {
|
|||||||
|
|
||||||
// The context of the parsing phase for the compiler.
|
// The context of the parsing phase for the compiler.
|
||||||
struct Parser {
|
struct Parser {
|
||||||
_Source src;
|
pkpy::shared_ptr<SourceData> src;
|
||||||
|
|
||||||
const char* token_start;
|
const char* token_start;
|
||||||
const char* curr_char;
|
const char* curr_char;
|
||||||
@ -260,15 +260,12 @@ struct Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the current char is [c] consume it and advance char by 1 and returns
|
|
||||||
// true otherwise returns false.
|
|
||||||
bool matchchar(char c) {
|
bool matchchar(char c) {
|
||||||
if (peekchar() != c) return false;
|
if (peekchar() != c) return false;
|
||||||
eatchar_include_newline();
|
eatchar_include_newline();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the next token as the type.
|
|
||||||
void set_next_token(_TokenType type, PyVar value=nullptr) {
|
void set_next_token(_TokenType type, PyVar value=nullptr) {
|
||||||
switch(type){
|
switch(type){
|
||||||
case TK("{"): case TK("["): case TK("("): brackets_level++; break;
|
case TK("{"): case TK("["): case TK("("): brackets_level++; break;
|
||||||
@ -288,7 +285,7 @@ struct Parser {
|
|||||||
else set_next_token(one);
|
else set_next_token(one);
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser(_Source src) {
|
Parser(pkpy::shared_ptr<SourceData> src) {
|
||||||
this->src = src;
|
this->src = src;
|
||||||
this->token_start = src->source;
|
this->token_start = src->source;
|
||||||
this->curr_char = src->source;
|
this->curr_char = src->source;
|
||||||
|
@ -107,7 +107,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
|
|||||||
_vm->bindBuiltinFunc<1>("dir", [](VM* vm, const pkpy::Args& args) {
|
_vm->bindBuiltinFunc<1>("dir", [](VM* vm, const pkpy::Args& args) {
|
||||||
std::vector<_Str> names;
|
std::vector<_Str> names;
|
||||||
for (auto& [k, _] : args[0]->attribs) names.push_back(k);
|
for (auto& [k, _] : args[0]->attribs) names.push_back(k);
|
||||||
for (auto& [k, _] : args[0]->_type->attribs) {
|
for (auto& [k, _] : args[0]->type->attribs) {
|
||||||
if (k.find("__") == 0) continue;
|
if (k.find("__") == 0) continue;
|
||||||
if (std::find(names.begin(), names.end(), k) == names.end()) names.push_back(k);
|
if (std::find(names.begin(), names.end(), k) == names.end()) names.push_back(k);
|
||||||
}
|
}
|
||||||
@ -130,7 +130,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
|
|||||||
_vm->bindMethod<1>("object", "__eq__", CPP_LAMBDA(vm->PyBool(args[0] == args[1])));
|
_vm->bindMethod<1>("object", "__eq__", CPP_LAMBDA(vm->PyBool(args[0] == args[1])));
|
||||||
_vm->bindMethod<1>("object", "__ne__", CPP_LAMBDA(vm->PyBool(args[0] != args[1])));
|
_vm->bindMethod<1>("object", "__ne__", CPP_LAMBDA(vm->PyBool(args[0] != args[1])));
|
||||||
|
|
||||||
_vm->bindStaticMethod<1>("type", "__new__", CPP_LAMBDA(args[0]->_type));
|
_vm->bindStaticMethod<1>("type", "__new__", CPP_LAMBDA(args[0]->type));
|
||||||
|
|
||||||
_vm->bindStaticMethod<-1>("range", "__new__", [](VM* vm, const pkpy::Args& args) {
|
_vm->bindStaticMethod<-1>("range", "__new__", [](VM* vm, const pkpy::Args& args) {
|
||||||
_Range r;
|
_Range r;
|
||||||
|
111
src/vm.h
111
src/vm.h
@ -23,7 +23,7 @@
|
|||||||
class VM {
|
class VM {
|
||||||
std::vector<PyVar> _small_integers; // [-5, 256]
|
std::vector<PyVar> _small_integers; // [-5, 256]
|
||||||
protected:
|
protected:
|
||||||
std::deque< std::unique_ptr<Frame> > callstack;
|
std::stack< std::unique_ptr<Frame> > callstack;
|
||||||
PyVar __py2py_call_signal;
|
PyVar __py2py_call_signal;
|
||||||
|
|
||||||
PyVar run_frame(Frame* frame){
|
PyVar run_frame(Frame* frame){
|
||||||
@ -35,24 +35,24 @@ protected:
|
|||||||
switch (byte.op)
|
switch (byte.op)
|
||||||
{
|
{
|
||||||
case OP_NO_OP: break; // do nothing
|
case OP_NO_OP: break; // do nothing
|
||||||
case OP_LOAD_CONST: frame->push(frame->code->co_consts[byte.arg]); break;
|
case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); break;
|
||||||
case OP_LOAD_LAMBDA: {
|
case OP_LOAD_LAMBDA: {
|
||||||
PyVar obj = frame->code->co_consts[byte.arg];
|
PyVar obj = frame->co->consts[byte.arg];
|
||||||
setattr(obj, __module__, frame->_module);
|
setattr(obj, __module__, frame->_module);
|
||||||
frame->push(obj);
|
frame->push(obj);
|
||||||
} break;
|
} break;
|
||||||
case OP_LOAD_NAME_REF: {
|
case OP_LOAD_NAME_REF: {
|
||||||
frame->push(PyRef(NameRef(frame->code->co_names[byte.arg])));
|
frame->push(PyRef(NameRef(frame->co->names[byte.arg])));
|
||||||
} break;
|
} break;
|
||||||
case OP_LOAD_NAME: {
|
case OP_LOAD_NAME: {
|
||||||
frame->push(NameRef(frame->code->co_names[byte.arg]).get(this, frame));
|
frame->push(NameRef(frame->co->names[byte.arg]).get(this, frame));
|
||||||
} break;
|
} break;
|
||||||
case OP_STORE_NAME: {
|
case OP_STORE_NAME: {
|
||||||
const auto& p = frame->code->co_names[byte.arg];
|
const auto& p = frame->co->names[byte.arg];
|
||||||
NameRef(p).set(this, frame, frame->pop_value(this));
|
NameRef(p).set(this, frame, frame->pop_value(this));
|
||||||
} break;
|
} break;
|
||||||
case OP_BUILD_ATTR_REF: {
|
case OP_BUILD_ATTR_REF: {
|
||||||
const auto& attr = frame->code->co_names[byte.arg];
|
const auto& attr = frame->co->names[byte.arg];
|
||||||
PyVar obj = frame->pop_value(this);
|
PyVar obj = frame->pop_value(this);
|
||||||
frame->push(PyRef(AttrRef(obj, NameRef(attr))));
|
frame->push(PyRef(AttrRef(obj, NameRef(attr))));
|
||||||
} break;
|
} break;
|
||||||
@ -111,7 +111,7 @@ protected:
|
|||||||
} break;
|
} break;
|
||||||
case OP_BUILD_CLASS:
|
case OP_BUILD_CLASS:
|
||||||
{
|
{
|
||||||
const _Str& clsName = frame->code->co_names[byte.arg].first;
|
const _Str& clsName = frame->co->names[byte.arg].first;
|
||||||
PyVar clsBase = frame->pop_value(this);
|
PyVar clsBase = frame->pop_value(this);
|
||||||
if(clsBase == None) clsBase = _tp_object;
|
if(clsBase == None) clsBase = _tp_object;
|
||||||
check_type(clsBase, _tp_type);
|
check_type(clsBase, _tp_type);
|
||||||
@ -191,14 +191,14 @@ protected:
|
|||||||
case OP_EXCEPTION_MATCH:
|
case OP_EXCEPTION_MATCH:
|
||||||
{
|
{
|
||||||
const auto& _e = PyException_AS_C(frame->top());
|
const auto& _e = PyException_AS_C(frame->top());
|
||||||
_Str name = frame->code->co_names[byte.arg].first;
|
_Str name = frame->co->names[byte.arg].first;
|
||||||
frame->push(PyBool(_e.match_type(name)));
|
frame->push(PyBool(_e.match_type(name)));
|
||||||
} break;
|
} break;
|
||||||
case OP_RAISE:
|
case OP_RAISE:
|
||||||
{
|
{
|
||||||
PyVar obj = frame->pop_value(this);
|
PyVar obj = frame->pop_value(this);
|
||||||
_Str msg = obj == None ? "" : PyStr_AS_C(asStr(obj));
|
_Str msg = obj == None ? "" : PyStr_AS_C(asStr(obj));
|
||||||
_Str type = frame->code->co_names[byte.arg].first;
|
_Str type = frame->co->names[byte.arg].first;
|
||||||
_error(type, msg);
|
_error(type, msg);
|
||||||
} break;
|
} break;
|
||||||
case OP_RE_RAISE: _raise(); break;
|
case OP_RE_RAISE: _raise(); break;
|
||||||
@ -237,11 +237,10 @@ protected:
|
|||||||
frame->push(std::move(ret));
|
frame->push(std::move(ret));
|
||||||
} break;
|
} break;
|
||||||
case OP_JUMP_ABSOLUTE: frame->jump_abs(byte.arg); break;
|
case OP_JUMP_ABSOLUTE: frame->jump_abs(byte.arg); break;
|
||||||
case OP_JUMP_RELATIVE: frame->jump_rel(byte.arg); break;
|
|
||||||
case OP_SAFE_JUMP_ABSOLUTE: frame->jump_abs_safe(byte.arg); break;
|
case OP_SAFE_JUMP_ABSOLUTE: frame->jump_abs_safe(byte.arg); break;
|
||||||
case OP_GOTO: {
|
case OP_GOTO: {
|
||||||
const _Str& label = frame->code->co_names[byte.arg].first;
|
const _Str& label = frame->co->names[byte.arg].first;
|
||||||
int* target = frame->code->co_labels.try_get(label);
|
int* target = frame->co->labels.try_get(label);
|
||||||
if(target == nullptr) _error("KeyError", "label '" + label + "' not found");
|
if(target == nullptr) _error("KeyError", "label '" + label + "' not found");
|
||||||
frame->jump_abs_safe(*target);
|
frame->jump_abs_safe(*target);
|
||||||
} break;
|
} break;
|
||||||
@ -266,18 +265,18 @@ protected:
|
|||||||
if(it->hasNext()){
|
if(it->hasNext()){
|
||||||
PyRef_AS_C(it->var)->set(this, frame, it->next());
|
PyRef_AS_C(it->var)->set(this, frame, it->next());
|
||||||
}else{
|
}else{
|
||||||
int blockEnd = frame->code->co_blocks[byte.block].end;
|
int blockEnd = frame->co->blocks[byte.block].end;
|
||||||
frame->jump_abs_safe(blockEnd);
|
frame->jump_abs_safe(blockEnd);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case OP_LOOP_CONTINUE:
|
case OP_LOOP_CONTINUE:
|
||||||
{
|
{
|
||||||
int blockStart = frame->code->co_blocks[byte.block].start;
|
int blockStart = frame->co->blocks[byte.block].start;
|
||||||
frame->jump_abs(blockStart);
|
frame->jump_abs(blockStart);
|
||||||
} break;
|
} break;
|
||||||
case OP_LOOP_BREAK:
|
case OP_LOOP_BREAK:
|
||||||
{
|
{
|
||||||
int blockEnd = frame->code->co_blocks[byte.block].end;
|
int blockEnd = frame->co->blocks[byte.block].end;
|
||||||
frame->jump_abs_safe(blockEnd);
|
frame->jump_abs_safe(blockEnd);
|
||||||
} break;
|
} break;
|
||||||
case OP_JUMP_IF_FALSE_OR_POP:
|
case OP_JUMP_IF_FALSE_OR_POP:
|
||||||
@ -303,7 +302,7 @@ protected:
|
|||||||
} break;
|
} break;
|
||||||
case OP_IMPORT_NAME:
|
case OP_IMPORT_NAME:
|
||||||
{
|
{
|
||||||
const _Str& name = frame->code->co_names[byte.arg].first;
|
const _Str& name = frame->co->names[byte.arg].first;
|
||||||
auto it = _modules.find(name);
|
auto it = _modules.find(name);
|
||||||
if(it == _modules.end()){
|
if(it == _modules.end()){
|
||||||
auto it2 = _lazy_modules.find(name);
|
auto it2 = _lazy_modules.find(name);
|
||||||
@ -332,12 +331,12 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(frame->code->src->mode == EVAL_MODE || frame->code->src->mode == JSON_MODE){
|
if(frame->co->src->mode == EVAL_MODE || frame->co->src->mode == JSON_MODE){
|
||||||
if(frame->stack_size() != 1) throw std::runtime_error("stack size is not 1 in EVAL/JSON_MODE");
|
if(frame->_data.size() != 1) throw std::runtime_error("_data.size() != 1 in EVAL/JSON_MODE");
|
||||||
return frame->pop_value(this);
|
return frame->pop_value(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(frame->stack_size() != 0) throw std::runtime_error("stack not empty in EXEC_MODE");
|
if(!frame->_data.empty()) throw std::runtime_error("_data.size() != 0 in EXEC_MODE");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +380,7 @@ public:
|
|||||||
|
|
||||||
inline Frame* top_frame() const {
|
inline Frame* top_frame() const {
|
||||||
if(callstack.empty()) UNREACHABLE();
|
if(callstack.empty()) UNREACHABLE();
|
||||||
return callstack.back().get();
|
return callstack.top().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar asRepr(const PyVar& obj){
|
PyVar asRepr(const PyVar& obj){
|
||||||
@ -407,7 +406,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyVar fast_call(const _Str& name, pkpy::Args&& args){
|
PyVar fast_call(const _Str& name, pkpy::Args&& args){
|
||||||
PyObject* cls = args[0]->_type.get();
|
PyObject* cls = args[0]->type.get();
|
||||||
while(cls != None.get()) {
|
while(cls != None.get()) {
|
||||||
PyVar* val = cls->attribs.try_get(name);
|
PyVar* val = cls->attribs.try_get(name);
|
||||||
if(val != nullptr) return call(*val, std::move(args));
|
if(val != nullptr) return call(*val, std::move(args));
|
||||||
@ -514,7 +513,7 @@ public:
|
|||||||
PyVar* it_m = (*callable)->attribs.try_get(__module__);
|
PyVar* it_m = (*callable)->attribs.try_get(__module__);
|
||||||
PyVar _module = it_m != nullptr ? *it_m : top_frame()->_module;
|
PyVar _module = it_m != nullptr ? *it_m : top_frame()->_module;
|
||||||
if(opCall){
|
if(opCall){
|
||||||
__push_new_frame(fn->code, _module, _locals);
|
__new_frame(fn->code, _module, _locals);
|
||||||
return __py2py_call_signal;
|
return __py2py_call_signal;
|
||||||
}
|
}
|
||||||
return _exec(fn->code, _module, _locals);
|
return _exec(fn->code, _module, _locals);
|
||||||
@ -533,46 +532,46 @@ public:
|
|||||||
}catch (const _Exception& e){
|
}catch (const _Exception& e){
|
||||||
*_stderr << e.summary() << '\n';
|
*_stderr << e.summary() << '\n';
|
||||||
}
|
}
|
||||||
// catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
// *_stderr << "A std::exception occurred! It may be a bug, please report it!!\n";
|
*_stderr << "A std::exception occurred! It may be a bug, please report it!!\n";
|
||||||
// *_stderr << e.what() << '\n';
|
*_stderr << e.what() << '\n';
|
||||||
// }
|
}
|
||||||
callstack.clear();
|
callstack = {};
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
Frame* __push_new_frame(Args&&... args){
|
Frame* __new_frame(Args&&... args){
|
||||||
if(callstack.size() > maxRecursionDepth){
|
if(callstack.size() > maxRecursionDepth){
|
||||||
_error("RecursionError", "maximum recursion depth exceeded");
|
_error("RecursionError", "maximum recursion depth exceeded");
|
||||||
}
|
}
|
||||||
callstack.emplace_back(std::make_unique<Frame>(std::forward<Args>(args)...));
|
callstack.emplace(std::make_unique<Frame>(std::forward<Args>(args)...));
|
||||||
return callstack.back().get();
|
return callstack.top().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
PyVar _exec(Args&&... args){
|
PyVar _exec(Args&&... args){
|
||||||
Frame* frame = __push_new_frame(std::forward<Args>(args)...);
|
Frame* frame = __new_frame(std::forward<Args>(args)...);
|
||||||
i64 base_id = frame->id();
|
i64 base_id = frame->_id;
|
||||||
PyVar ret = nullptr;
|
PyVar ret = nullptr;
|
||||||
bool need_raise = false;
|
bool need_raise = false;
|
||||||
|
|
||||||
while(true){
|
while(true){
|
||||||
if(frame->id() < base_id) UNREACHABLE();
|
if(frame->_id < base_id) UNREACHABLE();
|
||||||
try{
|
try{
|
||||||
if(need_raise){ need_raise = false; _raise(); }
|
if(need_raise){ need_raise = false; _raise(); }
|
||||||
ret = run_frame(frame);
|
ret = run_frame(frame);
|
||||||
|
|
||||||
if(ret != __py2py_call_signal){
|
if(ret != __py2py_call_signal){
|
||||||
if(frame->id() == base_id){ // [ frameBase<- ]
|
if(frame->_id == base_id){ // [ frameBase<- ]
|
||||||
break;
|
break;
|
||||||
}else{
|
}else{
|
||||||
callstack.pop_back();
|
callstack.pop();
|
||||||
frame = callstack.back().get();
|
frame = callstack.top().get();
|
||||||
frame->push(ret);
|
frame->push(ret);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
frame = callstack.back().get(); // [ frameBase, newFrame<- ]
|
frame = callstack.top().get(); // [ frameBase, newFrame<- ]
|
||||||
}
|
}
|
||||||
}catch(HandledException& e){
|
}catch(HandledException& e){
|
||||||
continue;
|
continue;
|
||||||
@ -580,11 +579,11 @@ public:
|
|||||||
PyVar obj = frame->pop();
|
PyVar obj = frame->pop();
|
||||||
_Exception& _e = PyException_AS_C(obj);
|
_Exception& _e = PyException_AS_C(obj);
|
||||||
_e.st_push(frame->curr_snapshot());
|
_e.st_push(frame->curr_snapshot());
|
||||||
callstack.pop_back();
|
callstack.pop();
|
||||||
|
|
||||||
if(!callstack.empty()){
|
if(!callstack.empty()){
|
||||||
frame = callstack.back().get();
|
frame = callstack.top().get();
|
||||||
if(frame->id() < base_id) throw e;
|
if(frame->_id < base_id) throw e;
|
||||||
frame->push(obj);
|
frame->push(obj);
|
||||||
need_raise = true;
|
need_raise = true;
|
||||||
continue;
|
continue;
|
||||||
@ -593,7 +592,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callstack.pop_back();
|
callstack.pop();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -651,7 +650,7 @@ public:
|
|||||||
if(!(*root)->is_type(_tp_super)) break;
|
if(!(*root)->is_type(_tp_super)) break;
|
||||||
depth++;
|
depth++;
|
||||||
}
|
}
|
||||||
cls = (*root)->_type.get();
|
cls = (*root)->type.get();
|
||||||
for(int i=0; i<depth; i++) cls = cls->attribs[__base__].get();
|
for(int i=0; i<depth; i++) cls = cls->attribs[__base__].get();
|
||||||
|
|
||||||
it = (*root)->attribs.find(name);
|
it = (*root)->attribs.find(name);
|
||||||
@ -659,7 +658,7 @@ public:
|
|||||||
}else{
|
}else{
|
||||||
it = obj->attribs.find(name);
|
it = obj->attribs.find(name);
|
||||||
if(it != obj->attribs.end()) return it->second;
|
if(it != obj->attribs.end()) return it->second;
|
||||||
cls = obj->_type.get();
|
cls = obj->type.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
while(cls != None.get()) {
|
while(cls != None.get()) {
|
||||||
@ -775,30 +774,30 @@ public:
|
|||||||
// ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5);
|
// ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5);
|
||||||
std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
|
std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
|
||||||
if(byte.op == OP_LOAD_CONST){
|
if(byte.op == OP_LOAD_CONST){
|
||||||
argStr += " (" + PyStr_AS_C(asRepr(code->co_consts[byte.arg])) + ")";
|
argStr += " (" + PyStr_AS_C(asRepr(code->consts[byte.arg])) + ")";
|
||||||
}
|
}
|
||||||
if(byte.op == OP_LOAD_NAME_REF || byte.op == OP_LOAD_NAME || byte.op == OP_RAISE){
|
if(byte.op == OP_LOAD_NAME_REF || byte.op == OP_LOAD_NAME || byte.op == OP_RAISE){
|
||||||
argStr += " (" + code->co_names[byte.arg].first.__escape(true) + ")";
|
argStr += " (" + code->names[byte.arg].first.__escape(true) + ")";
|
||||||
}
|
}
|
||||||
ss << pad(argStr, 20); // may overflow
|
ss << pad(argStr, 20); // may overflow
|
||||||
ss << code->co_blocks[byte.block].to_string();
|
ss << code->blocks[byte.block].to_string();
|
||||||
if(i != code->co_code.size() - 1) ss << '\n';
|
if(i != code->co_code.size() - 1) ss << '\n';
|
||||||
}
|
}
|
||||||
_StrStream consts;
|
_StrStream consts;
|
||||||
consts << "co_consts: ";
|
consts << "consts: ";
|
||||||
consts << PyStr_AS_C(asRepr(PyList(code->co_consts)));
|
consts << PyStr_AS_C(asRepr(PyList(code->consts)));
|
||||||
|
|
||||||
_StrStream names;
|
_StrStream names;
|
||||||
names << "co_names: ";
|
names << "names: ";
|
||||||
PyVarList list;
|
PyVarList list;
|
||||||
for(int i=0; i<code->co_names.size(); i++){
|
for(int i=0; i<code->names.size(); i++){
|
||||||
list.push_back(PyStr(code->co_names[i].first));
|
list.push_back(PyStr(code->names[i].first));
|
||||||
}
|
}
|
||||||
names << PyStr_AS_C(asRepr(PyList(list)));
|
names << PyStr_AS_C(asRepr(PyList(list)));
|
||||||
ss << '\n' << consts.str() << '\n' << names.str() << '\n';
|
ss << '\n' << consts.str() << '\n' << names.str() << '\n';
|
||||||
|
|
||||||
for(int i=0; i<code->co_consts.size(); i++){
|
for(int i=0; i<code->consts.size(); i++){
|
||||||
PyVar obj = code->co_consts[i];
|
PyVar obj = code->consts[i];
|
||||||
if(obj->is_type(_tp_function)){
|
if(obj->is_type(_tp_function)){
|
||||||
const auto& f = PyFunction_AS_C(obj);
|
const auto& f = PyFunction_AS_C(obj);
|
||||||
ss << disassemble(f->code);
|
ss << disassemble(f->code);
|
||||||
@ -881,9 +880,9 @@ public:
|
|||||||
this->__py2py_call_signal = new_object(new_type_object("_signal"), DUMMY_VAL);
|
this->__py2py_call_signal = new_object(new_type_object("_signal"), DUMMY_VAL);
|
||||||
|
|
||||||
setattr(_tp_type, __base__, _tp_object);
|
setattr(_tp_type, __base__, _tp_object);
|
||||||
_tp_type->_type = _tp_type;
|
_tp_type->type = _tp_type;
|
||||||
setattr(_tp_object, __base__, None);
|
setattr(_tp_object, __base__, None);
|
||||||
_tp_object->_type = _tp_type;
|
_tp_object->type = _tp_type;
|
||||||
|
|
||||||
for (auto& [name, type] : _types) {
|
for (auto& [name, type] : _types) {
|
||||||
setattr(type, __name__, PyStr(name));
|
setattr(type, __name__, PyStr(name));
|
||||||
|
@ -8,6 +8,8 @@ def f():
|
|||||||
try:
|
try:
|
||||||
raise KeyError('foo')
|
raise KeyError('foo')
|
||||||
except A: # will fail to catch
|
except A: # will fail to catch
|
||||||
|
print("xx")
|
||||||
|
except:
|
||||||
print("exception caught")
|
print("exception caught")
|
||||||
print(123)
|
print(123)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user