mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 12:00:18 +00:00
up
This commit is contained in:
parent
6ebd78e7ae
commit
41b7c1adb9
File diff suppressed because it is too large
Load Diff
@ -1 +1 @@
|
||||
Subproject commit 647691921747b5c2a242df30c5639d0410a6b621
|
||||
Subproject commit 8663b7ea6ff8e7b0bf5b15bf3f12d38b1384165b
|
102
src/codeobject.h
102
src/codeobject.h
@ -16,7 +16,7 @@ static const char* OP_NAMES[] = {
|
||||
#undef OPCODE
|
||||
};
|
||||
|
||||
struct ByteCode{
|
||||
struct Bytecode{
|
||||
uint8_t op;
|
||||
int arg;
|
||||
int line;
|
||||
@ -44,7 +44,7 @@ struct CodeBlock {
|
||||
int start; // start index of this block in co_code, inclusive
|
||||
int end; // end index of this block in co_code, exclusive
|
||||
|
||||
std::string toString() const {
|
||||
std::string to_string() const {
|
||||
if(parent == -1) return "";
|
||||
std::string s = "[";
|
||||
for(int i = 0; i < id.size(); i++){
|
||||
@ -57,17 +57,9 @@ struct CodeBlock {
|
||||
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();
|
||||
}
|
||||
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 {
|
||||
@ -79,11 +71,7 @@ struct CodeObject {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
CompileMode mode() const {
|
||||
return src->mode;
|
||||
}
|
||||
|
||||
std::vector<ByteCode> co_code;
|
||||
std::vector<Bytecode> co_code;
|
||||
PyVarList co_consts;
|
||||
std::vector<std::pair<_Str, NameScope>> co_names;
|
||||
std::vector<_Str> co_global_names;
|
||||
@ -121,7 +109,7 @@ struct CodeObject {
|
||||
// goto/label should be put at toplevel statements
|
||||
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()){
|
||||
_Str msg = "label '" + label + "' already exists";
|
||||
throw std::runtime_error(msg.c_str());
|
||||
@ -129,7 +117,7 @@ struct CodeObject {
|
||||
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()){
|
||||
scope = NAME_GLOBAL;
|
||||
}
|
||||
@ -141,7 +129,7 @@ struct CodeObject {
|
||||
return co_names.size() - 1;
|
||||
}
|
||||
|
||||
int addConst(PyVar v){
|
||||
int add_const(PyVar v){
|
||||
co_consts.push_back(v);
|
||||
return co_consts.size() - 1;
|
||||
}
|
||||
@ -150,7 +138,7 @@ struct CodeObject {
|
||||
for(int i=0; i<co_code.size(); i++){
|
||||
if(co_code[i].op >= OP_BINARY_OP && co_code[i].op <= OP_CONTAINS_OP){
|
||||
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_NAME_REF){
|
||||
bc.op = OP_LOAD_NAME;
|
||||
@ -164,7 +152,7 @@ struct CodeObject {
|
||||
int KWARGC = (co_code[i].arg >> 16) & 0xFFFF;
|
||||
if(KWARGC != 0) continue;
|
||||
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_NAME_REF){
|
||||
bc.op = OP_LOAD_NAME;
|
||||
@ -192,38 +180,28 @@ public:
|
||||
PyVar _module;
|
||||
PyVarDict f_locals;
|
||||
|
||||
inline PyVarDict copy_f_locals() const {
|
||||
return f_locals;
|
||||
}
|
||||
|
||||
inline PyVarDict& f_globals(){
|
||||
return _module->attribs;
|
||||
}
|
||||
inline PyVarDict f_locals_copy() const { return f_locals; }
|
||||
inline PyVarDict& f_globals(){ return _module->attribs; }
|
||||
|
||||
Frame(const _Code code, PyVar _module, PyVarDict&& locals)
|
||||
: code(code), _module(_module), f_locals(std::move(locals)) {
|
||||
}
|
||||
|
||||
inline const ByteCode& next_bytecode() {
|
||||
inline const Bytecode& next_bytecode() {
|
||||
ip = next_ip;
|
||||
next_ip = ip + 1;
|
||||
return code->co_code[ip];
|
||||
}
|
||||
|
||||
_Str errorSnapshot(){
|
||||
_Str curr_snapshot(){
|
||||
int line = code->co_code[ip].line;
|
||||
return code->src->snapshot(line);
|
||||
}
|
||||
|
||||
inline int stackSize() const {
|
||||
return s_data.size();
|
||||
}
|
||||
inline int stack_size() const{ return s_data.size(); }
|
||||
inline bool has_next_bytecode() const{ return next_ip < code->co_code.size(); }
|
||||
|
||||
inline bool has_next_bytecode() const {
|
||||
return next_ip < code->co_code.size();
|
||||
}
|
||||
|
||||
inline PyVar __pop(){
|
||||
inline PyVar pop(){
|
||||
if(s_data.empty()) throw std::runtime_error("s_data.empty() is true");
|
||||
PyVar v = std::move(s_data.back());
|
||||
s_data.pop_back();
|
||||
@ -232,62 +210,58 @@ public:
|
||||
|
||||
inline void try_deref(VM*, PyVar&);
|
||||
|
||||
inline PyVar popValue(VM* vm){
|
||||
PyVar value = __pop();
|
||||
inline PyVar pop_value(VM* vm){
|
||||
PyVar value = pop();
|
||||
try_deref(vm, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline PyVar topValue(VM* vm){
|
||||
PyVar value = __top();
|
||||
inline PyVar top_value(VM* vm){
|
||||
PyVar value = top();
|
||||
try_deref(vm, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline PyVar& __top(){
|
||||
inline PyVar& top(){
|
||||
if(s_data.empty()) throw std::runtime_error("s_data.empty() is true");
|
||||
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];
|
||||
try_deref(vm, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void push(T&& obj){
|
||||
s_data.push_back(std::forward<T>(obj));
|
||||
}
|
||||
inline void push(T&& obj){ s_data.push_back(std::forward<T>(obj)); }
|
||||
|
||||
inline void jumpAbsolute(int i){
|
||||
next_ip = i;
|
||||
}
|
||||
inline void jump_abs(int i){ next_ip = i; }
|
||||
|
||||
void jumpAbsoluteSafe(int target){
|
||||
const ByteCode& prev = code->co_code[ip];
|
||||
void jump_abs_safe(int target){
|
||||
const Bytecode& prev = code->co_code[ip];
|
||||
int i = prev.block;
|
||||
next_ip = target;
|
||||
if(next_ip >= code->co_code.size()){
|
||||
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;
|
||||
}
|
||||
}else{
|
||||
const ByteCode& next = code->co_code[target];
|
||||
const Bytecode& next = code->co_code[target];
|
||||
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;
|
||||
}
|
||||
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;
|
||||
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);
|
||||
for(int i=n-1; i>=0; i--){
|
||||
v._index(i) = std::move(s_data[new_size + i]);
|
||||
@ -297,15 +271,15 @@ public:
|
||||
return v;
|
||||
}
|
||||
|
||||
PyVarList popNValuesReversedUnlimited(VM* vm, int n){
|
||||
PyVarList pop_n_values_reversed_unlimited(VM* vm, int 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;
|
||||
}
|
||||
|
||||
pkpy::ArgList __popNReversed(int n){
|
||||
pkpy::ArgList pop_n_reversed(int 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;
|
||||
}
|
||||
};
|
429
src/compiler.h
429
src/compiler.h
@ -27,7 +27,7 @@ public:
|
||||
|
||||
emhash8::HashMap<_TokenType, GrammarRule> rules;
|
||||
|
||||
_Code getCode() {
|
||||
_Code co() {
|
||||
return codes.top();
|
||||
}
|
||||
|
||||
@ -204,13 +204,13 @@ public:
|
||||
|
||||
// Lex the next token and set it as the next token.
|
||||
void _lexToken() {
|
||||
parser->previous = parser->current;
|
||||
parser->current = parser->nextToken();
|
||||
parser->prev = parser->curr;
|
||||
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') {
|
||||
parser->token_start = parser->current_char;
|
||||
while (parser->peek_char() != '\0') {
|
||||
parser->token_start = parser->curr_char;
|
||||
char c = parser->eatCharIncludeNewLine();
|
||||
switch (c) {
|
||||
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"));
|
||||
}
|
||||
|
||||
inline _TokenType peek() {
|
||||
return parser->current.type;
|
||||
return parser->curr.type;
|
||||
}
|
||||
|
||||
// not sure this will work
|
||||
_TokenType peekNext() {
|
||||
_TokenType peek_next() {
|
||||
if(parser->nexts.empty()) return TK("@eof");
|
||||
return parser->nexts.front().type;
|
||||
}
|
||||
@ -370,14 +370,14 @@ public:
|
||||
}
|
||||
|
||||
void exprLiteral() {
|
||||
PyVar value = parser->previous.value;
|
||||
int index = getCode()->addConst(value);
|
||||
emitCode(OP_LOAD_CONST, index);
|
||||
PyVar value = parser->prev.value;
|
||||
int index = co()->add_const(value);
|
||||
emit(OP_LOAD_CONST, index);
|
||||
}
|
||||
|
||||
void exprFString() {
|
||||
static const std::regex pattern(R"(\{(.*?)\})");
|
||||
PyVar value = parser->previous.value;
|
||||
PyVar value = parser->prev.value;
|
||||
_Str s = vm->PyStr_AS_C(value);
|
||||
std::sregex_iterator begin(s.begin(), s.end(), pattern);
|
||||
std::sregex_iterator end;
|
||||
@ -387,21 +387,21 @@ public:
|
||||
std::smatch m = *it;
|
||||
if (i < m.position()) {
|
||||
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++;
|
||||
}
|
||||
emitCode(OP_LOAD_EVAL_FN);
|
||||
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(m[1].str())));
|
||||
emitCode(OP_CALL, 1);
|
||||
emit(OP_LOAD_EVAL_FN);
|
||||
emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(m[1].str())));
|
||||
emit(OP_CALL, 1);
|
||||
size++;
|
||||
i = (int)(m.position() + m.length());
|
||||
}
|
||||
if (i < s.size()) {
|
||||
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++;
|
||||
}
|
||||
emitCode(OP_BUILD_STRING, size);
|
||||
emit(OP_BUILD_STRING, size);
|
||||
}
|
||||
|
||||
void exprLambda() {
|
||||
@ -414,35 +414,35 @@ public:
|
||||
func->code = pkpy::make_shared<CodeObject>(parser->src, func->name);
|
||||
this->codes.push(func->code);
|
||||
EXPR_TUPLE();
|
||||
emitCode(OP_RETURN_VALUE);
|
||||
emit(OP_RETURN_VALUE);
|
||||
func->code->optimize();
|
||||
this->codes.pop();
|
||||
emitCode(OP_LOAD_LAMBDA, getCode()->addConst(vm->PyFunction(func)));
|
||||
emit(OP_LOAD_LAMBDA, co()->add_const(vm->PyFunction(func)));
|
||||
}
|
||||
|
||||
void exprAssign() {
|
||||
_TokenType op = parser->previous.type;
|
||||
_TokenType op = parser->prev.type;
|
||||
if(op == TK("=")) { // a = (expr)
|
||||
EXPR_TUPLE();
|
||||
emitCode(OP_STORE_REF);
|
||||
emit(OP_STORE_REF);
|
||||
}else{ // a += (expr) -> a = a + (expr)
|
||||
// TODO: optimization is needed for inplace operators
|
||||
emitCode(OP_DUP_TOP);
|
||||
emit(OP_DUP_TOP);
|
||||
EXPR();
|
||||
switch (op) {
|
||||
case TK("+="): emitCode(OP_BINARY_OP, 0); break;
|
||||
case TK("-="): emitCode(OP_BINARY_OP, 1); break;
|
||||
case TK("*="): emitCode(OP_BINARY_OP, 2); break;
|
||||
case TK("/="): emitCode(OP_BINARY_OP, 3); break;
|
||||
case TK("//="): emitCode(OP_BINARY_OP, 4); break;
|
||||
case TK("+="): emit(OP_BINARY_OP, 0); break;
|
||||
case TK("-="): emit(OP_BINARY_OP, 1); break;
|
||||
case TK("*="): emit(OP_BINARY_OP, 2); break;
|
||||
case TK("/="): emit(OP_BINARY_OP, 3); break;
|
||||
case TK("//="): emit(OP_BINARY_OP, 4); break;
|
||||
|
||||
case TK("%="): emitCode(OP_BINARY_OP, 5); break;
|
||||
case TK("&="): emitCode(OP_BITWISE_OP, 2); break;
|
||||
case TK("|="): emitCode(OP_BITWISE_OP, 3); break;
|
||||
case TK("^="): emitCode(OP_BITWISE_OP, 4); break;
|
||||
case TK("%="): emit(OP_BINARY_OP, 5); break;
|
||||
case TK("&="): emit(OP_BITWISE_OP, 2); break;
|
||||
case TK("|="): emit(OP_BITWISE_OP, 3); break;
|
||||
case TK("^="): emit(OP_BITWISE_OP, 4); break;
|
||||
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
|
||||
size++;
|
||||
} while(match(TK(",")));
|
||||
emitCode(OP_BUILD_SMART_TUPLE, size);
|
||||
emit(OP_BUILD_SMART_TUPLE, size);
|
||||
}
|
||||
|
||||
void exprOr() {
|
||||
int patch = emitCode(OP_JUMP_IF_TRUE_OR_POP);
|
||||
int patch = emit(OP_JUMP_IF_TRUE_OR_POP);
|
||||
parsePrecedence(PREC_LOGICAL_OR);
|
||||
patchJump(patch);
|
||||
patch_jump(patch);
|
||||
}
|
||||
|
||||
void exprAnd() {
|
||||
int patch = emitCode(OP_JUMP_IF_FALSE_OR_POP);
|
||||
int patch = emit(OP_JUMP_IF_FALSE_OR_POP);
|
||||
parsePrecedence(PREC_LOGICAL_AND);
|
||||
patchJump(patch);
|
||||
patch_jump(patch);
|
||||
}
|
||||
|
||||
void exprTernary() {
|
||||
int patch = emitCode(OP_POP_JUMP_IF_FALSE);
|
||||
int patch = emit(OP_POP_JUMP_IF_FALSE);
|
||||
EXPR(); // if true
|
||||
int patch2 = emitCode(OP_JUMP_ABSOLUTE);
|
||||
int patch2 = emit(OP_JUMP_ABSOLUTE);
|
||||
consume(TK(":"));
|
||||
patchJump(patch);
|
||||
patch_jump(patch);
|
||||
EXPR(); // if false
|
||||
patchJump(patch2);
|
||||
patch_jump(patch2);
|
||||
}
|
||||
|
||||
void exprBinaryOp() {
|
||||
_TokenType op = parser->previous.type;
|
||||
_TokenType op = parser->prev.type;
|
||||
parsePrecedence((Precedence)(rules[op].precedence + 1));
|
||||
|
||||
switch (op) {
|
||||
case TK("+"): emitCode(OP_BINARY_OP, 0); break;
|
||||
case TK("-"): emitCode(OP_BINARY_OP, 1); break;
|
||||
case TK("*"): emitCode(OP_BINARY_OP, 2); break;
|
||||
case TK("/"): emitCode(OP_BINARY_OP, 3); break;
|
||||
case TK("//"): emitCode(OP_BINARY_OP, 4); break;
|
||||
case TK("%"): emitCode(OP_BINARY_OP, 5); break;
|
||||
case TK("**"): emitCode(OP_BINARY_OP, 6); break;
|
||||
case TK("+"): emit(OP_BINARY_OP, 0); break;
|
||||
case TK("-"): emit(OP_BINARY_OP, 1); break;
|
||||
case TK("*"): emit(OP_BINARY_OP, 2); break;
|
||||
case TK("/"): emit(OP_BINARY_OP, 3); break;
|
||||
case TK("//"): emit(OP_BINARY_OP, 4); break;
|
||||
case TK("%"): emit(OP_BINARY_OP, 5); break;
|
||||
case TK("**"): emit(OP_BINARY_OP, 6); break;
|
||||
|
||||
case TK("<"): emitCode(OP_COMPARE_OP, 0); break;
|
||||
case TK("<="): emitCode(OP_COMPARE_OP, 1); break;
|
||||
case TK("=="): emitCode(OP_COMPARE_OP, 2); break;
|
||||
case TK("!="): emitCode(OP_COMPARE_OP, 3); break;
|
||||
case TK(">"): emitCode(OP_COMPARE_OP, 4); break;
|
||||
case TK(">="): emitCode(OP_COMPARE_OP, 5); break;
|
||||
case TK("in"): emitCode(OP_CONTAINS_OP, 0); break;
|
||||
case TK("not in"): emitCode(OP_CONTAINS_OP, 1); break;
|
||||
case TK("is"): emitCode(OP_IS_OP, 0); break;
|
||||
case TK("is not"): emitCode(OP_IS_OP, 1); break;
|
||||
case TK("<"): emit(OP_COMPARE_OP, 0); break;
|
||||
case TK("<="): emit(OP_COMPARE_OP, 1); break;
|
||||
case TK("=="): emit(OP_COMPARE_OP, 2); break;
|
||||
case TK("!="): emit(OP_COMPARE_OP, 3); break;
|
||||
case TK(">"): emit(OP_COMPARE_OP, 4); break;
|
||||
case TK(">="): emit(OP_COMPARE_OP, 5); break;
|
||||
case TK("in"): emit(OP_CONTAINS_OP, 0); break;
|
||||
case TK("not in"): emit(OP_CONTAINS_OP, 1); break;
|
||||
case TK("is"): emit(OP_IS_OP, 0); break;
|
||||
case TK("is not"): emit(OP_IS_OP, 1); break;
|
||||
|
||||
case TK("<<"): emitCode(OP_BITWISE_OP, 0); break;
|
||||
case TK(">>"): emitCode(OP_BITWISE_OP, 1); break;
|
||||
case TK("&"): emitCode(OP_BITWISE_OP, 2); break;
|
||||
case TK("|"): emitCode(OP_BITWISE_OP, 3); break;
|
||||
case TK("^"): emitCode(OP_BITWISE_OP, 4); break;
|
||||
case TK("<<"): emit(OP_BITWISE_OP, 0); break;
|
||||
case TK(">>"): emit(OP_BITWISE_OP, 1); break;
|
||||
case TK("&"): emit(OP_BITWISE_OP, 2); break;
|
||||
case TK("|"): emit(OP_BITWISE_OP, 3); break;
|
||||
case TK("^"): emit(OP_BITWISE_OP, 4); break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void exprUnaryOp() {
|
||||
_TokenType op = parser->previous.type;
|
||||
_TokenType op = parser->prev.type;
|
||||
matchNewLines();
|
||||
parsePrecedence((Precedence)(PREC_UNARY + 1));
|
||||
|
||||
switch (op) {
|
||||
case TK("-"): emitCode(OP_UNARY_NEGATIVE); break;
|
||||
case TK("not"): emitCode(OP_UNARY_NOT); break;
|
||||
case TK("-"): emit(OP_UNARY_NEGATIVE); break;
|
||||
case TK("not"): emit(OP_UNARY_NOT); break;
|
||||
case TK("*"): syntaxError("cannot use '*' as unary operator"); break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
@ -531,8 +531,8 @@ public:
|
||||
}
|
||||
|
||||
void exprList() {
|
||||
int _patch = emitCode(OP_NO_OP);
|
||||
int _body_start = getCode()->co_code.size();
|
||||
int _patch = emit(OP_NO_OP);
|
||||
int _body_start = co()->co_code.size();
|
||||
int ARGC = 0;
|
||||
do {
|
||||
matchNewLines(mode()==SINGLE_MODE);
|
||||
@ -543,47 +543,47 @@ public:
|
||||
} while (match(TK(",")));
|
||||
matchNewLines(mode()==SINGLE_MODE);
|
||||
consume(TK("]"));
|
||||
emitCode(OP_BUILD_LIST, ARGC);
|
||||
emit(OP_BUILD_LIST, ARGC);
|
||||
return;
|
||||
|
||||
__LISTCOMP:
|
||||
int _body_end_return = emitCode(OP_JUMP_ABSOLUTE, -1);
|
||||
int _body_end = getCode()->co_code.size();
|
||||
getCode()->co_code[_patch].op = OP_JUMP_ABSOLUTE;
|
||||
getCode()->co_code[_patch].arg = _body_end;
|
||||
emitCode(OP_BUILD_LIST, 0);
|
||||
int _body_end_return = emit(OP_JUMP_ABSOLUTE, -1);
|
||||
int _body_end = co()->co_code.size();
|
||||
co()->co_code[_patch].op = OP_JUMP_ABSOLUTE;
|
||||
co()->co_code[_patch].arg = _body_end;
|
||||
emit(OP_BUILD_LIST, 0);
|
||||
EXPR_FOR_VARS();consume(TK("in"));EXPR_TUPLE();
|
||||
matchNewLines(mode()==SINGLE_MODE);
|
||||
|
||||
int _skipPatch = emitCode(OP_JUMP_ABSOLUTE);
|
||||
int _cond_start = getCode()->co_code.size();
|
||||
int _skipPatch = emit(OP_JUMP_ABSOLUTE);
|
||||
int _cond_start = co()->co_code.size();
|
||||
int _cond_end_return = -1;
|
||||
if(match(TK("if"))) {
|
||||
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);
|
||||
getCode()->__enterBlock(FOR_LOOP);
|
||||
emitCode(OP_FOR_ITER);
|
||||
emit(OP_GET_ITER);
|
||||
co()->__enterBlock(FOR_LOOP);
|
||||
emit(OP_FOR_ITER);
|
||||
|
||||
if(_cond_end_return != -1) { // there is an if condition
|
||||
emitCode(OP_JUMP_ABSOLUTE, _cond_start);
|
||||
patchJump(_cond_end_return);
|
||||
int ifpatch = emitCode(OP_POP_JUMP_IF_FALSE);
|
||||
emitCode(OP_JUMP_ABSOLUTE, _body_start);
|
||||
patchJump(_body_end_return);
|
||||
emitCode(OP_LIST_APPEND);
|
||||
patchJump(ifpatch);
|
||||
emit(OP_JUMP_ABSOLUTE, _cond_start);
|
||||
patch_jump(_cond_end_return);
|
||||
int ifpatch = emit(OP_POP_JUMP_IF_FALSE);
|
||||
emit(OP_JUMP_ABSOLUTE, _body_start);
|
||||
patch_jump(_body_end_return);
|
||||
emit(OP_LIST_APPEND);
|
||||
patch_jump(ifpatch);
|
||||
}else{
|
||||
emitCode(OP_JUMP_ABSOLUTE, _body_start);
|
||||
patchJump(_body_end_return);
|
||||
emitCode(OP_LIST_APPEND);
|
||||
emit(OP_JUMP_ABSOLUTE, _body_start);
|
||||
patch_jump(_body_end_return);
|
||||
emit(OP_LIST_APPEND);
|
||||
}
|
||||
|
||||
emitCode(OP_LOOP_CONTINUE); keepOpcodeLine();
|
||||
getCode()->__exitBlock();
|
||||
emit(OP_LOOP_CONTINUE, -1, true);
|
||||
co()->__exitBlock();
|
||||
matchNewLines(mode()==SINGLE_MODE);
|
||||
consume(TK("]"));
|
||||
}
|
||||
@ -606,8 +606,8 @@ __LISTCOMP:
|
||||
matchNewLines();
|
||||
consume(TK("}"));
|
||||
|
||||
if(size == 0 || parsing_dict) emitCode(OP_BUILD_MAP, size);
|
||||
else emitCode(OP_BUILD_SET, size);
|
||||
if(size == 0 || parsing_dict) emit(OP_BUILD_MAP, size);
|
||||
else emit(OP_BUILD_SET, size);
|
||||
}
|
||||
|
||||
void exprCall() {
|
||||
@ -616,10 +616,10 @@ __LISTCOMP:
|
||||
do {
|
||||
matchNewLines(mode()==SINGLE_MODE);
|
||||
if (peek() == TK(")")) break;
|
||||
if(peek() == TK("@id") && peekNext() == TK("=")) {
|
||||
if(peek() == TK("@id") && peek_next() == TK("=")) {
|
||||
consume(TK("@id"));
|
||||
const _Str& key = parser->previous.str();
|
||||
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(key)));
|
||||
const _Str& key = parser->prev.str();
|
||||
emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(key)));
|
||||
consume(TK("="));
|
||||
EXPR();
|
||||
KWARGC++;
|
||||
@ -631,82 +631,79 @@ __LISTCOMP:
|
||||
matchNewLines(mode()==SINGLE_MODE);
|
||||
} while (match(TK(",")));
|
||||
consume(TK(")"));
|
||||
emitCode(OP_CALL, (KWARGC << 16) | ARGC);
|
||||
emit(OP_CALL, (KWARGC << 16) | ARGC);
|
||||
}
|
||||
|
||||
void exprName() {
|
||||
Token tkname = parser->previous;
|
||||
int index = getCode()->addName(
|
||||
Token tkname = parser->prev;
|
||||
int index = co()->add_name(
|
||||
tkname.str(),
|
||||
codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL
|
||||
);
|
||||
emitCode(OP_LOAD_NAME_REF, index);
|
||||
emit(OP_LOAD_NAME_REF, index);
|
||||
}
|
||||
|
||||
void exprAttrib() {
|
||||
consume(TK("@id"));
|
||||
const _Str& name = parser->previous.str();
|
||||
int index = getCode()->addName(name, NAME_ATTR);
|
||||
emitCode(OP_BUILD_ATTR_REF, index);
|
||||
const _Str& name = parser->prev.str();
|
||||
int index = co()->add_name(name, NAME_ATTR);
|
||||
emit(OP_BUILD_ATTR_REF, index);
|
||||
}
|
||||
|
||||
// [:], [:b]
|
||||
// [a], [a:], [a:b]
|
||||
void exprSubscript() {
|
||||
if(match(TK(":"))){
|
||||
emitCode(OP_LOAD_NONE);
|
||||
emit(OP_LOAD_NONE);
|
||||
if(match(TK("]"))){
|
||||
emitCode(OP_LOAD_NONE);
|
||||
emit(OP_LOAD_NONE);
|
||||
}else{
|
||||
EXPR_TUPLE();
|
||||
consume(TK("]"));
|
||||
}
|
||||
emitCode(OP_BUILD_SLICE);
|
||||
emit(OP_BUILD_SLICE);
|
||||
}else{
|
||||
EXPR_TUPLE();
|
||||
if(match(TK(":"))){
|
||||
if(match(TK("]"))){
|
||||
emitCode(OP_LOAD_NONE);
|
||||
emit(OP_LOAD_NONE);
|
||||
}else{
|
||||
EXPR_TUPLE();
|
||||
consume(TK("]"));
|
||||
}
|
||||
emitCode(OP_BUILD_SLICE);
|
||||
emit(OP_BUILD_SLICE);
|
||||
}else{
|
||||
consume(TK("]"));
|
||||
}
|
||||
}
|
||||
|
||||
emitCode(OP_BUILD_INDEX_REF);
|
||||
emit(OP_BUILD_INDEX_REF);
|
||||
}
|
||||
|
||||
void exprValue() {
|
||||
_TokenType op = parser->previous.type;
|
||||
_TokenType op = parser->prev.type;
|
||||
switch (op) {
|
||||
case TK("None"): emitCode(OP_LOAD_NONE); break;
|
||||
case TK("True"): emitCode(OP_LOAD_TRUE); break;
|
||||
case TK("False"): emitCode(OP_LOAD_FALSE); break;
|
||||
case TK("..."): emitCode(OP_LOAD_ELLIPSIS); break;
|
||||
case TK("None"): emit(OP_LOAD_NONE); break;
|
||||
case TK("True"): emit(OP_LOAD_TRUE); break;
|
||||
case TK("False"): emit(OP_LOAD_FALSE); break;
|
||||
case TK("..."): emit(OP_LOAD_ELLIPSIS); break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void keepOpcodeLine(){
|
||||
int i = getCode()->co_code.size() - 1;
|
||||
getCode()->co_code[i].line = getCode()->co_code[i-1].line;
|
||||
}
|
||||
|
||||
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}
|
||||
int emit(Opcode opcode, int arg=-1, bool keepline=false) {
|
||||
int line = parser->prev.line;
|
||||
co()->co_code.push_back(
|
||||
Bytecode{(uint8_t)opcode, arg, line, (uint16_t)co()->_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) {
|
||||
int target = getCode()->co_code.size();
|
||||
getCode()->co_code[addr_index].arg = target;
|
||||
inline void patch_jump(int addr_index) {
|
||||
int target = co()->co_code.size();
|
||||
co()->co_code[addr_index].arg = target;
|
||||
}
|
||||
|
||||
void compileBlockBody(){
|
||||
@ -729,9 +726,9 @@ __LISTCOMP:
|
||||
|
||||
Token compileImportPath() {
|
||||
consume(TK("@id"));
|
||||
Token tkmodule = parser->previous;
|
||||
int index = getCode()->addName(tkmodule.str(), NAME_GLOBAL);
|
||||
emitCode(OP_IMPORT_NAME, index);
|
||||
Token tkmodule = parser->prev;
|
||||
int index = co()->add_name(tkmodule.str(), NAME_GLOBAL);
|
||||
emit(OP_IMPORT_NAME, index);
|
||||
return tkmodule;
|
||||
}
|
||||
|
||||
@ -741,10 +738,10 @@ __LISTCOMP:
|
||||
Token tkmodule = compileImportPath();
|
||||
if (match(TK("as"))) {
|
||||
consume(TK("@id"));
|
||||
tkmodule = parser->previous;
|
||||
tkmodule = parser->prev;
|
||||
}
|
||||
int index = getCode()->addName(tkmodule.str(), NAME_GLOBAL);
|
||||
emitCode(OP_STORE_NAME_REF, index);
|
||||
int index = co()->add_name(tkmodule.str(), NAME_GLOBAL);
|
||||
emit(OP_STORE_NAME_REF, index);
|
||||
} while (match(TK(",")));
|
||||
consumeEndStatement();
|
||||
}
|
||||
@ -754,30 +751,30 @@ __LISTCOMP:
|
||||
Token tkmodule = compileImportPath();
|
||||
consume(TK("import"));
|
||||
do {
|
||||
emitCode(OP_DUP_TOP);
|
||||
emit(OP_DUP_TOP);
|
||||
consume(TK("@id"));
|
||||
Token tkname = parser->previous;
|
||||
int index = getCode()->addName(tkname.str(), NAME_GLOBAL);
|
||||
emitCode(OP_BUILD_ATTR_REF, index);
|
||||
Token tkname = parser->prev;
|
||||
int index = co()->add_name(tkname.str(), NAME_GLOBAL);
|
||||
emit(OP_BUILD_ATTR_REF, index);
|
||||
if (match(TK("as"))) {
|
||||
consume(TK("@id"));
|
||||
tkname = parser->previous;
|
||||
tkname = parser->prev;
|
||||
}
|
||||
index = getCode()->addName(tkname.str(), NAME_GLOBAL);
|
||||
emitCode(OP_STORE_NAME_REF, index);
|
||||
index = co()->add_name(tkname.str(), NAME_GLOBAL);
|
||||
emit(OP_STORE_NAME_REF, index);
|
||||
} while (match(TK(",")));
|
||||
emitCode(OP_POP_TOP);
|
||||
emit(OP_POP_TOP);
|
||||
consumeEndStatement();
|
||||
}
|
||||
|
||||
void parsePrecedence(Precedence precedence) {
|
||||
lexToken();
|
||||
GrammarFn prefix = rules[parser->previous.type].prefix;
|
||||
if (prefix == nullptr) syntaxError(_Str("expected an expression, but got ") + TK_STR(parser->previous.type));
|
||||
GrammarFn prefix = rules[parser->prev.type].prefix;
|
||||
if (prefix == nullptr) syntaxError(_Str("expected an expression, but got ") + TK_STR(parser->prev.type));
|
||||
(this->*prefix)();
|
||||
while (rules[peek()].precedence >= precedence) {
|
||||
lexToken();
|
||||
_TokenType op = parser->previous.type;
|
||||
_TokenType op = parser->prev.type;
|
||||
GrammarFn infix = rules[op].infix;
|
||||
if(infix == nullptr) throw std::runtime_error("(infix == nullptr) is true");
|
||||
(this->*infix)();
|
||||
@ -788,32 +785,32 @@ __LISTCOMP:
|
||||
matchNewLines();
|
||||
EXPR_TUPLE();
|
||||
|
||||
int ifpatch = emitCode(OP_POP_JUMP_IF_FALSE);
|
||||
int ifpatch = emit(OP_POP_JUMP_IF_FALSE);
|
||||
compileBlockBody();
|
||||
|
||||
if (match(TK("elif"))) {
|
||||
int exit_jump = emitCode(OP_JUMP_ABSOLUTE);
|
||||
patchJump(ifpatch);
|
||||
int exit_jump = emit(OP_JUMP_ABSOLUTE);
|
||||
patch_jump(ifpatch);
|
||||
compileIfStatement();
|
||||
patchJump(exit_jump);
|
||||
patch_jump(exit_jump);
|
||||
} else if (match(TK("else"))) {
|
||||
int exit_jump = emitCode(OP_JUMP_ABSOLUTE);
|
||||
patchJump(ifpatch);
|
||||
int exit_jump = emit(OP_JUMP_ABSOLUTE);
|
||||
patch_jump(ifpatch);
|
||||
compileBlockBody();
|
||||
patchJump(exit_jump);
|
||||
patch_jump(exit_jump);
|
||||
} else {
|
||||
patchJump(ifpatch);
|
||||
patch_jump(ifpatch);
|
||||
}
|
||||
}
|
||||
|
||||
void compileWhileLoop() {
|
||||
getCode()->__enterBlock(WHILE_LOOP);
|
||||
co()->__enterBlock(WHILE_LOOP);
|
||||
EXPR_TUPLE();
|
||||
int patch = emitCode(OP_POP_JUMP_IF_FALSE);
|
||||
int patch = emit(OP_POP_JUMP_IF_FALSE);
|
||||
compileBlockBody();
|
||||
emitCode(OP_LOOP_CONTINUE); keepOpcodeLine();
|
||||
patchJump(patch);
|
||||
getCode()->__exitBlock();
|
||||
emit(OP_LOOP_CONTINUE, -1, true);
|
||||
patch_jump(patch);
|
||||
co()->__exitBlock();
|
||||
}
|
||||
|
||||
void EXPR_FOR_VARS(){
|
||||
@ -822,24 +819,24 @@ __LISTCOMP:
|
||||
consume(TK("@id"));
|
||||
exprName(); size++;
|
||||
} while (match(TK(",")));
|
||||
if(size > 1) emitCode(OP_BUILD_SMART_TUPLE, size);
|
||||
if(size > 1) emit(OP_BUILD_SMART_TUPLE, size);
|
||||
}
|
||||
|
||||
void compileForLoop() {
|
||||
EXPR_FOR_VARS();consume(TK("in")); EXPR_TUPLE();
|
||||
emitCode(OP_GET_ITER);
|
||||
getCode()->__enterBlock(FOR_LOOP);
|
||||
emitCode(OP_FOR_ITER);
|
||||
emit(OP_GET_ITER);
|
||||
co()->__enterBlock(FOR_LOOP);
|
||||
emit(OP_FOR_ITER);
|
||||
compileBlockBody();
|
||||
emitCode(OP_LOOP_CONTINUE); keepOpcodeLine();
|
||||
getCode()->__exitBlock();
|
||||
emit(OP_LOOP_CONTINUE, -1, true);
|
||||
co()->__exitBlock();
|
||||
}
|
||||
|
||||
void compileTryExcept() {
|
||||
getCode()->__enterBlock(TRY_EXCEPT);
|
||||
co()->__enterBlock(TRY_EXCEPT);
|
||||
compileBlockBody();
|
||||
int patch = emitCode(OP_JUMP_ABSOLUTE);
|
||||
getCode()->__exitBlock();
|
||||
int patch = emit(OP_JUMP_ABSOLUTE);
|
||||
co()->__exitBlock();
|
||||
consume(TK("except"));
|
||||
if(match(TK("@id"))){ // exception name
|
||||
compileBlockBody();
|
||||
@ -848,28 +845,28 @@ __LISTCOMP:
|
||||
consume(TK(":"));
|
||||
syntaxError("finally is not supported yet");
|
||||
}
|
||||
patchJump(patch);
|
||||
patch_jump(patch);
|
||||
}
|
||||
|
||||
void compileStatement() {
|
||||
if (match(TK("break"))) {
|
||||
if (!getCode()->__isCurrBlockLoop()) syntaxError("'break' outside loop");
|
||||
if (!co()->__isCurrBlockLoop()) syntaxError("'break' outside loop");
|
||||
consumeEndStatement();
|
||||
emitCode(OP_LOOP_BREAK);
|
||||
emit(OP_LOOP_BREAK);
|
||||
} else if (match(TK("continue"))) {
|
||||
if (!getCode()->__isCurrBlockLoop()) syntaxError("'continue' not properly in loop");
|
||||
if (!co()->__isCurrBlockLoop()) syntaxError("'continue' not properly in loop");
|
||||
consumeEndStatement();
|
||||
emitCode(OP_LOOP_CONTINUE);
|
||||
emit(OP_LOOP_CONTINUE);
|
||||
} else if (match(TK("return"))) {
|
||||
if (codes.size() == 1)
|
||||
syntaxError("'return' outside function");
|
||||
if(matchEndStatement()){
|
||||
emitCode(OP_LOAD_NONE);
|
||||
emit(OP_LOAD_NONE);
|
||||
}else{
|
||||
EXPR_TUPLE();
|
||||
consumeEndStatement();
|
||||
}
|
||||
emitCode(OP_RETURN_VALUE);
|
||||
emit(OP_RETURN_VALUE);
|
||||
} else if (match(TK("if"))) {
|
||||
compileIfStatement();
|
||||
} else if (match(TK("while"))) {
|
||||
@ -880,54 +877,54 @@ __LISTCOMP:
|
||||
compileTryExcept();
|
||||
}else if(match(TK("assert"))){
|
||||
EXPR();
|
||||
emitCode(OP_ASSERT);
|
||||
emit(OP_ASSERT);
|
||||
consumeEndStatement();
|
||||
} else if(match(TK("with"))){
|
||||
EXPR();
|
||||
consume(TK("as"));
|
||||
consume(TK("@id"));
|
||||
Token tkname = parser->previous;
|
||||
int index = getCode()->addName(
|
||||
Token tkname = parser->prev;
|
||||
int index = co()->add_name(
|
||||
tkname.str(),
|
||||
codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL
|
||||
);
|
||||
emitCode(OP_STORE_NAME_REF, index);
|
||||
emitCode(OP_LOAD_NAME_REF, index);
|
||||
emitCode(OP_WITH_ENTER);
|
||||
emit(OP_STORE_NAME_REF, index);
|
||||
emit(OP_LOAD_NAME_REF, index);
|
||||
emit(OP_WITH_ENTER);
|
||||
compileBlockBody();
|
||||
emitCode(OP_LOAD_NAME_REF, index);
|
||||
emitCode(OP_WITH_EXIT);
|
||||
emit(OP_LOAD_NAME_REF, index);
|
||||
emit(OP_WITH_EXIT);
|
||||
} else if(match(TK("label"))){
|
||||
if(mode() != EXEC_MODE) syntaxError("'label' is only available in EXEC_MODE");
|
||||
consume(TK(".")); consume(TK("@id"));
|
||||
getCode()->addLabel(parser->previous.str());
|
||||
co()->add_label(parser->prev.str());
|
||||
consumeEndStatement();
|
||||
} else if(match(TK("goto"))){
|
||||
// https://entrian.com/goto/
|
||||
if(mode() != EXEC_MODE) syntaxError("'goto' is only available in EXEC_MODE");
|
||||
consume(TK(".")); consume(TK("@id"));
|
||||
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str())));
|
||||
emitCode(OP_GOTO);
|
||||
emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(parser->prev.str())));
|
||||
emit(OP_GOTO);
|
||||
consumeEndStatement();
|
||||
} else if(match(TK("raise"))){
|
||||
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("("))){
|
||||
EXPR();
|
||||
consume(TK(")"));
|
||||
}else{
|
||||
emitCode(OP_LOAD_NONE); // ...?
|
||||
emit(OP_LOAD_NONE); // ...?
|
||||
}
|
||||
emitCode(OP_RAISE_ERROR);
|
||||
emit(OP_RAISE_ERROR);
|
||||
consumeEndStatement();
|
||||
} else if(match(TK("del"))){
|
||||
EXPR();
|
||||
emitCode(OP_DELETE_REF);
|
||||
emit(OP_DELETE_REF);
|
||||
consumeEndStatement();
|
||||
} else if(match(TK("global"))){
|
||||
do {
|
||||
consume(TK("@id"));
|
||||
getCode()->co_global_names.push_back(parser->previous.str());
|
||||
co()->co_global_names.push_back(parser->prev.str());
|
||||
} while (match(TK(",")));
|
||||
consumeEndStatement();
|
||||
} else if(match(TK("pass"))){
|
||||
@ -936,30 +933,30 @@ __LISTCOMP:
|
||||
EXPR_ANY();
|
||||
consumeEndStatement();
|
||||
// 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(mode()==SINGLE_MODE && parser->indents.top()==0) emitCode(OP_PRINT_EXPR);
|
||||
emitCode(OP_POP_TOP);
|
||||
if(mode()==SINGLE_MODE && parser->indents.top()==0) emit(OP_PRINT_EXPR);
|
||||
emit(OP_POP_TOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void compileClass(){
|
||||
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;
|
||||
if(match(TK("("))){
|
||||
consume(TK("@id"));
|
||||
superClsNameIdx = getCode()->addName(parser->previous.str(), NAME_GLOBAL);
|
||||
superClsNameIdx = co()->add_name(parser->prev.str(), NAME_GLOBAL);
|
||||
consume(TK(")"));
|
||||
}
|
||||
emitCode(OP_LOAD_NONE);
|
||||
emit(OP_LOAD_NONE);
|
||||
isCompilingClass = true;
|
||||
__compileBlockBody(&Compiler::compileFunction);
|
||||
isCompilingClass = false;
|
||||
if(superClsNameIdx == -1) emitCode(OP_LOAD_NONE);
|
||||
else emitCode(OP_LOAD_NAME_REF, superClsNameIdx);
|
||||
emitCode(OP_BUILD_CLASS, clsNameIdx);
|
||||
if(superClsNameIdx == -1) emit(OP_LOAD_NONE);
|
||||
else emit(OP_LOAD_NAME_REF, superClsNameIdx);
|
||||
emit(OP_BUILD_CLASS, clsNameIdx);
|
||||
}
|
||||
|
||||
void __compileFunctionArgs(_Func func, bool enableTypeHints){
|
||||
@ -976,7 +973,7 @@ __LISTCOMP:
|
||||
}
|
||||
|
||||
consume(TK("@id"));
|
||||
const _Str& name = parser->previous.str();
|
||||
const _Str& name = parser->prev.str();
|
||||
if(func->hasName(name)) syntaxError("duplicate argument name");
|
||||
|
||||
// eat type hints
|
||||
@ -992,7 +989,7 @@ __LISTCOMP:
|
||||
consume(TK("="));
|
||||
PyVarOrNull value = readLiteral();
|
||||
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->kwArgsOrder.push_back(name);
|
||||
@ -1009,7 +1006,7 @@ __LISTCOMP:
|
||||
}
|
||||
_Func func = pkpy::make_shared<Function>();
|
||||
consume(TK("@id"));
|
||||
func->name = parser->previous.str();
|
||||
func->name = parser->prev.str();
|
||||
|
||||
if (match(TK("(")) && !match(TK(")"))) {
|
||||
__compileFunctionArgs(func, true);
|
||||
@ -1024,18 +1021,18 @@ __LISTCOMP:
|
||||
compileBlockBody();
|
||||
func->code->optimize();
|
||||
this->codes.pop();
|
||||
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyFunction(func)));
|
||||
if(!isCompilingClass) emitCode(OP_STORE_FUNCTION);
|
||||
emit(OP_LOAD_CONST, co()->add_const(vm->PyFunction(func)));
|
||||
if(!isCompilingClass) emit(OP_STORE_FUNCTION);
|
||||
}
|
||||
|
||||
PyVarOrNull readLiteral(){
|
||||
if(match(TK("-"))){
|
||||
consume(TK("@num"));
|
||||
PyVar val = parser->previous.value;
|
||||
PyVar val = parser->prev.value;
|
||||
return vm->numNegated(val);
|
||||
}
|
||||
if(match(TK("@num"))) return parser->previous.value;
|
||||
if(match(TK("@str"))) return parser->previous.value;
|
||||
if(match(TK("@num"))) return parser->prev.value;
|
||||
if(match(TK("@str"))) return parser->prev.value;
|
||||
if(match(TK("True"))) return vm->PyBool(true);
|
||||
if(match(TK("False"))) return vm->PyBool(false);
|
||||
if(match(TK("None"))) return vm->None;
|
||||
@ -1078,7 +1075,7 @@ __LISTCOMP:
|
||||
return code;
|
||||
}else if(mode()==JSON_MODE){
|
||||
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("["))) exprList();
|
||||
else syntaxError("expect a JSON object or array");
|
||||
@ -1096,14 +1093,14 @@ __LISTCOMP:
|
||||
|
||||
/***** Error Reporter *****/
|
||||
_Str getLineSnapshot(){
|
||||
int lineno = parser->current.line;
|
||||
const char* cursor = parser->current.start;
|
||||
int lineno = parser->curr.line;
|
||||
const char* cursor = parser->curr.start;
|
||||
// if error occurs in lexing, lineno should be `parser->current_line`
|
||||
if(lexingCnt > 0){
|
||||
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);
|
||||
}
|
||||
|
||||
|
65
src/parser.h
65
src/parser.h
@ -98,9 +98,9 @@ struct Parser {
|
||||
_Source src;
|
||||
|
||||
const char* token_start;
|
||||
const char* current_char;
|
||||
const char* curr_char;
|
||||
int current_line = 1;
|
||||
Token previous, current;
|
||||
Token prev, curr;
|
||||
std::queue<Token> nexts;
|
||||
std::stack<int> indents;
|
||||
|
||||
@ -120,28 +120,23 @@ struct Parser {
|
||||
return t;
|
||||
}
|
||||
|
||||
char peekChar() {
|
||||
return *current_char;
|
||||
inline char peek_char() {
|
||||
return *curr_char;
|
||||
}
|
||||
|
||||
std::string_view lookahead(int n){
|
||||
const char* c = current_char;
|
||||
const char* c = curr_char;
|
||||
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++;
|
||||
}
|
||||
return std::string_view(current_char, n);
|
||||
}
|
||||
|
||||
char peekNextChar() {
|
||||
if (peekChar() == '\0') return '\0';
|
||||
return *(current_char + 1);
|
||||
return std::string_view(curr_char, n);
|
||||
}
|
||||
|
||||
int eatSpaces(){
|
||||
int count = 0;
|
||||
while (true) {
|
||||
switch (peekChar()) {
|
||||
switch (peek_char()) {
|
||||
case ' ' : count+=1; break;
|
||||
case '\t': count+=4; break;
|
||||
default: return count;
|
||||
@ -153,8 +148,8 @@ struct Parser {
|
||||
bool eatIndentation(){
|
||||
if(brackets_level_0 > 0 || brackets_level_1 > 0 || brackets_level_2 > 0) return true;
|
||||
int spaces = eatSpaces();
|
||||
if(peekChar() == '#') skipLineComment();
|
||||
if(peekChar() == '\0' || peekChar() == '\n') return true;
|
||||
if(peek_char() == '#') skipLineComment();
|
||||
if(peek_char() == '\0' || peek_char() == '\n') return true;
|
||||
// https://docs.python.org/3/reference/lexical_analysis.html#indentation
|
||||
if(spaces > indents.top()){
|
||||
indents.push(spaces);
|
||||
@ -172,26 +167,26 @@ struct Parser {
|
||||
}
|
||||
|
||||
char eatChar() {
|
||||
char c = peekChar();
|
||||
char c = peek_char();
|
||||
if(c == '\n') throw std::runtime_error("eatChar() cannot consume a newline");
|
||||
current_char++;
|
||||
curr_char++;
|
||||
return c;
|
||||
}
|
||||
|
||||
char eatCharIncludeNewLine() {
|
||||
char c = peekChar();
|
||||
current_char++;
|
||||
char c = peek_char();
|
||||
curr_char++;
|
||||
if (c == '\n'){
|
||||
current_line++;
|
||||
src->lineStarts.push_back(current_char);
|
||||
src->lineStarts.push_back(curr_char);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int eatName() {
|
||||
current_char--;
|
||||
curr_char--;
|
||||
while(true){
|
||||
uint8_t c = peekChar();
|
||||
uint8_t c = peek_char();
|
||||
int u8bytes = 0;
|
||||
if((c & 0b10000000) == 0b00000000) u8bytes = 1;
|
||||
else if((c & 0b11100000) == 0b11000000) u8bytes = 2;
|
||||
@ -200,14 +195,14 @@ struct Parser {
|
||||
else return 1;
|
||||
if(u8bytes == 1){
|
||||
if(isalpha(c) || c=='_' || isdigit(c)) {
|
||||
current_char++;
|
||||
curr_char++;
|
||||
continue;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// handle multibyte char
|
||||
std::string u8str(current_char, u8bytes);
|
||||
std::string u8str(curr_char, u8bytes);
|
||||
if(u8str.size() != u8bytes) return 2;
|
||||
uint32_t value = 0;
|
||||
for(int k=0; k < u8bytes; k++){
|
||||
@ -220,11 +215,11 @@ struct Parser {
|
||||
value |= (b & 0b00111111) << (6*(u8bytes-k-1));
|
||||
}
|
||||
}
|
||||
if(__isLoChar(value)) current_char += u8bytes;
|
||||
if(__isLoChar(value)) curr_char += u8bytes;
|
||||
else break;
|
||||
}
|
||||
|
||||
int length = (int)(current_char - token_start);
|
||||
int length = (int)(curr_char - token_start);
|
||||
if(length == 0) return 3;
|
||||
std::string_view name(token_start, length);
|
||||
|
||||
@ -243,14 +238,14 @@ struct Parser {
|
||||
|
||||
if(__KW_MAP.count(name)){
|
||||
if(name == "not"){
|
||||
if(strncmp(current_char, " in", 3) == 0){
|
||||
current_char += 3;
|
||||
if(strncmp(curr_char, " in", 3) == 0){
|
||||
curr_char += 3;
|
||||
setNextToken(TK("not in"));
|
||||
return 0;
|
||||
}
|
||||
}else if(name == "is"){
|
||||
if(strncmp(current_char, " not", 4) == 0){
|
||||
current_char += 4;
|
||||
if(strncmp(curr_char, " not", 4) == 0){
|
||||
curr_char += 4;
|
||||
setNextToken(TK("is not"));
|
||||
return 0;
|
||||
}
|
||||
@ -264,7 +259,7 @@ struct Parser {
|
||||
|
||||
void skipLineComment() {
|
||||
char c;
|
||||
while ((c = peekChar()) != '\0') {
|
||||
while ((c = peek_char()) != '\0') {
|
||||
if (c == '\n') return;
|
||||
eatChar();
|
||||
}
|
||||
@ -273,14 +268,14 @@ 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) {
|
||||
if (peekChar() != c) return false;
|
||||
if (peek_char() != c) return false;
|
||||
eatCharIncludeNewLine();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns an error token from the current position for reporting error.
|
||||
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.
|
||||
@ -298,7 +293,7 @@ struct Parser {
|
||||
nexts.push( Token{
|
||||
type,
|
||||
token_start,
|
||||
(int)(current_char - token_start),
|
||||
(int)(curr_char - token_start),
|
||||
current_line - ((type == TK("@eol")) ? 1 : 0),
|
||||
value
|
||||
});
|
||||
@ -312,7 +307,7 @@ struct Parser {
|
||||
Parser(_Source src) {
|
||||
this->src = src;
|
||||
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->indents.push(0);
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
|
||||
vm->__checkArgSize(args, 1);
|
||||
const _Str& expr = vm->PyStr_AS_C(args[0]);
|
||||
_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) {
|
||||
@ -672,7 +672,7 @@ void __addModuleJson(VM* vm){
|
||||
vm->__checkArgSize(args, 1);
|
||||
const _Str& expr = vm->PyStr_AS_C(args[0]);
|
||||
_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) {
|
||||
|
176
src/vm.h
176
src/vm.h
@ -21,28 +21,28 @@
|
||||
|
||||
|
||||
class VM {
|
||||
std::atomic<bool> _stopFlag = false;
|
||||
std::vector<PyVar> _smallIntegers; // [-5, 256]
|
||||
std::atomic<bool> _stop_flag = false;
|
||||
std::vector<PyVar> _small_integers; // [-5, 256]
|
||||
PyVarDict _modules; // loaded modules
|
||||
emhash8::HashMap<_Str, _Str> _lazy_modules; // lazy loaded modules
|
||||
protected:
|
||||
std::deque< pkpy::unique_ptr<Frame> > callstack;
|
||||
PyVarDict _modules; // loaded modules
|
||||
emhash8::HashMap<_Str, _Str> _lazyModules; // lazy loaded modules
|
||||
PyVar __py2py_call_signal;
|
||||
|
||||
void _checkStopFlag(){
|
||||
if(_stopFlag){
|
||||
_stopFlag = false;
|
||||
inline void test_stop_flag(){
|
||||
if(_stop_flag){
|
||||
_stop_flag = false;
|
||||
_error("KeyboardInterrupt", "");
|
||||
}
|
||||
}
|
||||
|
||||
PyVar runFrame(Frame* frame){
|
||||
PyVar run_frame(Frame* frame){
|
||||
while(frame->has_next_bytecode()){
|
||||
const ByteCode& byte = frame->next_bytecode();
|
||||
//printf("[%d] %s (%d)\n", frame->stackSize(), OP_NAMES[byte.op], byte.arg);
|
||||
const Bytecode& byte = frame->next_bytecode();
|
||||
//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());
|
||||
|
||||
_checkStopFlag();
|
||||
test_stop_flag();
|
||||
|
||||
switch (byte.op)
|
||||
{
|
||||
@ -61,30 +61,30 @@ protected:
|
||||
} break;
|
||||
case OP_STORE_NAME_REF: {
|
||||
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;
|
||||
case OP_BUILD_ATTR_REF: {
|
||||
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))));
|
||||
} break;
|
||||
case OP_BUILD_INDEX_REF: {
|
||||
PyVar index = frame->popValue(this);
|
||||
PyVarRef obj = frame->popValue(this);
|
||||
PyVar index = frame->pop_value(this);
|
||||
PyVarRef obj = frame->pop_value(this);
|
||||
frame->push(PyRef(IndexRef(obj, index)));
|
||||
} break;
|
||||
case OP_STORE_REF: {
|
||||
PyVar obj = frame->popValue(this);
|
||||
PyVarRef r = frame->__pop();
|
||||
PyVar obj = frame->pop_value(this);
|
||||
PyVarRef r = frame->pop();
|
||||
PyRef_AS_C(r)->set(this, frame, std::move(obj));
|
||||
} break;
|
||||
case OP_DELETE_REF: {
|
||||
PyVarRef r = frame->__pop();
|
||||
PyVarRef r = frame->pop();
|
||||
PyRef_AS_C(r)->del(this, frame);
|
||||
} break;
|
||||
case OP_BUILD_SMART_TUPLE:
|
||||
{
|
||||
pkpy::ArgList items = frame->__popNReversed(byte.arg);
|
||||
pkpy::ArgList items = frame->pop_n_reversed(byte.arg);
|
||||
bool done = false;
|
||||
for(int i=0; i<items.size(); i++){
|
||||
if(!items[i]->isType(_tp_ref)) {
|
||||
@ -100,7 +100,7 @@ protected:
|
||||
} break;
|
||||
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;
|
||||
for(int i=0; i<items.size(); i++) ss << PyStr_AS_C(asStr(items[i]));
|
||||
frame->push(PyStr(ss.str()));
|
||||
@ -110,13 +110,13 @@ protected:
|
||||
} break;
|
||||
case OP_LIST_APPEND: {
|
||||
pkpy::ArgList args(2);
|
||||
args[1] = frame->popValue(this); // obj
|
||||
args[0] = frame->__topValueN(this, -2); // list
|
||||
args[1] = frame->pop_value(this); // obj
|
||||
args[0] = frame->top_value_offset(this, -2); // list
|
||||
fastCall(m_append, std::move(args));
|
||||
} break;
|
||||
case OP_STORE_FUNCTION:
|
||||
{
|
||||
PyVar obj = frame->popValue(this);
|
||||
PyVar obj = frame->pop_value(this);
|
||||
const _Func& fn = PyFunction_AS_C(obj);
|
||||
setAttr(obj, __module__, frame->_module);
|
||||
frame->f_globals()[fn->name] = obj;
|
||||
@ -124,78 +124,78 @@ protected:
|
||||
case OP_BUILD_CLASS:
|
||||
{
|
||||
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;
|
||||
__checkType(clsBase, _tp_type);
|
||||
PyVar cls = newUserClassType(frame->_module, clsName, clsBase);
|
||||
while(true){
|
||||
PyVar fn = frame->popValue(this);
|
||||
PyVar fn = frame->pop_value(this);
|
||||
if(fn == None) break;
|
||||
const _Func& f = PyFunction_AS_C(fn);
|
||||
setAttr(fn, __module__, frame->_module);
|
||||
setAttr(cls, f->name, fn);
|
||||
}
|
||||
} break;
|
||||
case OP_RETURN_VALUE: return frame->popValue(this);
|
||||
case OP_RETURN_VALUE: return frame->pop_value(this);
|
||||
case OP_PRINT_EXPR:
|
||||
{
|
||||
const PyVar expr = frame->topValue(this);
|
||||
const PyVar expr = frame->top_value(this);
|
||||
if(expr == None) break;
|
||||
*_stdout << PyStr_AS_C(asRepr(expr)) << '\n';
|
||||
} break;
|
||||
case OP_POP_TOP: frame->popValue(this); break;
|
||||
case OP_POP_TOP: frame->pop_value(this); break;
|
||||
case OP_BINARY_OP:
|
||||
{
|
||||
frame->push(
|
||||
fastCall(BINARY_SPECIAL_METHODS[byte.arg],
|
||||
frame->popNValuesReversed(this, 2))
|
||||
frame->pop_n_values_reversed(this, 2))
|
||||
);
|
||||
// pkpy::ArgList args(2);
|
||||
// args._index(1) = frame->popValue(this);
|
||||
// args._index(0) = frame->topValue(this);
|
||||
// frame->__top() = fastCall(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
|
||||
// args._index(1) = frame->pop_value(this);
|
||||
// args._index(0) = frame->top_value(this);
|
||||
// frame->top() = fastCall(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
|
||||
} break;
|
||||
case OP_BITWISE_OP:
|
||||
{
|
||||
frame->push(
|
||||
fastCall(BITWISE_SPECIAL_METHODS[byte.arg],
|
||||
frame->popNValuesReversed(this, 2))
|
||||
frame->pop_n_values_reversed(this, 2))
|
||||
);
|
||||
} break;
|
||||
case OP_COMPARE_OP:
|
||||
{
|
||||
// for __ne__ we use the negation of __eq__
|
||||
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));
|
||||
frame->push(std::move(res));
|
||||
} break;
|
||||
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;
|
||||
frame->push(PyBool(ret_c));
|
||||
} break;
|
||||
case OP_CONTAINS_OP:
|
||||
{
|
||||
PyVar rhs = frame->popValue(this);
|
||||
bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::oneArg(frame->popValue(this))));
|
||||
PyVar rhs = frame->pop_value(this);
|
||||
bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::oneArg(frame->pop_value(this))));
|
||||
if(byte.arg == 1) ret_c = !ret_c;
|
||||
frame->push(PyBool(ret_c));
|
||||
} break;
|
||||
case OP_UNARY_NEGATIVE:
|
||||
{
|
||||
PyVar obj = frame->popValue(this);
|
||||
PyVar obj = frame->pop_value(this);
|
||||
frame->push(numNegated(obj));
|
||||
} break;
|
||||
case OP_UNARY_NOT:
|
||||
{
|
||||
PyVar obj = frame->popValue(this);
|
||||
PyVar obj = frame->pop_value(this);
|
||||
const PyVar& obj_bool = asBool(obj);
|
||||
frame->push(PyBool(!PyBool_AS_C(obj_bool)));
|
||||
} break;
|
||||
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;
|
||||
case OP_LOAD_NONE: frame->push(None); break;
|
||||
case OP_LOAD_TRUE: frame->push(True); break;
|
||||
@ -203,24 +203,24 @@ protected:
|
||||
case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); break;
|
||||
case OP_ASSERT:
|
||||
{
|
||||
PyVar expr = frame->popValue(this);
|
||||
PyVar expr = frame->pop_value(this);
|
||||
_assert(PyBool_AS_C(expr), "assertion failed");
|
||||
} break;
|
||||
case OP_RAISE_ERROR:
|
||||
{
|
||||
_Str msg = PyStr_AS_C(asRepr(frame->popValue(this)));
|
||||
_Str type = PyStr_AS_C(frame->popValue(this));
|
||||
_Str msg = PyStr_AS_C(asRepr(frame->pop_value(this)));
|
||||
_Str type = PyStr_AS_C(frame->pop_value(this));
|
||||
_error(type, msg);
|
||||
} break;
|
||||
case OP_BUILD_LIST:
|
||||
{
|
||||
frame->push(PyList(
|
||||
frame->popNValuesReversedUnlimited(this, byte.arg)
|
||||
frame->pop_n_values_reversed_unlimited(this, byte.arg)
|
||||
));
|
||||
} break;
|
||||
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"]);
|
||||
for(int i=0; i<items.size(); i+=2){
|
||||
call(obj, __setitem__, pkpy::twoArgs(items[i], items[i+1]));
|
||||
@ -230,42 +230,42 @@ protected:
|
||||
case OP_BUILD_SET:
|
||||
{
|
||||
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));
|
||||
frame->push(obj);
|
||||
} 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:
|
||||
{
|
||||
int ARGC = byte.arg & 0xFFFF;
|
||||
int KWARGC = (byte.arg >> 16) & 0xFFFF;
|
||||
pkpy::ArgList kwargs(0);
|
||||
if(KWARGC > 0) kwargs = frame->popNValuesReversed(this, KWARGC*2);
|
||||
pkpy::ArgList args = frame->popNValuesReversed(this, ARGC);
|
||||
PyVar callable = frame->popValue(this);
|
||||
if(KWARGC > 0) kwargs = frame->pop_n_values_reversed(this, KWARGC*2);
|
||||
pkpy::ArgList args = frame->pop_n_values_reversed(this, ARGC);
|
||||
PyVar callable = frame->pop_value(this);
|
||||
PyVar ret = call(callable, std::move(args), kwargs, true);
|
||||
if(ret == __py2py_call_signal) return ret;
|
||||
frame->push(std::move(ret));
|
||||
} break;
|
||||
case OP_JUMP_ABSOLUTE: frame->jumpAbsolute(byte.arg); break;
|
||||
case OP_SAFE_JUMP_ABSOLUTE: frame->jumpAbsoluteSafe(byte.arg); break;
|
||||
case OP_JUMP_ABSOLUTE: frame->jump_abs(byte.arg); break;
|
||||
case OP_SAFE_JUMP_ABSOLUTE: frame->jump_abs_safe(byte.arg); break;
|
||||
case OP_GOTO: {
|
||||
PyVar obj = frame->popValue(this);
|
||||
PyVar obj = frame->pop_value(this);
|
||||
const _Str& label = PyStr_AS_C(obj);
|
||||
int* target = frame->code->co_labels.try_get(label);
|
||||
if(target == nullptr){
|
||||
_error("KeyError", "label '" + label + "' not found");
|
||||
}
|
||||
frame->jumpAbsoluteSafe(*target);
|
||||
frame->jump_abs_safe(*target);
|
||||
} break;
|
||||
case OP_GET_ITER:
|
||||
{
|
||||
PyVar obj = frame->popValue(this);
|
||||
PyVar obj = frame->pop_value(this);
|
||||
PyVarOrNull iter_fn = getAttr(obj, __iter__, false);
|
||||
if(iter_fn != nullptr){
|
||||
PyVar tmp = call(iter_fn);
|
||||
PyVarRef var = frame->__pop();
|
||||
PyVarRef var = frame->pop();
|
||||
__checkType(var, _tp_ref);
|
||||
PyIter_AS_C(tmp)->var = var;
|
||||
frame->push(std::move(tmp));
|
||||
@ -275,41 +275,41 @@ protected:
|
||||
} break;
|
||||
case OP_FOR_ITER:
|
||||
{
|
||||
// __top() must be PyIter, so no need to try_deref()
|
||||
auto& it = PyIter_AS_C(frame->__top());
|
||||
// top() must be PyIter, so no need to try_deref()
|
||||
auto& it = PyIter_AS_C(frame->top());
|
||||
if(it->hasNext()){
|
||||
PyRef_AS_C(it->var)->set(this, frame, it->next());
|
||||
}else{
|
||||
int blockEnd = frame->code->co_blocks[byte.block].end;
|
||||
frame->jumpAbsoluteSafe(blockEnd);
|
||||
frame->jump_abs_safe(blockEnd);
|
||||
}
|
||||
} break;
|
||||
case OP_LOOP_CONTINUE:
|
||||
{
|
||||
int blockStart = frame->code->co_blocks[byte.block].start;
|
||||
frame->jumpAbsolute(blockStart);
|
||||
frame->jump_abs(blockStart);
|
||||
} break;
|
||||
case OP_LOOP_BREAK:
|
||||
{
|
||||
int blockEnd = frame->code->co_blocks[byte.block].end;
|
||||
frame->jumpAbsoluteSafe(blockEnd);
|
||||
frame->jump_abs_safe(blockEnd);
|
||||
} break;
|
||||
case OP_JUMP_IF_FALSE_OR_POP:
|
||||
{
|
||||
const PyVar expr = frame->topValue(this);
|
||||
if(asBool(expr)==False) frame->jumpAbsolute(byte.arg);
|
||||
else frame->popValue(this);
|
||||
const PyVar expr = frame->top_value(this);
|
||||
if(asBool(expr)==False) frame->jump_abs(byte.arg);
|
||||
else frame->pop_value(this);
|
||||
} break;
|
||||
case OP_JUMP_IF_TRUE_OR_POP:
|
||||
{
|
||||
const PyVar expr = frame->topValue(this);
|
||||
if(asBool(expr)==True) frame->jumpAbsolute(byte.arg);
|
||||
else frame->popValue(this);
|
||||
const PyVar expr = frame->top_value(this);
|
||||
if(asBool(expr)==True) frame->jump_abs(byte.arg);
|
||||
else frame->pop_value(this);
|
||||
} break;
|
||||
case OP_BUILD_SLICE:
|
||||
{
|
||||
PyVar stop = frame->popValue(this);
|
||||
PyVar start = frame->popValue(this);
|
||||
PyVar stop = frame->pop_value(this);
|
||||
PyVar start = frame->pop_value(this);
|
||||
_Slice s;
|
||||
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);}
|
||||
@ -320,8 +320,8 @@ protected:
|
||||
const _Str& name = frame->code->co_names[byte.arg].first;
|
||||
auto it = _modules.find(name);
|
||||
if(it == _modules.end()){
|
||||
auto it2 = _lazyModules.find(name);
|
||||
if(it2 == _lazyModules.end()){
|
||||
auto it2 = _lazy_modules.find(name);
|
||||
if(it2 == _lazy_modules.end()){
|
||||
_error("ImportError", "module '" + name + "' not found");
|
||||
}else{
|
||||
const _Str& source = it2->second;
|
||||
@ -329,15 +329,15 @@ protected:
|
||||
PyVar _m = newModule(name);
|
||||
_exec(code, _m, {});
|
||||
frame->push(_m);
|
||||
_lazyModules.erase(it2);
|
||||
_lazy_modules.erase(it2);
|
||||
}
|
||||
}else{
|
||||
frame->push(it->second);
|
||||
}
|
||||
} break;
|
||||
// TODO: using "goto" inside with block may cause __exit__ not called
|
||||
case OP_WITH_ENTER: call(frame->popValue(this), __enter__); break;
|
||||
case OP_WITH_EXIT: call(frame->popValue(this), __exit__); break;
|
||||
case OP_WITH_ENTER: call(frame->pop_value(this), __enter__); break;
|
||||
case OP_WITH_EXIT: call(frame->pop_value(this), __exit__); break;
|
||||
default:
|
||||
systemError(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
|
||||
break;
|
||||
@ -345,11 +345,11 @@ protected:
|
||||
}
|
||||
|
||||
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");
|
||||
return frame->popValue(this);
|
||||
if(frame->stack_size() != 1) systemError("stack size is not 1 in EVAL_MODE/JSON_MODE");
|
||||
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;
|
||||
}
|
||||
|
||||
@ -380,18 +380,18 @@ public:
|
||||
}
|
||||
initializeBuiltinClasses();
|
||||
|
||||
_smallIntegers.reserve(300);
|
||||
for(_Int i=-5; i<=256; i++) _smallIntegers.push_back(newObject(_tp_int, i));
|
||||
_small_integers.reserve(300);
|
||||
for(_Int i=-5; i<=256; i++) _small_integers.push_back(newObject(_tp_int, i));
|
||||
}
|
||||
|
||||
void keyboardInterrupt(){
|
||||
_stopFlag = true;
|
||||
_stop_flag = true;
|
||||
}
|
||||
|
||||
void sleepForSecs(_Float sec){
|
||||
_Int ms = (_Int)(sec * 1000);
|
||||
for(_Int i=0; i<ms; i+=20){
|
||||
_checkStopFlag();
|
||||
test_stop_flag();
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_sleep(20);
|
||||
#else
|
||||
@ -590,7 +590,7 @@ public:
|
||||
PyVar ret = nullptr;
|
||||
|
||||
while(true){
|
||||
ret = runFrame(frame);
|
||||
ret = run_frame(frame);
|
||||
if(ret != __py2py_call_signal){
|
||||
if(frame == frameBase){ // [ frameBase<- ]
|
||||
break;
|
||||
@ -640,7 +640,7 @@ public:
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -774,7 +774,7 @@ public:
|
||||
ss << code->name << ":\n";
|
||||
int prev_line = -1;
|
||||
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);
|
||||
if(byte.line == prev_line) line = "";
|
||||
else{
|
||||
@ -799,7 +799,7 @@ public:
|
||||
argStr += " (" + code->co_names[byte.arg].first.__escape(true) + ")";
|
||||
}
|
||||
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';
|
||||
}
|
||||
_StrStream consts;
|
||||
@ -846,7 +846,7 @@ public:
|
||||
|
||||
__DEF_PY_AS_C(Int, _Int, _tp_int)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -949,7 +949,7 @@ private:
|
||||
std::stack<_Str> snapshots;
|
||||
while (!callstack.empty()){
|
||||
if(snapshots.size() < 8){
|
||||
snapshots.push(callstack.back()->errorSnapshot());
|
||||
snapshots.push(callstack.back()->curr_snapshot());
|
||||
}
|
||||
callstack.pop_back();
|
||||
}
|
||||
@ -1183,7 +1183,7 @@ public:
|
||||
if(_state != THREAD_RUNNING) UNREACHABLE();
|
||||
_state = THREAD_SUSPENDED;
|
||||
while(_state == THREAD_SUSPENDED){
|
||||
_checkStopFlag();
|
||||
test_stop_flag();
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_sleep(20);
|
||||
#else
|
||||
|
Loading…
x
Reference in New Issue
Block a user