This commit is contained in:
blueloveTH 2023-02-04 17:46:50 +08:00
parent 981fcbc8e5
commit 730201907c
9 changed files with 170 additions and 209 deletions

View File

@ -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;
} }

View File

@ -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,8 +807,10 @@ __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();
do {
consume(TK("except")); consume(TK("except"));
if(match(TK("@id"))){ if(match(TK("@id"))){
int name_idx = co()->add_name(parser->prev.str(), NAME_SPECIAL); int name_idx = co()->add_name(parser->prev.str(), NAME_SPECIAL);
@ -817,22 +818,23 @@ __LISTCOMP:
}else{ }else{
emit(OP_LOAD_TRUE); emit(OP_LOAD_TRUE);
} }
int patch_2 = emit(OP_POP_JUMP_IF_FALSE); int patch = emit(OP_POP_JUMP_IF_FALSE);
emit(OP_POP_TOP); // pop the exception on match emit(OP_POP_TOP); // pop the exception on match
compileBlockBody(); compileBlockBody();
emit(OP_JUMP_RELATIVE, 1); patches.push_back(emit(OP_JUMP_ABSOLUTE));
patch_jump(patch_2);
emit(OP_RE_RAISE); // no match, re-raise
patch_jump(patch); patch_jump(patch);
}while(peek() == TK("except"));
emit(OP_RE_RAISE); // no match, re-raise
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"))){

View File

@ -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;

View File

@ -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__])

View File

@ -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)

View File

@ -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;

View File

@ -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
View File

@ -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));

View File

@ -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)