This commit is contained in:
blueloveTH 2023-01-11 15:29:47 +08:00
parent 6ebd78e7ae
commit 41b7c1adb9
7 changed files with 743 additions and 811 deletions

File diff suppressed because it is too large Load Diff

@ -1 +1 @@
Subproject commit 647691921747b5c2a242df30c5639d0410a6b621 Subproject commit 8663b7ea6ff8e7b0bf5b15bf3f12d38b1384165b

View File

@ -16,7 +16,7 @@ static const char* OP_NAMES[] = {
#undef OPCODE #undef OPCODE
}; };
struct ByteCode{ struct Bytecode{
uint8_t op; uint8_t op;
int arg; int arg;
int line; int line;
@ -44,7 +44,7 @@ struct CodeBlock {
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 toString() const { std::string to_string() const {
if(parent == -1) return ""; if(parent == -1) return "";
std::string s = "["; std::string s = "[";
for(int i = 0; i < id.size(); i++){ for(int i = 0; i < id.size(); i++){
@ -57,17 +57,9 @@ struct CodeBlock {
return s; return s;
} }
bool operator==(const std::vector<int>& other) const { bool operator==(const std::vector<int>& other) const{ return id == other; }
return id == other; bool operator!=(const std::vector<int>& other) const{ return id != other; }
} int depth() const{ return id.size(); }
bool operator!=(const std::vector<int>& other) const {
return id != other;
}
int depth() const {
return id.size();
}
}; };
struct CodeObject { struct CodeObject {
@ -79,11 +71,7 @@ struct CodeObject {
this->name = name; this->name = name;
} }
CompileMode mode() const { std::vector<Bytecode> co_code;
return src->mode;
}
std::vector<ByteCode> co_code;
PyVarList co_consts; PyVarList co_consts;
std::vector<std::pair<_Str, NameScope>> co_names; std::vector<std::pair<_Str, NameScope>> co_names;
std::vector<_Str> co_global_names; std::vector<_Str> co_global_names;
@ -121,7 +109,7 @@ struct CodeObject {
// goto/label should be put at toplevel statements // goto/label should be put at toplevel statements
emhash8::HashMap<_Str, int> co_labels; emhash8::HashMap<_Str, int> co_labels;
void addLabel(const _Str& label){ void add_label(const _Str& label){
if(co_labels.find(label) != co_labels.end()){ if(co_labels.find(label) != co_labels.end()){
_Str msg = "label '" + label + "' already exists"; _Str msg = "label '" + label + "' already exists";
throw std::runtime_error(msg.c_str()); throw std::runtime_error(msg.c_str());
@ -129,7 +117,7 @@ struct CodeObject {
co_labels[label] = co_code.size(); co_labels[label] = co_code.size();
} }
int addName(_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 && std::find(co_global_names.begin(), co_global_names.end(), name) != co_global_names.end()){
scope = NAME_GLOBAL; scope = NAME_GLOBAL;
} }
@ -141,7 +129,7 @@ struct CodeObject {
return co_names.size() - 1; return co_names.size() - 1;
} }
int addConst(PyVar v){ int add_const(PyVar v){
co_consts.push_back(v); co_consts.push_back(v);
return co_consts.size() - 1; return co_consts.size() - 1;
} }
@ -150,7 +138,7 @@ struct CodeObject {
for(int i=0; i<co_code.size(); i++){ for(int i=0; i<co_code.size(); i++){
if(co_code[i].op >= OP_BINARY_OP && co_code[i].op <= OP_CONTAINS_OP){ if(co_code[i].op >= OP_BINARY_OP && co_code[i].op <= OP_CONTAINS_OP){
for(int j=0; j<2; j++){ for(int j=0; j<2; j++){
ByteCode& bc = co_code[i-j-1]; Bytecode& bc = co_code[i-j-1];
if(bc.op >= OP_LOAD_CONST && bc.op <= OP_LOAD_NAME_REF){ if(bc.op >= OP_LOAD_CONST && bc.op <= OP_LOAD_NAME_REF){
if(bc.op == OP_LOAD_NAME_REF){ if(bc.op == OP_LOAD_NAME_REF){
bc.op = OP_LOAD_NAME; bc.op = OP_LOAD_NAME;
@ -164,7 +152,7 @@ struct CodeObject {
int KWARGC = (co_code[i].arg >> 16) & 0xFFFF; int KWARGC = (co_code[i].arg >> 16) & 0xFFFF;
if(KWARGC != 0) continue; if(KWARGC != 0) continue;
for(int j=0; j<ARGC+1; j++){ for(int j=0; j<ARGC+1; j++){
ByteCode& bc = co_code[i-j-1]; Bytecode& bc = co_code[i-j-1];
if(bc.op >= OP_LOAD_CONST && bc.op <= OP_LOAD_NAME_REF){ if(bc.op >= OP_LOAD_CONST && bc.op <= OP_LOAD_NAME_REF){
if(bc.op == OP_LOAD_NAME_REF){ if(bc.op == OP_LOAD_NAME_REF){
bc.op = OP_LOAD_NAME; bc.op = OP_LOAD_NAME;
@ -192,38 +180,28 @@ public:
PyVar _module; PyVar _module;
PyVarDict f_locals; PyVarDict f_locals;
inline PyVarDict copy_f_locals() const { inline PyVarDict f_locals_copy() const { return f_locals; }
return f_locals; inline PyVarDict& f_globals(){ return _module->attribs; }
}
inline PyVarDict& f_globals(){
return _module->attribs;
}
Frame(const _Code code, PyVar _module, PyVarDict&& locals) Frame(const _Code code, PyVar _module, PyVarDict&& locals)
: code(code), _module(_module), f_locals(std::move(locals)) { : code(code), _module(_module), f_locals(std::move(locals)) {
} }
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 code->co_code[ip];
} }
_Str errorSnapshot(){ _Str curr_snapshot(){
int line = code->co_code[ip].line; int line = code->co_code[ip].line;
return code->src->snapshot(line); return code->src->snapshot(line);
} }
inline int stackSize() const { inline int stack_size() const{ return s_data.size(); }
return s_data.size(); inline bool has_next_bytecode() const{ return next_ip < code->co_code.size(); }
}
inline bool has_next_bytecode() const { inline PyVar pop(){
return next_ip < code->co_code.size();
}
inline PyVar __pop(){
if(s_data.empty()) throw std::runtime_error("s_data.empty() is true"); if(s_data.empty()) throw std::runtime_error("s_data.empty() is true");
PyVar v = std::move(s_data.back()); PyVar v = std::move(s_data.back());
s_data.pop_back(); s_data.pop_back();
@ -232,62 +210,58 @@ public:
inline void try_deref(VM*, PyVar&); inline void try_deref(VM*, PyVar&);
inline PyVar popValue(VM* vm){ inline PyVar pop_value(VM* vm){
PyVar value = __pop(); PyVar value = pop();
try_deref(vm, value); try_deref(vm, value);
return value; return value;
} }
inline PyVar topValue(VM* vm){ inline PyVar top_value(VM* vm){
PyVar value = __top(); PyVar value = top();
try_deref(vm, value); try_deref(vm, value);
return value; return value;
} }
inline PyVar& __top(){ inline PyVar& top(){
if(s_data.empty()) throw std::runtime_error("s_data.empty() is true"); if(s_data.empty()) throw std::runtime_error("s_data.empty() is true");
return s_data.back(); return s_data.back();
} }
inline PyVar __topValueN(VM* vm, int n=-1){ inline PyVar top_value_offset(VM* vm, int n){
PyVar value = s_data[s_data.size() + n]; PyVar value = s_data[s_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){ inline void push(T&& obj){ s_data.push_back(std::forward<T>(obj)); }
s_data.push_back(std::forward<T>(obj));
}
inline void jumpAbsolute(int i){ inline void jump_abs(int i){ next_ip = i; }
next_ip = i;
}
void jumpAbsoluteSafe(int target){ void jump_abs_safe(int target){
const ByteCode& prev = code->co_code[ip]; const Bytecode& prev = code->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 >= code->co_code.size()){
while(i>=0){ while(i>=0){
if(code->co_blocks[i].type == FOR_LOOP) __pop(); if(code->co_blocks[i].type == FOR_LOOP) pop();
i = code->co_blocks[i].parent; i = code->co_blocks[i].parent;
} }
}else{ }else{
const ByteCode& next = code->co_code[target]; const Bytecode& next = code->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(code->co_blocks[i].type == FOR_LOOP) pop();
i = code->co_blocks[i].parent; i = code->co_blocks[i].parent;
} }
if(i!=next.block) throw std::runtime_error( if(i!=next.block) throw std::runtime_error(
"invalid jump from " + code->co_blocks[prev.block].toString() + " to " + code->co_blocks[next.block].toString() "invalid jump from " + code->co_blocks[prev.block].to_string() + " to " + code->co_blocks[next.block].to_string()
); );
} }
} }
pkpy::ArgList popNValuesReversed(VM* vm, int n){ pkpy::ArgList pop_n_values_reversed(VM* vm, int n){
int new_size = s_data.size() - n; int new_size = s_data.size() - n;
if(new_size < 0) throw std::runtime_error("stackSize() < n"); if(new_size < 0) throw std::runtime_error("stack_size() < n");
pkpy::ArgList v(n); pkpy::ArgList v(n);
for(int i=n-1; i>=0; i--){ for(int i=n-1; i>=0; i--){
v._index(i) = std::move(s_data[new_size + i]); v._index(i) = std::move(s_data[new_size + i]);
@ -297,15 +271,15 @@ public:
return v; return v;
} }
PyVarList popNValuesReversedUnlimited(VM* vm, int n){ PyVarList pop_n_values_reversed_unlimited(VM* vm, int n){
PyVarList v(n); PyVarList v(n);
for(int i=n-1; i>=0; i--) v[i] = popValue(vm); for(int i=n-1; i>=0; i--) v[i] = pop_value(vm);
return v; return v;
} }
pkpy::ArgList __popNReversed(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._index(i) = __pop(); for(int i=n-1; i>=0; i--) v._index(i) = pop();
return v; return v;
} }
}; };

View File

@ -27,7 +27,7 @@ public:
emhash8::HashMap<_TokenType, GrammarRule> rules; emhash8::HashMap<_TokenType, GrammarRule> rules;
_Code getCode() { _Code co() {
return codes.top(); return codes.top();
} }
@ -204,13 +204,13 @@ public:
// Lex the next token and set it as the next token. // Lex the next token and set it as the next token.
void _lexToken() { void _lexToken() {
parser->previous = parser->current; parser->prev = parser->curr;
parser->current = parser->nextToken(); parser->curr = parser->nextToken();
//_Str _info = parser->current.info(); std::cout << _info << '[' << parser->current_line << ']' << std::endl; //_Str _info = parser->curr.info(); std::cout << _info << '[' << parser->current_line << ']' << std::endl;
while (parser->peekChar() != '\0') { while (parser->peek_char() != '\0') {
parser->token_start = parser->current_char; parser->token_start = parser->curr_char;
char c = parser->eatCharIncludeNewLine(); char c = parser->eatCharIncludeNewLine();
switch (c) { switch (c) {
case '\'': case '"': eatString(c, NORMAL_STRING); return; case '\'': case '"': eatString(c, NORMAL_STRING); return;
@ -314,16 +314,16 @@ public:
} }
} }
parser->token_start = parser->current_char; parser->token_start = parser->curr_char;
parser->setNextToken(TK("@eof")); parser->setNextToken(TK("@eof"));
} }
inline _TokenType peek() { inline _TokenType peek() {
return parser->current.type; return parser->curr.type;
} }
// not sure this will work // not sure this will work
_TokenType peekNext() { _TokenType peek_next() {
if(parser->nexts.empty()) return TK("@eof"); if(parser->nexts.empty()) return TK("@eof");
return parser->nexts.front().type; return parser->nexts.front().type;
} }
@ -370,14 +370,14 @@ public:
} }
void exprLiteral() { void exprLiteral() {
PyVar value = parser->previous.value; PyVar value = parser->prev.value;
int index = getCode()->addConst(value); int index = co()->add_const(value);
emitCode(OP_LOAD_CONST, index); emit(OP_LOAD_CONST, index);
} }
void exprFString() { void exprFString() {
static const std::regex pattern(R"(\{(.*?)\})"); static const std::regex pattern(R"(\{(.*?)\})");
PyVar value = parser->previous.value; PyVar value = parser->prev.value;
_Str s = vm->PyStr_AS_C(value); _Str s = vm->PyStr_AS_C(value);
std::sregex_iterator begin(s.begin(), s.end(), pattern); std::sregex_iterator begin(s.begin(), s.end(), pattern);
std::sregex_iterator end; std::sregex_iterator end;
@ -387,21 +387,21 @@ public:
std::smatch m = *it; std::smatch m = *it;
if (i < m.position()) { if (i < m.position()) {
std::string literal = s.substr(i, m.position() - i); std::string literal = s.substr(i, m.position() - i);
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(literal))); emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(literal)));
size++; size++;
} }
emitCode(OP_LOAD_EVAL_FN); emit(OP_LOAD_EVAL_FN);
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(m[1].str()))); emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(m[1].str())));
emitCode(OP_CALL, 1); emit(OP_CALL, 1);
size++; size++;
i = (int)(m.position() + m.length()); i = (int)(m.position() + m.length());
} }
if (i < s.size()) { if (i < s.size()) {
std::string literal = s.substr(i, s.size() - i); std::string literal = s.substr(i, s.size() - i);
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(literal))); emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(literal)));
size++; size++;
} }
emitCode(OP_BUILD_STRING, size); emit(OP_BUILD_STRING, size);
} }
void exprLambda() { void exprLambda() {
@ -414,35 +414,35 @@ public:
func->code = pkpy::make_shared<CodeObject>(parser->src, func->name); func->code = pkpy::make_shared<CodeObject>(parser->src, func->name);
this->codes.push(func->code); this->codes.push(func->code);
EXPR_TUPLE(); EXPR_TUPLE();
emitCode(OP_RETURN_VALUE); emit(OP_RETURN_VALUE);
func->code->optimize(); func->code->optimize();
this->codes.pop(); this->codes.pop();
emitCode(OP_LOAD_LAMBDA, getCode()->addConst(vm->PyFunction(func))); emit(OP_LOAD_LAMBDA, co()->add_const(vm->PyFunction(func)));
} }
void exprAssign() { void exprAssign() {
_TokenType op = parser->previous.type; _TokenType op = parser->prev.type;
if(op == TK("=")) { // a = (expr) if(op == TK("=")) { // a = (expr)
EXPR_TUPLE(); EXPR_TUPLE();
emitCode(OP_STORE_REF); emit(OP_STORE_REF);
}else{ // a += (expr) -> a = a + (expr) }else{ // a += (expr) -> a = a + (expr)
// TODO: optimization is needed for inplace operators // TODO: optimization is needed for inplace operators
emitCode(OP_DUP_TOP); emit(OP_DUP_TOP);
EXPR(); EXPR();
switch (op) { switch (op) {
case TK("+="): emitCode(OP_BINARY_OP, 0); break; case TK("+="): emit(OP_BINARY_OP, 0); break;
case TK("-="): emitCode(OP_BINARY_OP, 1); break; case TK("-="): emit(OP_BINARY_OP, 1); break;
case TK("*="): emitCode(OP_BINARY_OP, 2); break; case TK("*="): emit(OP_BINARY_OP, 2); break;
case TK("/="): emitCode(OP_BINARY_OP, 3); break; case TK("/="): emit(OP_BINARY_OP, 3); break;
case TK("//="): emitCode(OP_BINARY_OP, 4); break; case TK("//="): emit(OP_BINARY_OP, 4); break;
case TK("%="): emitCode(OP_BINARY_OP, 5); break; case TK("%="): emit(OP_BINARY_OP, 5); break;
case TK("&="): emitCode(OP_BITWISE_OP, 2); break; case TK("&="): emit(OP_BITWISE_OP, 2); break;
case TK("|="): emitCode(OP_BITWISE_OP, 3); break; case TK("|="): emit(OP_BITWISE_OP, 3); break;
case TK("^="): emitCode(OP_BITWISE_OP, 4); break; case TK("^="): emit(OP_BITWISE_OP, 4); break;
default: UNREACHABLE(); default: UNREACHABLE();
} }
emitCode(OP_STORE_REF); emit(OP_STORE_REF);
} }
} }
@ -452,72 +452,72 @@ public:
EXPR(); // NOTE: "1," will fail, "1,2" will be ok EXPR(); // NOTE: "1," will fail, "1,2" will be ok
size++; size++;
} while(match(TK(","))); } while(match(TK(",")));
emitCode(OP_BUILD_SMART_TUPLE, size); emit(OP_BUILD_SMART_TUPLE, size);
} }
void exprOr() { void exprOr() {
int patch = emitCode(OP_JUMP_IF_TRUE_OR_POP); int patch = emit(OP_JUMP_IF_TRUE_OR_POP);
parsePrecedence(PREC_LOGICAL_OR); parsePrecedence(PREC_LOGICAL_OR);
patchJump(patch); patch_jump(patch);
} }
void exprAnd() { void exprAnd() {
int patch = emitCode(OP_JUMP_IF_FALSE_OR_POP); int patch = emit(OP_JUMP_IF_FALSE_OR_POP);
parsePrecedence(PREC_LOGICAL_AND); parsePrecedence(PREC_LOGICAL_AND);
patchJump(patch); patch_jump(patch);
} }
void exprTernary() { void exprTernary() {
int patch = emitCode(OP_POP_JUMP_IF_FALSE); int patch = emit(OP_POP_JUMP_IF_FALSE);
EXPR(); // if true EXPR(); // if true
int patch2 = emitCode(OP_JUMP_ABSOLUTE); int patch2 = emit(OP_JUMP_ABSOLUTE);
consume(TK(":")); consume(TK(":"));
patchJump(patch); patch_jump(patch);
EXPR(); // if false EXPR(); // if false
patchJump(patch2); patch_jump(patch2);
} }
void exprBinaryOp() { void exprBinaryOp() {
_TokenType op = parser->previous.type; _TokenType op = parser->prev.type;
parsePrecedence((Precedence)(rules[op].precedence + 1)); parsePrecedence((Precedence)(rules[op].precedence + 1));
switch (op) { switch (op) {
case TK("+"): emitCode(OP_BINARY_OP, 0); break; case TK("+"): emit(OP_BINARY_OP, 0); break;
case TK("-"): emitCode(OP_BINARY_OP, 1); break; case TK("-"): emit(OP_BINARY_OP, 1); break;
case TK("*"): emitCode(OP_BINARY_OP, 2); break; case TK("*"): emit(OP_BINARY_OP, 2); break;
case TK("/"): emitCode(OP_BINARY_OP, 3); break; case TK("/"): emit(OP_BINARY_OP, 3); break;
case TK("//"): emitCode(OP_BINARY_OP, 4); break; case TK("//"): emit(OP_BINARY_OP, 4); break;
case TK("%"): emitCode(OP_BINARY_OP, 5); break; case TK("%"): emit(OP_BINARY_OP, 5); break;
case TK("**"): emitCode(OP_BINARY_OP, 6); break; case TK("**"): emit(OP_BINARY_OP, 6); break;
case TK("<"): emitCode(OP_COMPARE_OP, 0); break; case TK("<"): emit(OP_COMPARE_OP, 0); break;
case TK("<="): emitCode(OP_COMPARE_OP, 1); break; case TK("<="): emit(OP_COMPARE_OP, 1); break;
case TK("=="): emitCode(OP_COMPARE_OP, 2); break; case TK("=="): emit(OP_COMPARE_OP, 2); break;
case TK("!="): emitCode(OP_COMPARE_OP, 3); break; case TK("!="): emit(OP_COMPARE_OP, 3); break;
case TK(">"): emitCode(OP_COMPARE_OP, 4); break; case TK(">"): emit(OP_COMPARE_OP, 4); break;
case TK(">="): emitCode(OP_COMPARE_OP, 5); break; case TK(">="): emit(OP_COMPARE_OP, 5); break;
case TK("in"): emitCode(OP_CONTAINS_OP, 0); break; case TK("in"): emit(OP_CONTAINS_OP, 0); break;
case TK("not in"): emitCode(OP_CONTAINS_OP, 1); break; case TK("not in"): emit(OP_CONTAINS_OP, 1); break;
case TK("is"): emitCode(OP_IS_OP, 0); break; case TK("is"): emit(OP_IS_OP, 0); break;
case TK("is not"): emitCode(OP_IS_OP, 1); break; case TK("is not"): emit(OP_IS_OP, 1); break;
case TK("<<"): emitCode(OP_BITWISE_OP, 0); break; case TK("<<"): emit(OP_BITWISE_OP, 0); break;
case TK(">>"): emitCode(OP_BITWISE_OP, 1); break; case TK(">>"): emit(OP_BITWISE_OP, 1); break;
case TK("&"): emitCode(OP_BITWISE_OP, 2); break; case TK("&"): emit(OP_BITWISE_OP, 2); break;
case TK("|"): emitCode(OP_BITWISE_OP, 3); break; case TK("|"): emit(OP_BITWISE_OP, 3); break;
case TK("^"): emitCode(OP_BITWISE_OP, 4); break; case TK("^"): emit(OP_BITWISE_OP, 4); break;
default: UNREACHABLE(); default: UNREACHABLE();
} }
} }
void exprUnaryOp() { void exprUnaryOp() {
_TokenType op = parser->previous.type; _TokenType op = parser->prev.type;
matchNewLines(); matchNewLines();
parsePrecedence((Precedence)(PREC_UNARY + 1)); parsePrecedence((Precedence)(PREC_UNARY + 1));
switch (op) { switch (op) {
case TK("-"): emitCode(OP_UNARY_NEGATIVE); break; case TK("-"): emit(OP_UNARY_NEGATIVE); break;
case TK("not"): emitCode(OP_UNARY_NOT); break; case TK("not"): emit(OP_UNARY_NOT); break;
case TK("*"): syntaxError("cannot use '*' as unary operator"); break; case TK("*"): syntaxError("cannot use '*' as unary operator"); break;
default: UNREACHABLE(); default: UNREACHABLE();
} }
@ -531,8 +531,8 @@ public:
} }
void exprList() { void exprList() {
int _patch = emitCode(OP_NO_OP); int _patch = emit(OP_NO_OP);
int _body_start = getCode()->co_code.size(); int _body_start = co()->co_code.size();
int ARGC = 0; int ARGC = 0;
do { do {
matchNewLines(mode()==SINGLE_MODE); matchNewLines(mode()==SINGLE_MODE);
@ -543,47 +543,47 @@ public:
} while (match(TK(","))); } while (match(TK(",")));
matchNewLines(mode()==SINGLE_MODE); matchNewLines(mode()==SINGLE_MODE);
consume(TK("]")); consume(TK("]"));
emitCode(OP_BUILD_LIST, ARGC); emit(OP_BUILD_LIST, ARGC);
return; return;
__LISTCOMP: __LISTCOMP:
int _body_end_return = emitCode(OP_JUMP_ABSOLUTE, -1); int _body_end_return = emit(OP_JUMP_ABSOLUTE, -1);
int _body_end = getCode()->co_code.size(); int _body_end = co()->co_code.size();
getCode()->co_code[_patch].op = OP_JUMP_ABSOLUTE; co()->co_code[_patch].op = OP_JUMP_ABSOLUTE;
getCode()->co_code[_patch].arg = _body_end; co()->co_code[_patch].arg = _body_end;
emitCode(OP_BUILD_LIST, 0); emit(OP_BUILD_LIST, 0);
EXPR_FOR_VARS();consume(TK("in"));EXPR_TUPLE(); EXPR_FOR_VARS();consume(TK("in"));EXPR_TUPLE();
matchNewLines(mode()==SINGLE_MODE); matchNewLines(mode()==SINGLE_MODE);
int _skipPatch = emitCode(OP_JUMP_ABSOLUTE); int _skipPatch = emit(OP_JUMP_ABSOLUTE);
int _cond_start = getCode()->co_code.size(); int _cond_start = co()->co_code.size();
int _cond_end_return = -1; int _cond_end_return = -1;
if(match(TK("if"))) { if(match(TK("if"))) {
EXPR_TUPLE(); EXPR_TUPLE();
_cond_end_return = emitCode(OP_JUMP_ABSOLUTE, -1); _cond_end_return = emit(OP_JUMP_ABSOLUTE, -1);
} }
patchJump(_skipPatch); patch_jump(_skipPatch);
emitCode(OP_GET_ITER); emit(OP_GET_ITER);
getCode()->__enterBlock(FOR_LOOP); co()->__enterBlock(FOR_LOOP);
emitCode(OP_FOR_ITER); emit(OP_FOR_ITER);
if(_cond_end_return != -1) { // there is an if condition if(_cond_end_return != -1) { // there is an if condition
emitCode(OP_JUMP_ABSOLUTE, _cond_start); emit(OP_JUMP_ABSOLUTE, _cond_start);
patchJump(_cond_end_return); patch_jump(_cond_end_return);
int ifpatch = emitCode(OP_POP_JUMP_IF_FALSE); int ifpatch = emit(OP_POP_JUMP_IF_FALSE);
emitCode(OP_JUMP_ABSOLUTE, _body_start); emit(OP_JUMP_ABSOLUTE, _body_start);
patchJump(_body_end_return); patch_jump(_body_end_return);
emitCode(OP_LIST_APPEND); emit(OP_LIST_APPEND);
patchJump(ifpatch); patch_jump(ifpatch);
}else{ }else{
emitCode(OP_JUMP_ABSOLUTE, _body_start); emit(OP_JUMP_ABSOLUTE, _body_start);
patchJump(_body_end_return); patch_jump(_body_end_return);
emitCode(OP_LIST_APPEND); emit(OP_LIST_APPEND);
} }
emitCode(OP_LOOP_CONTINUE); keepOpcodeLine(); emit(OP_LOOP_CONTINUE, -1, true);
getCode()->__exitBlock(); co()->__exitBlock();
matchNewLines(mode()==SINGLE_MODE); matchNewLines(mode()==SINGLE_MODE);
consume(TK("]")); consume(TK("]"));
} }
@ -606,8 +606,8 @@ __LISTCOMP:
matchNewLines(); matchNewLines();
consume(TK("}")); consume(TK("}"));
if(size == 0 || parsing_dict) emitCode(OP_BUILD_MAP, size); if(size == 0 || parsing_dict) emit(OP_BUILD_MAP, size);
else emitCode(OP_BUILD_SET, size); else emit(OP_BUILD_SET, size);
} }
void exprCall() { void exprCall() {
@ -616,10 +616,10 @@ __LISTCOMP:
do { do {
matchNewLines(mode()==SINGLE_MODE); matchNewLines(mode()==SINGLE_MODE);
if (peek() == TK(")")) break; if (peek() == TK(")")) break;
if(peek() == TK("@id") && peekNext() == TK("=")) { if(peek() == TK("@id") && peek_next() == TK("=")) {
consume(TK("@id")); consume(TK("@id"));
const _Str& key = parser->previous.str(); const _Str& key = parser->prev.str();
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(key))); emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(key)));
consume(TK("=")); consume(TK("="));
EXPR(); EXPR();
KWARGC++; KWARGC++;
@ -631,82 +631,79 @@ __LISTCOMP:
matchNewLines(mode()==SINGLE_MODE); matchNewLines(mode()==SINGLE_MODE);
} while (match(TK(","))); } while (match(TK(",")));
consume(TK(")")); consume(TK(")"));
emitCode(OP_CALL, (KWARGC << 16) | ARGC); emit(OP_CALL, (KWARGC << 16) | ARGC);
} }
void exprName() { void exprName() {
Token tkname = parser->previous; Token tkname = parser->prev;
int index = getCode()->addName( int index = co()->add_name(
tkname.str(), tkname.str(),
codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL
); );
emitCode(OP_LOAD_NAME_REF, index); emit(OP_LOAD_NAME_REF, index);
} }
void exprAttrib() { void exprAttrib() {
consume(TK("@id")); consume(TK("@id"));
const _Str& name = parser->previous.str(); const _Str& name = parser->prev.str();
int index = getCode()->addName(name, NAME_ATTR); int index = co()->add_name(name, NAME_ATTR);
emitCode(OP_BUILD_ATTR_REF, index); emit(OP_BUILD_ATTR_REF, index);
} }
// [:], [:b] // [:], [:b]
// [a], [a:], [a:b] // [a], [a:], [a:b]
void exprSubscript() { void exprSubscript() {
if(match(TK(":"))){ if(match(TK(":"))){
emitCode(OP_LOAD_NONE); emit(OP_LOAD_NONE);
if(match(TK("]"))){ if(match(TK("]"))){
emitCode(OP_LOAD_NONE); emit(OP_LOAD_NONE);
}else{ }else{
EXPR_TUPLE(); EXPR_TUPLE();
consume(TK("]")); consume(TK("]"));
} }
emitCode(OP_BUILD_SLICE); emit(OP_BUILD_SLICE);
}else{ }else{
EXPR_TUPLE(); EXPR_TUPLE();
if(match(TK(":"))){ if(match(TK(":"))){
if(match(TK("]"))){ if(match(TK("]"))){
emitCode(OP_LOAD_NONE); emit(OP_LOAD_NONE);
}else{ }else{
EXPR_TUPLE(); EXPR_TUPLE();
consume(TK("]")); consume(TK("]"));
} }
emitCode(OP_BUILD_SLICE); emit(OP_BUILD_SLICE);
}else{ }else{
consume(TK("]")); consume(TK("]"));
} }
} }
emitCode(OP_BUILD_INDEX_REF); emit(OP_BUILD_INDEX_REF);
} }
void exprValue() { void exprValue() {
_TokenType op = parser->previous.type; _TokenType op = parser->prev.type;
switch (op) { switch (op) {
case TK("None"): emitCode(OP_LOAD_NONE); break; case TK("None"): emit(OP_LOAD_NONE); break;
case TK("True"): emitCode(OP_LOAD_TRUE); break; case TK("True"): emit(OP_LOAD_TRUE); break;
case TK("False"): emitCode(OP_LOAD_FALSE); break; case TK("False"): emit(OP_LOAD_FALSE); break;
case TK("..."): emitCode(OP_LOAD_ELLIPSIS); break; case TK("..."): emit(OP_LOAD_ELLIPSIS); break;
default: UNREACHABLE(); default: UNREACHABLE();
} }
} }
void keepOpcodeLine(){ int emit(Opcode opcode, int arg=-1, bool keepline=false) {
int i = getCode()->co_code.size() - 1; int line = parser->prev.line;
getCode()->co_code[i].line = getCode()->co_code[i-1].line; co()->co_code.push_back(
} Bytecode{(uint8_t)opcode, arg, line, (uint16_t)co()->_currBlockIndex}
int emitCode(Opcode opcode, int arg=-1) {
int line = parser->previous.line;
getCode()->co_code.push_back(
ByteCode{(uint8_t)opcode, arg, line, (uint16_t)getCode()->_currBlockIndex}
); );
return getCode()->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;
return i;
} }
inline void patchJump(int addr_index) { inline void patch_jump(int addr_index) {
int target = getCode()->co_code.size(); int target = co()->co_code.size();
getCode()->co_code[addr_index].arg = target; co()->co_code[addr_index].arg = target;
} }
void compileBlockBody(){ void compileBlockBody(){
@ -729,9 +726,9 @@ __LISTCOMP:
Token compileImportPath() { Token compileImportPath() {
consume(TK("@id")); consume(TK("@id"));
Token tkmodule = parser->previous; Token tkmodule = parser->prev;
int index = getCode()->addName(tkmodule.str(), NAME_GLOBAL); int index = co()->add_name(tkmodule.str(), NAME_GLOBAL);
emitCode(OP_IMPORT_NAME, index); emit(OP_IMPORT_NAME, index);
return tkmodule; return tkmodule;
} }
@ -741,10 +738,10 @@ __LISTCOMP:
Token tkmodule = compileImportPath(); Token tkmodule = compileImportPath();
if (match(TK("as"))) { if (match(TK("as"))) {
consume(TK("@id")); consume(TK("@id"));
tkmodule = parser->previous; tkmodule = parser->prev;
} }
int index = getCode()->addName(tkmodule.str(), NAME_GLOBAL); int index = co()->add_name(tkmodule.str(), NAME_GLOBAL);
emitCode(OP_STORE_NAME_REF, index); emit(OP_STORE_NAME_REF, index);
} while (match(TK(","))); } while (match(TK(",")));
consumeEndStatement(); consumeEndStatement();
} }
@ -754,30 +751,30 @@ __LISTCOMP:
Token tkmodule = compileImportPath(); Token tkmodule = compileImportPath();
consume(TK("import")); consume(TK("import"));
do { do {
emitCode(OP_DUP_TOP); emit(OP_DUP_TOP);
consume(TK("@id")); consume(TK("@id"));
Token tkname = parser->previous; Token tkname = parser->prev;
int index = getCode()->addName(tkname.str(), NAME_GLOBAL); int index = co()->add_name(tkname.str(), NAME_GLOBAL);
emitCode(OP_BUILD_ATTR_REF, index); emit(OP_BUILD_ATTR_REF, index);
if (match(TK("as"))) { if (match(TK("as"))) {
consume(TK("@id")); consume(TK("@id"));
tkname = parser->previous; tkname = parser->prev;
} }
index = getCode()->addName(tkname.str(), NAME_GLOBAL); index = co()->add_name(tkname.str(), NAME_GLOBAL);
emitCode(OP_STORE_NAME_REF, index); emit(OP_STORE_NAME_REF, index);
} while (match(TK(","))); } while (match(TK(",")));
emitCode(OP_POP_TOP); emit(OP_POP_TOP);
consumeEndStatement(); consumeEndStatement();
} }
void parsePrecedence(Precedence precedence) { void parsePrecedence(Precedence precedence) {
lexToken(); lexToken();
GrammarFn prefix = rules[parser->previous.type].prefix; GrammarFn prefix = rules[parser->prev.type].prefix;
if (prefix == nullptr) syntaxError(_Str("expected an expression, but got ") + TK_STR(parser->previous.type)); if (prefix == nullptr) syntaxError(_Str("expected an expression, but got ") + TK_STR(parser->prev.type));
(this->*prefix)(); (this->*prefix)();
while (rules[peek()].precedence >= precedence) { while (rules[peek()].precedence >= precedence) {
lexToken(); lexToken();
_TokenType op = parser->previous.type; _TokenType op = parser->prev.type;
GrammarFn infix = rules[op].infix; GrammarFn infix = rules[op].infix;
if(infix == nullptr) throw std::runtime_error("(infix == nullptr) is true"); if(infix == nullptr) throw std::runtime_error("(infix == nullptr) is true");
(this->*infix)(); (this->*infix)();
@ -788,32 +785,32 @@ __LISTCOMP:
matchNewLines(); matchNewLines();
EXPR_TUPLE(); EXPR_TUPLE();
int ifpatch = emitCode(OP_POP_JUMP_IF_FALSE); int ifpatch = emit(OP_POP_JUMP_IF_FALSE);
compileBlockBody(); compileBlockBody();
if (match(TK("elif"))) { if (match(TK("elif"))) {
int exit_jump = emitCode(OP_JUMP_ABSOLUTE); int exit_jump = emit(OP_JUMP_ABSOLUTE);
patchJump(ifpatch); patch_jump(ifpatch);
compileIfStatement(); compileIfStatement();
patchJump(exit_jump); patch_jump(exit_jump);
} else if (match(TK("else"))) { } else if (match(TK("else"))) {
int exit_jump = emitCode(OP_JUMP_ABSOLUTE); int exit_jump = emit(OP_JUMP_ABSOLUTE);
patchJump(ifpatch); patch_jump(ifpatch);
compileBlockBody(); compileBlockBody();
patchJump(exit_jump); patch_jump(exit_jump);
} else { } else {
patchJump(ifpatch); patch_jump(ifpatch);
} }
} }
void compileWhileLoop() { void compileWhileLoop() {
getCode()->__enterBlock(WHILE_LOOP); co()->__enterBlock(WHILE_LOOP);
EXPR_TUPLE(); EXPR_TUPLE();
int patch = emitCode(OP_POP_JUMP_IF_FALSE); int patch = emit(OP_POP_JUMP_IF_FALSE);
compileBlockBody(); compileBlockBody();
emitCode(OP_LOOP_CONTINUE); keepOpcodeLine(); emit(OP_LOOP_CONTINUE, -1, true);
patchJump(patch); patch_jump(patch);
getCode()->__exitBlock(); co()->__exitBlock();
} }
void EXPR_FOR_VARS(){ void EXPR_FOR_VARS(){
@ -822,24 +819,24 @@ __LISTCOMP:
consume(TK("@id")); consume(TK("@id"));
exprName(); size++; exprName(); size++;
} while (match(TK(","))); } while (match(TK(",")));
if(size > 1) emitCode(OP_BUILD_SMART_TUPLE, size); if(size > 1) emit(OP_BUILD_SMART_TUPLE, size);
} }
void compileForLoop() { void compileForLoop() {
EXPR_FOR_VARS();consume(TK("in")); EXPR_TUPLE(); EXPR_FOR_VARS();consume(TK("in")); EXPR_TUPLE();
emitCode(OP_GET_ITER); emit(OP_GET_ITER);
getCode()->__enterBlock(FOR_LOOP); co()->__enterBlock(FOR_LOOP);
emitCode(OP_FOR_ITER); emit(OP_FOR_ITER);
compileBlockBody(); compileBlockBody();
emitCode(OP_LOOP_CONTINUE); keepOpcodeLine(); emit(OP_LOOP_CONTINUE, -1, true);
getCode()->__exitBlock(); co()->__exitBlock();
} }
void compileTryExcept() { void compileTryExcept() {
getCode()->__enterBlock(TRY_EXCEPT); co()->__enterBlock(TRY_EXCEPT);
compileBlockBody(); compileBlockBody();
int patch = emitCode(OP_JUMP_ABSOLUTE); int patch = emit(OP_JUMP_ABSOLUTE);
getCode()->__exitBlock(); co()->__exitBlock();
consume(TK("except")); consume(TK("except"));
if(match(TK("@id"))){ // exception name if(match(TK("@id"))){ // exception name
compileBlockBody(); compileBlockBody();
@ -848,28 +845,28 @@ __LISTCOMP:
consume(TK(":")); consume(TK(":"));
syntaxError("finally is not supported yet"); syntaxError("finally is not supported yet");
} }
patchJump(patch); patch_jump(patch);
} }
void compileStatement() { void compileStatement() {
if (match(TK("break"))) { if (match(TK("break"))) {
if (!getCode()->__isCurrBlockLoop()) syntaxError("'break' outside loop"); if (!co()->__isCurrBlockLoop()) syntaxError("'break' outside loop");
consumeEndStatement(); consumeEndStatement();
emitCode(OP_LOOP_BREAK); emit(OP_LOOP_BREAK);
} else if (match(TK("continue"))) { } else if (match(TK("continue"))) {
if (!getCode()->__isCurrBlockLoop()) syntaxError("'continue' not properly in loop"); if (!co()->__isCurrBlockLoop()) syntaxError("'continue' not properly in loop");
consumeEndStatement(); consumeEndStatement();
emitCode(OP_LOOP_CONTINUE); emit(OP_LOOP_CONTINUE);
} else if (match(TK("return"))) { } else if (match(TK("return"))) {
if (codes.size() == 1) if (codes.size() == 1)
syntaxError("'return' outside function"); syntaxError("'return' outside function");
if(matchEndStatement()){ if(matchEndStatement()){
emitCode(OP_LOAD_NONE); emit(OP_LOAD_NONE);
}else{ }else{
EXPR_TUPLE(); EXPR_TUPLE();
consumeEndStatement(); consumeEndStatement();
} }
emitCode(OP_RETURN_VALUE); emit(OP_RETURN_VALUE);
} else if (match(TK("if"))) { } else if (match(TK("if"))) {
compileIfStatement(); compileIfStatement();
} else if (match(TK("while"))) { } else if (match(TK("while"))) {
@ -880,54 +877,54 @@ __LISTCOMP:
compileTryExcept(); compileTryExcept();
}else if(match(TK("assert"))){ }else if(match(TK("assert"))){
EXPR(); EXPR();
emitCode(OP_ASSERT); emit(OP_ASSERT);
consumeEndStatement(); consumeEndStatement();
} else if(match(TK("with"))){ } else if(match(TK("with"))){
EXPR(); EXPR();
consume(TK("as")); consume(TK("as"));
consume(TK("@id")); consume(TK("@id"));
Token tkname = parser->previous; Token tkname = parser->prev;
int index = getCode()->addName( int index = co()->add_name(
tkname.str(), tkname.str(),
codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL
); );
emitCode(OP_STORE_NAME_REF, index); emit(OP_STORE_NAME_REF, index);
emitCode(OP_LOAD_NAME_REF, index); emit(OP_LOAD_NAME_REF, index);
emitCode(OP_WITH_ENTER); emit(OP_WITH_ENTER);
compileBlockBody(); compileBlockBody();
emitCode(OP_LOAD_NAME_REF, index); emit(OP_LOAD_NAME_REF, index);
emitCode(OP_WITH_EXIT); emit(OP_WITH_EXIT);
} 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"));
getCode()->addLabel(parser->previous.str()); co()->add_label(parser->prev.str());
consumeEndStatement(); consumeEndStatement();
} else if(match(TK("goto"))){ } else if(match(TK("goto"))){
// https://entrian.com/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");
consume(TK(".")); consume(TK("@id")); consume(TK(".")); consume(TK("@id"));
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str()))); emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(parser->prev.str())));
emitCode(OP_GOTO); emit(OP_GOTO);
consumeEndStatement(); consumeEndStatement();
} else if(match(TK("raise"))){ } else if(match(TK("raise"))){
consume(TK("@id")); // dummy exception type consume(TK("@id")); // dummy exception type
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str()))); emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(parser->prev.str())));
if(match(TK("("))){ if(match(TK("("))){
EXPR(); EXPR();
consume(TK(")")); consume(TK(")"));
}else{ }else{
emitCode(OP_LOAD_NONE); // ...? emit(OP_LOAD_NONE); // ...?
} }
emitCode(OP_RAISE_ERROR); emit(OP_RAISE_ERROR);
consumeEndStatement(); consumeEndStatement();
} else if(match(TK("del"))){ } else if(match(TK("del"))){
EXPR(); EXPR();
emitCode(OP_DELETE_REF); emit(OP_DELETE_REF);
consumeEndStatement(); consumeEndStatement();
} else if(match(TK("global"))){ } else if(match(TK("global"))){
do { do {
consume(TK("@id")); consume(TK("@id"));
getCode()->co_global_names.push_back(parser->previous.str()); co()->co_global_names.push_back(parser->prev.str());
} while (match(TK(","))); } while (match(TK(",")));
consumeEndStatement(); consumeEndStatement();
} else if(match(TK("pass"))){ } else if(match(TK("pass"))){
@ -936,30 +933,30 @@ __LISTCOMP:
EXPR_ANY(); EXPR_ANY();
consumeEndStatement(); consumeEndStatement();
// If last op is not an assignment, pop the result. // If last op is not an assignment, pop the result.
uint8_t lastOp = getCode()->co_code.back().op; uint8_t lastOp = co()->co_code.back().op;
if( lastOp!=OP_STORE_NAME_REF && lastOp!=OP_STORE_REF){ if( lastOp!=OP_STORE_NAME_REF && lastOp!=OP_STORE_REF){
if(mode()==SINGLE_MODE && parser->indents.top()==0) emitCode(OP_PRINT_EXPR); if(mode()==SINGLE_MODE && parser->indents.top()==0) emit(OP_PRINT_EXPR);
emitCode(OP_POP_TOP); emit(OP_POP_TOP);
} }
} }
} }
void compileClass(){ void compileClass(){
consume(TK("@id")); consume(TK("@id"));
int clsNameIdx = getCode()->addName(parser->previous.str(), NAME_GLOBAL); int clsNameIdx = co()->add_name(parser->prev.str(), NAME_GLOBAL);
int superClsNameIdx = -1; int superClsNameIdx = -1;
if(match(TK("("))){ if(match(TK("("))){
consume(TK("@id")); consume(TK("@id"));
superClsNameIdx = getCode()->addName(parser->previous.str(), NAME_GLOBAL); superClsNameIdx = co()->add_name(parser->prev.str(), NAME_GLOBAL);
consume(TK(")")); consume(TK(")"));
} }
emitCode(OP_LOAD_NONE); emit(OP_LOAD_NONE);
isCompilingClass = true; isCompilingClass = true;
__compileBlockBody(&Compiler::compileFunction); __compileBlockBody(&Compiler::compileFunction);
isCompilingClass = false; isCompilingClass = false;
if(superClsNameIdx == -1) emitCode(OP_LOAD_NONE); if(superClsNameIdx == -1) emit(OP_LOAD_NONE);
else emitCode(OP_LOAD_NAME_REF, superClsNameIdx); else emit(OP_LOAD_NAME_REF, superClsNameIdx);
emitCode(OP_BUILD_CLASS, clsNameIdx); emit(OP_BUILD_CLASS, clsNameIdx);
} }
void __compileFunctionArgs(_Func func, bool enableTypeHints){ void __compileFunctionArgs(_Func func, bool enableTypeHints){
@ -976,7 +973,7 @@ __LISTCOMP:
} }
consume(TK("@id")); consume(TK("@id"));
const _Str& name = parser->previous.str(); const _Str& name = parser->prev.str();
if(func->hasName(name)) syntaxError("duplicate argument name"); if(func->hasName(name)) syntaxError("duplicate argument name");
// eat type hints // eat type hints
@ -992,7 +989,7 @@ __LISTCOMP:
consume(TK("=")); consume(TK("="));
PyVarOrNull value = readLiteral(); PyVarOrNull value = readLiteral();
if(value == nullptr){ if(value == nullptr){
syntaxError(_Str("expect a literal, not ") + TK_STR(parser->current.type)); syntaxError(_Str("expect a literal, not ") + TK_STR(parser->curr.type));
} }
func->kwArgs[name] = value; func->kwArgs[name] = value;
func->kwArgsOrder.push_back(name); func->kwArgsOrder.push_back(name);
@ -1009,7 +1006,7 @@ __LISTCOMP:
} }
_Func func = pkpy::make_shared<Function>(); _Func func = pkpy::make_shared<Function>();
consume(TK("@id")); consume(TK("@id"));
func->name = parser->previous.str(); func->name = parser->prev.str();
if (match(TK("(")) && !match(TK(")"))) { if (match(TK("(")) && !match(TK(")"))) {
__compileFunctionArgs(func, true); __compileFunctionArgs(func, true);
@ -1024,18 +1021,18 @@ __LISTCOMP:
compileBlockBody(); compileBlockBody();
func->code->optimize(); func->code->optimize();
this->codes.pop(); this->codes.pop();
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyFunction(func))); emit(OP_LOAD_CONST, co()->add_const(vm->PyFunction(func)));
if(!isCompilingClass) emitCode(OP_STORE_FUNCTION); if(!isCompilingClass) emit(OP_STORE_FUNCTION);
} }
PyVarOrNull readLiteral(){ PyVarOrNull readLiteral(){
if(match(TK("-"))){ if(match(TK("-"))){
consume(TK("@num")); consume(TK("@num"));
PyVar val = parser->previous.value; PyVar val = parser->prev.value;
return vm->numNegated(val); return vm->numNegated(val);
} }
if(match(TK("@num"))) return parser->previous.value; if(match(TK("@num"))) return parser->prev.value;
if(match(TK("@str"))) return parser->previous.value; if(match(TK("@str"))) return parser->prev.value;
if(match(TK("True"))) return vm->PyBool(true); if(match(TK("True"))) return vm->PyBool(true);
if(match(TK("False"))) return vm->PyBool(false); if(match(TK("False"))) return vm->PyBool(false);
if(match(TK("None"))) return vm->None; if(match(TK("None"))) return vm->None;
@ -1078,7 +1075,7 @@ __LISTCOMP:
return code; return code;
}else if(mode()==JSON_MODE){ }else if(mode()==JSON_MODE){
PyVarOrNull value = readLiteral(); PyVarOrNull value = readLiteral();
if(value != nullptr) emitCode(OP_LOAD_CONST, code->addConst(value)); if(value != nullptr) emit(OP_LOAD_CONST, code->add_const(value));
else if(match(TK("{"))) exprMap(); else if(match(TK("{"))) exprMap();
else if(match(TK("["))) exprList(); else if(match(TK("["))) exprList();
else syntaxError("expect a JSON object or array"); else syntaxError("expect a JSON object or array");
@ -1096,14 +1093,14 @@ __LISTCOMP:
/***** Error Reporter *****/ /***** Error Reporter *****/
_Str getLineSnapshot(){ _Str getLineSnapshot(){
int lineno = parser->current.line; int lineno = parser->curr.line;
const char* cursor = parser->current.start; const char* cursor = parser->curr.start;
// if error occurs in lexing, lineno should be `parser->current_line` // if error occurs in lexing, lineno should be `parser->current_line`
if(lexingCnt > 0){ if(lexingCnt > 0){
lineno = parser->current_line; lineno = parser->current_line;
cursor = parser->current_char; cursor = parser->curr_char;
} }
if(parser->peekChar() == '\n') lineno--; if(parser->peek_char() == '\n') lineno--;
return parser->src->snapshot(lineno, cursor); return parser->src->snapshot(lineno, cursor);
} }

View File

@ -98,9 +98,9 @@ struct Parser {
_Source src; _Source src;
const char* token_start; const char* token_start;
const char* current_char; const char* curr_char;
int current_line = 1; int current_line = 1;
Token previous, current; Token prev, curr;
std::queue<Token> nexts; std::queue<Token> nexts;
std::stack<int> indents; std::stack<int> indents;
@ -120,28 +120,23 @@ struct Parser {
return t; return t;
} }
char peekChar() { inline char peek_char() {
return *current_char; return *curr_char;
} }
std::string_view lookahead(int n){ std::string_view lookahead(int n){
const char* c = current_char; const char* c = curr_char;
for(int i=0; i<n; i++){ for(int i=0; i<n; i++){
if(*c == '\0') return std::string_view(current_char, i); if(*c == '\0') return std::string_view(curr_char, i);
c++; c++;
} }
return std::string_view(current_char, n); return std::string_view(curr_char, n);
}
char peekNextChar() {
if (peekChar() == '\0') return '\0';
return *(current_char + 1);
} }
int eatSpaces(){ int eatSpaces(){
int count = 0; int count = 0;
while (true) { while (true) {
switch (peekChar()) { switch (peek_char()) {
case ' ' : count+=1; break; case ' ' : count+=1; break;
case '\t': count+=4; break; case '\t': count+=4; break;
default: return count; default: return count;
@ -153,8 +148,8 @@ struct Parser {
bool eatIndentation(){ bool eatIndentation(){
if(brackets_level_0 > 0 || brackets_level_1 > 0 || brackets_level_2 > 0) return true; if(brackets_level_0 > 0 || brackets_level_1 > 0 || brackets_level_2 > 0) return true;
int spaces = eatSpaces(); int spaces = eatSpaces();
if(peekChar() == '#') skipLineComment(); if(peek_char() == '#') skipLineComment();
if(peekChar() == '\0' || peekChar() == '\n') return true; if(peek_char() == '\0' || peek_char() == '\n') return true;
// https://docs.python.org/3/reference/lexical_analysis.html#indentation // https://docs.python.org/3/reference/lexical_analysis.html#indentation
if(spaces > indents.top()){ if(spaces > indents.top()){
indents.push(spaces); indents.push(spaces);
@ -172,26 +167,26 @@ struct Parser {
} }
char eatChar() { char eatChar() {
char c = peekChar(); char c = peek_char();
if(c == '\n') throw std::runtime_error("eatChar() cannot consume a newline"); if(c == '\n') throw std::runtime_error("eatChar() cannot consume a newline");
current_char++; curr_char++;
return c; return c;
} }
char eatCharIncludeNewLine() { char eatCharIncludeNewLine() {
char c = peekChar(); char c = peek_char();
current_char++; curr_char++;
if (c == '\n'){ if (c == '\n'){
current_line++; current_line++;
src->lineStarts.push_back(current_char); src->lineStarts.push_back(curr_char);
} }
return c; return c;
} }
int eatName() { int eatName() {
current_char--; curr_char--;
while(true){ while(true){
uint8_t c = peekChar(); uint8_t c = peek_char();
int u8bytes = 0; int u8bytes = 0;
if((c & 0b10000000) == 0b00000000) u8bytes = 1; if((c & 0b10000000) == 0b00000000) u8bytes = 1;
else if((c & 0b11100000) == 0b11000000) u8bytes = 2; else if((c & 0b11100000) == 0b11000000) u8bytes = 2;
@ -200,14 +195,14 @@ struct Parser {
else return 1; else return 1;
if(u8bytes == 1){ if(u8bytes == 1){
if(isalpha(c) || c=='_' || isdigit(c)) { if(isalpha(c) || c=='_' || isdigit(c)) {
current_char++; curr_char++;
continue; continue;
}else{ }else{
break; break;
} }
} }
// handle multibyte char // handle multibyte char
std::string u8str(current_char, u8bytes); std::string u8str(curr_char, u8bytes);
if(u8str.size() != u8bytes) return 2; if(u8str.size() != u8bytes) return 2;
uint32_t value = 0; uint32_t value = 0;
for(int k=0; k < u8bytes; k++){ for(int k=0; k < u8bytes; k++){
@ -220,11 +215,11 @@ struct Parser {
value |= (b & 0b00111111) << (6*(u8bytes-k-1)); value |= (b & 0b00111111) << (6*(u8bytes-k-1));
} }
} }
if(__isLoChar(value)) current_char += u8bytes; if(__isLoChar(value)) curr_char += u8bytes;
else break; else break;
} }
int length = (int)(current_char - token_start); int length = (int)(curr_char - token_start);
if(length == 0) return 3; if(length == 0) return 3;
std::string_view name(token_start, length); std::string_view name(token_start, length);
@ -243,14 +238,14 @@ struct Parser {
if(__KW_MAP.count(name)){ if(__KW_MAP.count(name)){
if(name == "not"){ if(name == "not"){
if(strncmp(current_char, " in", 3) == 0){ if(strncmp(curr_char, " in", 3) == 0){
current_char += 3; curr_char += 3;
setNextToken(TK("not in")); setNextToken(TK("not in"));
return 0; return 0;
} }
}else if(name == "is"){ }else if(name == "is"){
if(strncmp(current_char, " not", 4) == 0){ if(strncmp(curr_char, " not", 4) == 0){
current_char += 4; curr_char += 4;
setNextToken(TK("is not")); setNextToken(TK("is not"));
return 0; return 0;
} }
@ -264,7 +259,7 @@ struct Parser {
void skipLineComment() { void skipLineComment() {
char c; char c;
while ((c = peekChar()) != '\0') { while ((c = peek_char()) != '\0') {
if (c == '\n') return; if (c == '\n') return;
eatChar(); eatChar();
} }
@ -273,14 +268,14 @@ struct Parser {
// If the current char is [c] consume it and advance char by 1 and returns // If the current char is [c] consume it and advance char by 1 and returns
// true otherwise returns false. // true otherwise returns false.
bool matchChar(char c) { bool matchChar(char c) {
if (peekChar() != c) return false; if (peek_char() != c) return false;
eatCharIncludeNewLine(); eatCharIncludeNewLine();
return true; return true;
} }
// Returns an error token from the current position for reporting error. // Returns an error token from the current position for reporting error.
Token makeErrToken() { Token makeErrToken() {
return Token{TK("@error"), token_start, (int)(current_char - token_start), current_line}; return Token{TK("@error"), token_start, (int)(curr_char - token_start), current_line};
} }
// Initialize the next token as the type. // Initialize the next token as the type.
@ -298,7 +293,7 @@ struct Parser {
nexts.push( Token{ nexts.push( Token{
type, type,
token_start, token_start,
(int)(current_char - token_start), (int)(curr_char - token_start),
current_line - ((type == TK("@eol")) ? 1 : 0), current_line - ((type == TK("@eol")) ? 1 : 0),
value value
}); });
@ -312,7 +307,7 @@ struct Parser {
Parser(_Source src) { Parser(_Source src) {
this->src = src; this->src = src;
this->token_start = src->source; this->token_start = src->source;
this->current_char = src->source; this->curr_char = src->source;
this->nexts.push(Token{TK("@sof"), token_start, 0, current_line}); this->nexts.push(Token{TK("@sof"), token_start, 0, current_line});
this->indents.push(0); this->indents.push(0);
} }

View File

@ -67,7 +67,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
vm->__checkArgSize(args, 1); vm->__checkArgSize(args, 1);
const _Str& expr = vm->PyStr_AS_C(args[0]); const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = vm->compile(expr, "<eval>", EVAL_MODE); _Code code = vm->compile(expr, "<eval>", EVAL_MODE);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals()); return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->f_locals_copy());
}); });
_vm->bindBuiltinFunc("isinstance", [](VM* vm, const pkpy::ArgList& args) { _vm->bindBuiltinFunc("isinstance", [](VM* vm, const pkpy::ArgList& args) {
@ -672,7 +672,7 @@ void __addModuleJson(VM* vm){
vm->__checkArgSize(args, 1); vm->__checkArgSize(args, 1);
const _Str& expr = vm->PyStr_AS_C(args[0]); const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = vm->compile(expr, "<json>", JSON_MODE); _Code code = vm->compile(expr, "<json>", JSON_MODE);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals()); return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->f_locals_copy());
}); });
vm->bindFunc(mod, "dumps", [](VM* vm, const pkpy::ArgList& args) { vm->bindFunc(mod, "dumps", [](VM* vm, const pkpy::ArgList& args) {

176
src/vm.h
View File

@ -21,28 +21,28 @@
class VM { class VM {
std::atomic<bool> _stopFlag = false; std::atomic<bool> _stop_flag = false;
std::vector<PyVar> _smallIntegers; // [-5, 256] std::vector<PyVar> _small_integers; // [-5, 256]
PyVarDict _modules; // loaded modules
emhash8::HashMap<_Str, _Str> _lazy_modules; // lazy loaded modules
protected: protected:
std::deque< pkpy::unique_ptr<Frame> > callstack; std::deque< pkpy::unique_ptr<Frame> > callstack;
PyVarDict _modules; // loaded modules
emhash8::HashMap<_Str, _Str> _lazyModules; // lazy loaded modules
PyVar __py2py_call_signal; PyVar __py2py_call_signal;
void _checkStopFlag(){ inline void test_stop_flag(){
if(_stopFlag){ if(_stop_flag){
_stopFlag = false; _stop_flag = false;
_error("KeyboardInterrupt", ""); _error("KeyboardInterrupt", "");
} }
} }
PyVar runFrame(Frame* frame){ PyVar run_frame(Frame* frame){
while(frame->has_next_bytecode()){ while(frame->has_next_bytecode()){
const ByteCode& byte = frame->next_bytecode(); const Bytecode& byte = frame->next_bytecode();
//printf("[%d] %s (%d)\n", frame->stackSize(), OP_NAMES[byte.op], byte.arg); //printf("[%d] %s (%d)\n", frame->stack_size(), OP_NAMES[byte.op], byte.arg);
//printf("%s\n", frame->code->src->getLine(byte.line).c_str()); //printf("%s\n", frame->code->src->getLine(byte.line).c_str());
_checkStopFlag(); test_stop_flag();
switch (byte.op) switch (byte.op)
{ {
@ -61,30 +61,30 @@ protected:
} break; } break;
case OP_STORE_NAME_REF: { case OP_STORE_NAME_REF: {
const auto& p = frame->code->co_names[byte.arg]; const auto& p = frame->code->co_names[byte.arg];
NameRef(p).set(this, frame, frame->popValue(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->code->co_names[byte.arg];
PyVar obj = frame->popValue(this); PyVar obj = frame->pop_value(this);
frame->push(PyRef(AttrRef(obj, NameRef(attr)))); frame->push(PyRef(AttrRef(obj, NameRef(attr))));
} break; } break;
case OP_BUILD_INDEX_REF: { case OP_BUILD_INDEX_REF: {
PyVar index = frame->popValue(this); PyVar index = frame->pop_value(this);
PyVarRef obj = frame->popValue(this); PyVarRef obj = frame->pop_value(this);
frame->push(PyRef(IndexRef(obj, index))); frame->push(PyRef(IndexRef(obj, index)));
} break; } break;
case OP_STORE_REF: { case OP_STORE_REF: {
PyVar obj = frame->popValue(this); PyVar obj = frame->pop_value(this);
PyVarRef r = frame->__pop(); PyVarRef r = frame->pop();
PyRef_AS_C(r)->set(this, frame, std::move(obj)); PyRef_AS_C(r)->set(this, frame, std::move(obj));
} break; } break;
case OP_DELETE_REF: { case OP_DELETE_REF: {
PyVarRef r = frame->__pop(); PyVarRef r = frame->pop();
PyRef_AS_C(r)->del(this, frame); PyRef_AS_C(r)->del(this, frame);
} break; } break;
case OP_BUILD_SMART_TUPLE: case OP_BUILD_SMART_TUPLE:
{ {
pkpy::ArgList items = frame->__popNReversed(byte.arg); pkpy::ArgList items = frame->pop_n_reversed(byte.arg);
bool done = false; bool done = false;
for(int i=0; i<items.size(); i++){ for(int i=0; i<items.size(); i++){
if(!items[i]->isType(_tp_ref)) { if(!items[i]->isType(_tp_ref)) {
@ -100,7 +100,7 @@ protected:
} break; } break;
case OP_BUILD_STRING: case OP_BUILD_STRING:
{ {
pkpy::ArgList items = frame->popNValuesReversed(this, byte.arg); pkpy::ArgList items = frame->pop_n_values_reversed(this, byte.arg);
_StrStream ss; _StrStream ss;
for(int i=0; i<items.size(); i++) ss << PyStr_AS_C(asStr(items[i])); for(int i=0; i<items.size(); i++) ss << PyStr_AS_C(asStr(items[i]));
frame->push(PyStr(ss.str())); frame->push(PyStr(ss.str()));
@ -110,13 +110,13 @@ protected:
} break; } break;
case OP_LIST_APPEND: { case OP_LIST_APPEND: {
pkpy::ArgList args(2); pkpy::ArgList args(2);
args[1] = frame->popValue(this); // obj args[1] = frame->pop_value(this); // obj
args[0] = frame->__topValueN(this, -2); // list args[0] = frame->top_value_offset(this, -2); // list
fastCall(m_append, std::move(args)); fastCall(m_append, std::move(args));
} break; } break;
case OP_STORE_FUNCTION: case OP_STORE_FUNCTION:
{ {
PyVar obj = frame->popValue(this); PyVar obj = frame->pop_value(this);
const _Func& fn = PyFunction_AS_C(obj); const _Func& fn = PyFunction_AS_C(obj);
setAttr(obj, __module__, frame->_module); setAttr(obj, __module__, frame->_module);
frame->f_globals()[fn->name] = obj; frame->f_globals()[fn->name] = obj;
@ -124,78 +124,78 @@ protected:
case OP_BUILD_CLASS: case OP_BUILD_CLASS:
{ {
const _Str& clsName = frame->code->co_names[byte.arg].first; const _Str& clsName = frame->code->co_names[byte.arg].first;
PyVar clsBase = frame->popValue(this); PyVar clsBase = frame->pop_value(this);
if(clsBase == None) clsBase = _tp_object; if(clsBase == None) clsBase = _tp_object;
__checkType(clsBase, _tp_type); __checkType(clsBase, _tp_type);
PyVar cls = newUserClassType(frame->_module, clsName, clsBase); PyVar cls = newUserClassType(frame->_module, clsName, clsBase);
while(true){ while(true){
PyVar fn = frame->popValue(this); PyVar fn = frame->pop_value(this);
if(fn == None) break; if(fn == None) break;
const _Func& f = PyFunction_AS_C(fn); const _Func& f = PyFunction_AS_C(fn);
setAttr(fn, __module__, frame->_module); setAttr(fn, __module__, frame->_module);
setAttr(cls, f->name, fn); setAttr(cls, f->name, fn);
} }
} break; } break;
case OP_RETURN_VALUE: return frame->popValue(this); case OP_RETURN_VALUE: return frame->pop_value(this);
case OP_PRINT_EXPR: case OP_PRINT_EXPR:
{ {
const PyVar expr = frame->topValue(this); const PyVar expr = frame->top_value(this);
if(expr == None) break; if(expr == None) break;
*_stdout << PyStr_AS_C(asRepr(expr)) << '\n'; *_stdout << PyStr_AS_C(asRepr(expr)) << '\n';
} break; } break;
case OP_POP_TOP: frame->popValue(this); break; case OP_POP_TOP: frame->pop_value(this); break;
case OP_BINARY_OP: case OP_BINARY_OP:
{ {
frame->push( frame->push(
fastCall(BINARY_SPECIAL_METHODS[byte.arg], fastCall(BINARY_SPECIAL_METHODS[byte.arg],
frame->popNValuesReversed(this, 2)) frame->pop_n_values_reversed(this, 2))
); );
// pkpy::ArgList args(2); // pkpy::ArgList args(2);
// args._index(1) = frame->popValue(this); // args._index(1) = frame->pop_value(this);
// args._index(0) = frame->topValue(this); // args._index(0) = frame->top_value(this);
// frame->__top() = fastCall(BINARY_SPECIAL_METHODS[byte.arg], std::move(args)); // frame->top() = fastCall(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
} break; } break;
case OP_BITWISE_OP: case OP_BITWISE_OP:
{ {
frame->push( frame->push(
fastCall(BITWISE_SPECIAL_METHODS[byte.arg], fastCall(BITWISE_SPECIAL_METHODS[byte.arg],
frame->popNValuesReversed(this, 2)) frame->pop_n_values_reversed(this, 2))
); );
} break; } break;
case OP_COMPARE_OP: case OP_COMPARE_OP:
{ {
// for __ne__ we use the negation of __eq__ // for __ne__ we use the negation of __eq__
int op = byte.arg == 3 ? 2 : byte.arg; int op = byte.arg == 3 ? 2 : byte.arg;
PyVar res = fastCall(CMP_SPECIAL_METHODS[op], frame->popNValuesReversed(this, 2)); PyVar res = fastCall(CMP_SPECIAL_METHODS[op], frame->pop_n_values_reversed(this, 2));
if(op != byte.arg) res = PyBool(!PyBool_AS_C(res)); if(op != byte.arg) res = PyBool(!PyBool_AS_C(res));
frame->push(std::move(res)); frame->push(std::move(res));
} break; } break;
case OP_IS_OP: case OP_IS_OP:
{ {
bool ret_c = frame->popValue(this) == frame->popValue(this); bool ret_c = frame->pop_value(this) == frame->pop_value(this);
if(byte.arg == 1) ret_c = !ret_c; if(byte.arg == 1) ret_c = !ret_c;
frame->push(PyBool(ret_c)); frame->push(PyBool(ret_c));
} break; } break;
case OP_CONTAINS_OP: case OP_CONTAINS_OP:
{ {
PyVar rhs = frame->popValue(this); PyVar rhs = frame->pop_value(this);
bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::oneArg(frame->popValue(this)))); bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::oneArg(frame->pop_value(this))));
if(byte.arg == 1) ret_c = !ret_c; if(byte.arg == 1) ret_c = !ret_c;
frame->push(PyBool(ret_c)); frame->push(PyBool(ret_c));
} break; } break;
case OP_UNARY_NEGATIVE: case OP_UNARY_NEGATIVE:
{ {
PyVar obj = frame->popValue(this); PyVar obj = frame->pop_value(this);
frame->push(numNegated(obj)); frame->push(numNegated(obj));
} break; } break;
case OP_UNARY_NOT: case OP_UNARY_NOT:
{ {
PyVar obj = frame->popValue(this); PyVar obj = frame->pop_value(this);
const PyVar& obj_bool = asBool(obj); const PyVar& obj_bool = asBool(obj);
frame->push(PyBool(!PyBool_AS_C(obj_bool))); frame->push(PyBool(!PyBool_AS_C(obj_bool)));
} break; } break;
case OP_POP_JUMP_IF_FALSE: case OP_POP_JUMP_IF_FALSE:
if(!PyBool_AS_C(asBool(frame->popValue(this)))) frame->jumpAbsolute(byte.arg); if(!PyBool_AS_C(asBool(frame->pop_value(this)))) frame->jump_abs(byte.arg);
break; break;
case OP_LOAD_NONE: frame->push(None); break; case OP_LOAD_NONE: frame->push(None); break;
case OP_LOAD_TRUE: frame->push(True); break; case OP_LOAD_TRUE: frame->push(True); break;
@ -203,24 +203,24 @@ protected:
case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); break; case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); break;
case OP_ASSERT: case OP_ASSERT:
{ {
PyVar expr = frame->popValue(this); PyVar expr = frame->pop_value(this);
_assert(PyBool_AS_C(expr), "assertion failed"); _assert(PyBool_AS_C(expr), "assertion failed");
} break; } break;
case OP_RAISE_ERROR: case OP_RAISE_ERROR:
{ {
_Str msg = PyStr_AS_C(asRepr(frame->popValue(this))); _Str msg = PyStr_AS_C(asRepr(frame->pop_value(this)));
_Str type = PyStr_AS_C(frame->popValue(this)); _Str type = PyStr_AS_C(frame->pop_value(this));
_error(type, msg); _error(type, msg);
} break; } break;
case OP_BUILD_LIST: case OP_BUILD_LIST:
{ {
frame->push(PyList( frame->push(PyList(
frame->popNValuesReversedUnlimited(this, byte.arg) frame->pop_n_values_reversed_unlimited(this, byte.arg)
)); ));
} break; } break;
case OP_BUILD_MAP: case OP_BUILD_MAP:
{ {
PyVarList items = frame->popNValuesReversedUnlimited(this, byte.arg*2); PyVarList items = frame->pop_n_values_reversed_unlimited(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]));
@ -230,42 +230,42 @@ protected:
case OP_BUILD_SET: case OP_BUILD_SET:
{ {
PyVar list = PyList( PyVar list = PyList(
frame->popNValuesReversedUnlimited(this, byte.arg) frame->pop_n_values_reversed_unlimited(this, byte.arg)
); );
PyVar obj = call(builtins->attribs["set"], pkpy::oneArg(list)); PyVar obj = call(builtins->attribs["set"], pkpy::oneArg(list));
frame->push(obj); frame->push(obj);
} break; } break;
case OP_DUP_TOP: frame->push(frame->topValue(this)); break; case OP_DUP_TOP: frame->push(frame->top_value(this)); break;
case OP_CALL: case OP_CALL:
{ {
int ARGC = byte.arg & 0xFFFF; int ARGC = byte.arg & 0xFFFF;
int KWARGC = (byte.arg >> 16) & 0xFFFF; int KWARGC = (byte.arg >> 16) & 0xFFFF;
pkpy::ArgList kwargs(0); pkpy::ArgList kwargs(0);
if(KWARGC > 0) kwargs = frame->popNValuesReversed(this, KWARGC*2); if(KWARGC > 0) kwargs = frame->pop_n_values_reversed(this, KWARGC*2);
pkpy::ArgList args = frame->popNValuesReversed(this, ARGC); pkpy::ArgList args = frame->pop_n_values_reversed(this, ARGC);
PyVar callable = frame->popValue(this); PyVar callable = frame->pop_value(this);
PyVar ret = call(callable, std::move(args), kwargs, true); PyVar ret = call(callable, std::move(args), kwargs, true);
if(ret == __py2py_call_signal) return ret; if(ret == __py2py_call_signal) return ret;
frame->push(std::move(ret)); frame->push(std::move(ret));
} break; } break;
case OP_JUMP_ABSOLUTE: frame->jumpAbsolute(byte.arg); break; case OP_JUMP_ABSOLUTE: frame->jump_abs(byte.arg); break;
case OP_SAFE_JUMP_ABSOLUTE: frame->jumpAbsoluteSafe(byte.arg); break; case OP_SAFE_JUMP_ABSOLUTE: frame->jump_abs_safe(byte.arg); break;
case OP_GOTO: { case OP_GOTO: {
PyVar obj = frame->popValue(this); PyVar obj = frame->pop_value(this);
const _Str& label = PyStr_AS_C(obj); const _Str& label = PyStr_AS_C(obj);
int* target = frame->code->co_labels.try_get(label); int* target = frame->code->co_labels.try_get(label);
if(target == nullptr){ if(target == nullptr){
_error("KeyError", "label '" + label + "' not found"); _error("KeyError", "label '" + label + "' not found");
} }
frame->jumpAbsoluteSafe(*target); frame->jump_abs_safe(*target);
} break; } break;
case OP_GET_ITER: case OP_GET_ITER:
{ {
PyVar obj = frame->popValue(this); PyVar obj = frame->pop_value(this);
PyVarOrNull iter_fn = getAttr(obj, __iter__, false); PyVarOrNull iter_fn = getAttr(obj, __iter__, false);
if(iter_fn != nullptr){ if(iter_fn != nullptr){
PyVar tmp = call(iter_fn); PyVar tmp = call(iter_fn);
PyVarRef var = frame->__pop(); PyVarRef var = frame->pop();
__checkType(var, _tp_ref); __checkType(var, _tp_ref);
PyIter_AS_C(tmp)->var = var; PyIter_AS_C(tmp)->var = var;
frame->push(std::move(tmp)); frame->push(std::move(tmp));
@ -275,41 +275,41 @@ protected:
} break; } break;
case OP_FOR_ITER: case OP_FOR_ITER:
{ {
// __top() must be PyIter, so no need to try_deref() // top() must be PyIter, so no need to try_deref()
auto& it = PyIter_AS_C(frame->__top()); auto& it = PyIter_AS_C(frame->top());
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->code->co_blocks[byte.block].end;
frame->jumpAbsoluteSafe(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->code->co_blocks[byte.block].start;
frame->jumpAbsolute(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->code->co_blocks[byte.block].end;
frame->jumpAbsoluteSafe(blockEnd); frame->jump_abs_safe(blockEnd);
} break; } break;
case OP_JUMP_IF_FALSE_OR_POP: case OP_JUMP_IF_FALSE_OR_POP:
{ {
const PyVar expr = frame->topValue(this); const PyVar expr = frame->top_value(this);
if(asBool(expr)==False) frame->jumpAbsolute(byte.arg); if(asBool(expr)==False) frame->jump_abs(byte.arg);
else frame->popValue(this); else frame->pop_value(this);
} break; } break;
case OP_JUMP_IF_TRUE_OR_POP: case OP_JUMP_IF_TRUE_OR_POP:
{ {
const PyVar expr = frame->topValue(this); const PyVar expr = frame->top_value(this);
if(asBool(expr)==True) frame->jumpAbsolute(byte.arg); if(asBool(expr)==True) frame->jump_abs(byte.arg);
else frame->popValue(this); else frame->pop_value(this);
} break; } break;
case OP_BUILD_SLICE: case OP_BUILD_SLICE:
{ {
PyVar stop = frame->popValue(this); PyVar stop = frame->pop_value(this);
PyVar start = frame->popValue(this); PyVar start = frame->pop_value(this);
_Slice s; _Slice s;
if(start != None) {__checkType(start, _tp_int); s.start = (int)PyInt_AS_C(start);} if(start != None) {__checkType(start, _tp_int); s.start = (int)PyInt_AS_C(start);}
if(stop != None) {__checkType(stop, _tp_int); s.stop = (int)PyInt_AS_C(stop);} if(stop != None) {__checkType(stop, _tp_int); s.stop = (int)PyInt_AS_C(stop);}
@ -320,8 +320,8 @@ protected:
const _Str& name = frame->code->co_names[byte.arg].first; const _Str& name = frame->code->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 = _lazyModules.find(name); auto it2 = _lazy_modules.find(name);
if(it2 == _lazyModules.end()){ if(it2 == _lazy_modules.end()){
_error("ImportError", "module '" + name + "' not found"); _error("ImportError", "module '" + name + "' not found");
}else{ }else{
const _Str& source = it2->second; const _Str& source = it2->second;
@ -329,15 +329,15 @@ protected:
PyVar _m = newModule(name); PyVar _m = newModule(name);
_exec(code, _m, {}); _exec(code, _m, {});
frame->push(_m); frame->push(_m);
_lazyModules.erase(it2); _lazy_modules.erase(it2);
} }
}else{ }else{
frame->push(it->second); frame->push(it->second);
} }
} break; } break;
// TODO: using "goto" inside with block may cause __exit__ not called // TODO: using "goto" inside with block may cause __exit__ not called
case OP_WITH_ENTER: call(frame->popValue(this), __enter__); break; case OP_WITH_ENTER: call(frame->pop_value(this), __enter__); break;
case OP_WITH_EXIT: call(frame->popValue(this), __exit__); break; case OP_WITH_EXIT: call(frame->pop_value(this), __exit__); break;
default: default:
systemError(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented"); systemError(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
break; break;
@ -345,11 +345,11 @@ protected:
} }
if(frame->code->src->mode == EVAL_MODE || frame->code->src->mode == JSON_MODE){ if(frame->code->src->mode == EVAL_MODE || frame->code->src->mode == JSON_MODE){
if(frame->stackSize() != 1) systemError("stack size is not 1 in EVAL_MODE/JSON_MODE"); if(frame->stack_size() != 1) systemError("stack size is not 1 in EVAL_MODE/JSON_MODE");
return frame->popValue(this); return frame->pop_value(this);
} }
if(frame->stackSize() != 0) systemError("stack not empty in EXEC_MODE"); if(frame->stack_size() != 0) systemError("stack not empty in EXEC_MODE");
return None; return None;
} }
@ -380,18 +380,18 @@ public:
} }
initializeBuiltinClasses(); initializeBuiltinClasses();
_smallIntegers.reserve(300); _small_integers.reserve(300);
for(_Int i=-5; i<=256; i++) _smallIntegers.push_back(newObject(_tp_int, i)); for(_Int i=-5; i<=256; i++) _small_integers.push_back(newObject(_tp_int, i));
} }
void keyboardInterrupt(){ void keyboardInterrupt(){
_stopFlag = true; _stop_flag = true;
} }
void sleepForSecs(_Float sec){ void sleepForSecs(_Float sec){
_Int ms = (_Int)(sec * 1000); _Int ms = (_Int)(sec * 1000);
for(_Int i=0; i<ms; i+=20){ for(_Int i=0; i<ms; i+=20){
_checkStopFlag(); test_stop_flag();
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
emscripten_sleep(20); emscripten_sleep(20);
#else #else
@ -590,7 +590,7 @@ public:
PyVar ret = nullptr; PyVar ret = nullptr;
while(true){ while(true){
ret = runFrame(frame); ret = run_frame(frame);
if(ret != __py2py_call_signal){ if(ret != __py2py_call_signal){
if(frame == frameBase){ // [ frameBase<- ] if(frame == frameBase){ // [ frameBase<- ]
break; break;
@ -640,7 +640,7 @@ public:
} }
void addLazyModule(_Str name, _Str source){ void addLazyModule(_Str name, _Str source){
_lazyModules[name] = 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) {
@ -774,7 +774,7 @@ public:
ss << code->name << ":\n"; ss << code->name << ":\n";
int prev_line = -1; int prev_line = -1;
for(int i=0; i<code->co_code.size(); i++){ for(int i=0; i<code->co_code.size(); i++){
const ByteCode& byte = code->co_code[i]; const Bytecode& byte = code->co_code[i];
_Str line = std::to_string(byte.line); _Str line = std::to_string(byte.line);
if(byte.line == prev_line) line = ""; if(byte.line == prev_line) line = "";
else{ else{
@ -799,7 +799,7 @@ public:
argStr += " (" + code->co_names[byte.arg].first.__escape(true) + ")"; argStr += " (" + code->co_names[byte.arg].first.__escape(true) + ")";
} }
ss << pad(argStr, 20); // may overflow ss << pad(argStr, 20); // may overflow
ss << code->co_blocks[byte.block].toString(); ss << code->co_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;
@ -846,7 +846,7 @@ public:
__DEF_PY_AS_C(Int, _Int, _tp_int) __DEF_PY_AS_C(Int, _Int, _tp_int)
inline PyVar PyInt(_Int value) { inline PyVar PyInt(_Int value) {
if(value >= -5 && value <= 256) return _smallIntegers[value + 5]; if(value >= -5 && value <= 256) return _small_integers[value + 5];
return newObject(_tp_int, value); return newObject(_tp_int, value);
} }
@ -949,7 +949,7 @@ private:
std::stack<_Str> snapshots; std::stack<_Str> snapshots;
while (!callstack.empty()){ while (!callstack.empty()){
if(snapshots.size() < 8){ if(snapshots.size() < 8){
snapshots.push(callstack.back()->errorSnapshot()); snapshots.push(callstack.back()->curr_snapshot());
} }
callstack.pop_back(); callstack.pop_back();
} }
@ -1183,7 +1183,7 @@ public:
if(_state != THREAD_RUNNING) UNREACHABLE(); if(_state != THREAD_RUNNING) UNREACHABLE();
_state = THREAD_SUSPENDED; _state = THREAD_SUSPENDED;
while(_state == THREAD_SUSPENDED){ while(_state == THREAD_SUSPENDED){
_checkStopFlag(); test_stop_flag();
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
emscripten_sleep(20); emscripten_sleep(20);
#else #else