mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-22 20:40:18 +00:00
up
This commit is contained in:
parent
190d2a0589
commit
e4e43826fe
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include <type_traits>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
|
@ -26,12 +26,13 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#define PK_VERSION "0.9.6"
|
#define PK_VERSION "0.9.6"
|
||||||
|
|
||||||
// debug macros
|
// debug macros
|
||||||
#define DEBUG_NO_BUILTIN_MODULES 0
|
#define DEBUG_NO_BUILTIN_MODULES 1
|
||||||
#define DEBUG_EXTRA_CHECK 1
|
#define DEBUG_MODE 1
|
||||||
|
|
||||||
#if (defined(__ANDROID__) && __ANDROID_API__ <= 22) || defined(__EMSCRIPTEN__)
|
#if (defined(__ANDROID__) && __ANDROID_API__ <= 22) || defined(__EMSCRIPTEN__)
|
||||||
#define PK_ENABLE_FILEIO 0
|
#define PK_ENABLE_FILEIO 0
|
||||||
|
@ -26,7 +26,7 @@ class Compiler {
|
|||||||
const Token& prev() { return tokens.at(i-1); }
|
const Token& prev() { return tokens.at(i-1); }
|
||||||
const Token& curr() { return tokens.at(i); }
|
const Token& curr() { return tokens.at(i); }
|
||||||
const Token& next() { return tokens.at(i+1); }
|
const Token& next() { return tokens.at(i+1); }
|
||||||
void advance() { i++; }
|
void advance(int delta=1) { i += delta; }
|
||||||
|
|
||||||
CodeEmitContext* ctx() { return &contexts.top(); }
|
CodeEmitContext* ctx() { return &contexts.top(); }
|
||||||
CompileMode mode() const{ return lexer->src->mode; }
|
CompileMode mode() const{ return lexer->src->mode; }
|
||||||
@ -42,7 +42,7 @@ class Compiler {
|
|||||||
void pop_context(){
|
void pop_context(){
|
||||||
if(!ctx()->s_expr.empty()) UNREACHABLE();
|
if(!ctx()->s_expr.empty()) UNREACHABLE();
|
||||||
// if the last op does not return, add a default return None
|
// if the last op does not return, add a default return None
|
||||||
if(ctx()->co->codes.back().op != OP_RETURN_VALUE){
|
if(ctx()->co->codes.empty() || ctx()->co->codes.back().op != OP_RETURN_VALUE){
|
||||||
ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
|
||||||
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
@ -185,12 +185,14 @@ class Compiler {
|
|||||||
|
|
||||||
// PASS
|
// PASS
|
||||||
void exprTuple(){
|
void exprTuple(){
|
||||||
auto e = make_expr<TupleExpr>();
|
std::vector<Expr_> items;
|
||||||
do {
|
do {
|
||||||
EXPR(); // NOTE: "1," will fail, "1,2" will be ok
|
EXPR(); // NOTE: "1," will fail, "1,2" will be ok
|
||||||
e->items.push_back(ctx()->s_expr.popx());
|
items.push_back(ctx()->s_expr.popx());
|
||||||
} while(match(TK(",")));
|
} while(match(TK(",")));
|
||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(make_expr<TupleExpr>(
|
||||||
|
std::move(items)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// PASS
|
// PASS
|
||||||
@ -577,7 +579,7 @@ class Compiler {
|
|||||||
EXPR(false);
|
EXPR(false);
|
||||||
// TODO: support multiple decorator
|
// TODO: support multiple decorator
|
||||||
// use a while loop to consume '@'
|
// use a while loop to consume '@'
|
||||||
if(!match_newlines(mode()==REPL_MODE)) SyntaxError();
|
if(!match_newlines_repl()) SyntaxError();
|
||||||
ctx()->emit(OP_SETUP_DECORATOR, BC_NOARG, prev().line);
|
ctx()->emit(OP_SETUP_DECORATOR, BC_NOARG, prev().line);
|
||||||
consume(TK("def"));
|
consume(TK("def"));
|
||||||
compile_function();
|
compile_function();
|
||||||
@ -585,11 +587,9 @@ class Compiler {
|
|||||||
|
|
||||||
bool try_compile_assignment(){
|
bool try_compile_assignment(){
|
||||||
Expr* lhs_p = ctx()->s_expr.top().get();
|
Expr* lhs_p = ctx()->s_expr.top().get();
|
||||||
bool inplace;
|
|
||||||
switch (curr().type) {
|
switch (curr().type) {
|
||||||
case TK("+="): case TK("-="): case TK("*="): case TK("/="): case TK("//="): case TK("%="):
|
case TK("+="): case TK("-="): case TK("*="): case TK("/="): case TK("//="): case TK("%="):
|
||||||
case TK("<<="): case TK(">>="): case TK("&="): case TK("|="): case TK("^="): {
|
case TK("<<="): case TK(">>="): case TK("&="): case TK("|="): case TK("^="): {
|
||||||
inplace = true;
|
|
||||||
advance();
|
advance();
|
||||||
auto e = make_expr<BinaryExpr>();
|
auto e = make_expr<BinaryExpr>();
|
||||||
e->op = prev().type - 1; // -1 to remove =
|
e->op = prev().type - 1; // -1 to remove =
|
||||||
@ -599,7 +599,6 @@ class Compiler {
|
|||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(std::move(e));
|
||||||
} break;
|
} break;
|
||||||
case TK("="):
|
case TK("="):
|
||||||
inplace = false;
|
|
||||||
advance();
|
advance();
|
||||||
EXPR_TUPLE();
|
EXPR_TUPLE();
|
||||||
break;
|
break;
|
||||||
@ -634,7 +633,7 @@ class Compiler {
|
|||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK("return"):
|
case TK("return"):
|
||||||
if (contexts.size() <= 1) SyntaxError("'ret urn' outside function");
|
if (contexts.size() <= 1) SyntaxError("'return' outside function");
|
||||||
if(match_end_stmt()){
|
if(match_end_stmt()){
|
||||||
ctx()->emit(OP_LOAD_NONE, BC_NOARG, kw_line);
|
ctx()->emit(OP_LOAD_NONE, BC_NOARG, kw_line);
|
||||||
}else{
|
}else{
|
||||||
@ -717,6 +716,7 @@ class Compiler {
|
|||||||
/*************************************************/
|
/*************************************************/
|
||||||
// handle dangling expression or assignment
|
// handle dangling expression or assignment
|
||||||
default: {
|
default: {
|
||||||
|
advance(-1); // do revert since we have pre-called advance() at the beginning
|
||||||
EXPR_TUPLE();
|
EXPR_TUPLE();
|
||||||
if(!try_compile_assignment()){
|
if(!try_compile_assignment()){
|
||||||
ctx()->emit_expr();
|
ctx()->emit_expr();
|
||||||
@ -791,7 +791,6 @@ class Compiler {
|
|||||||
|
|
||||||
void compile_function(){
|
void compile_function(){
|
||||||
// TODO: bug, if there are multiple decorators, will cause error
|
// TODO: bug, if there are multiple decorators, will cause error
|
||||||
bool has_decorator = !co()->codes.empty() && co()->codes.back().op == OP_SETUP_DECORATOR;
|
|
||||||
Function func;
|
Function func;
|
||||||
StrName obj_name;
|
StrName obj_name;
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
@ -812,38 +811,38 @@ class Compiler {
|
|||||||
func.code = push_context(lexer->src, func.name.str());
|
func.code = push_context(lexer->src, func.name.str());
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
pop_context();
|
pop_context();
|
||||||
emit(OP_LOAD_FUNCTION, co()->add_const(VAR(func)));
|
ctx()->emit(OP_LOAD_FUNCTION, ctx()->add_const(VAR(func)), prev().line);
|
||||||
if(name_scope() == NAME_LOCAL) emit(OP_SETUP_CLOSURE);
|
if(name_scope() == NAME_LOCAL) ctx()->emit(OP_SETUP_CLOSURE, BC_NOARG, prev().line);
|
||||||
if(!ctx()->is_compiling_class){
|
if(!ctx()->is_compiling_class){
|
||||||
if(obj_name.empty()){
|
if(obj_name.empty()){
|
||||||
if(has_decorator) emit(OP_CALL, 1);
|
auto e = make_expr<NameExpr>(func.name, name_scope());
|
||||||
emit(OP_STORE_NAME, co()->add_name(func.name, name_scope()));
|
e->emit_store(ctx());
|
||||||
} else {
|
} else {
|
||||||
if(has_decorator) SyntaxError("decorator is not supported here");
|
ctx()->emit(OP_LOAD_NAME, ctx()->add_name(obj_name), prev().line);
|
||||||
emit(OP_LOAD_NAME, co()->add_name(obj_name, name_scope()));
|
int index = ctx()->add_name(func.name);
|
||||||
int index = co()->add_name(func.name, NAME_ATTR);
|
ctx()->emit(OP_STORE_ATTR, index, prev().line);
|
||||||
emit(OP_BUILD_ATTR_REF, index);
|
|
||||||
emit(OP_ROT_TWO);
|
|
||||||
emit(OP_STORE_REF);
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(has_decorator) emit(OP_CALL, 1);
|
ctx()->emit(OP_STORE_CLASS_ATTR, ctx()->add_name(func.name), BC_KEEPLINE);
|
||||||
emit(OP_STORE_CLASS_ATTR, co()->add_name(func.name, name_scope()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* read_literal(){
|
PyObject* read_literal(){
|
||||||
if(match(TK("-"))){
|
advance();
|
||||||
consume(TK("@num"));
|
switch(prev().type){
|
||||||
PyObject* val = get_value(prev());
|
case TK("-"): {
|
||||||
return vm->num_negated(val);
|
consume(TK("@num"));
|
||||||
|
PyObject* val = LiteralExpr(prev().value).to_object(ctx());
|
||||||
|
return vm->num_negated(val);
|
||||||
|
}
|
||||||
|
case TK("@num"): return LiteralExpr(prev().value).to_object(ctx());
|
||||||
|
case TK("@str"): return LiteralExpr(prev().value).to_object(ctx());
|
||||||
|
case TK("True"): return VAR(true);
|
||||||
|
case TK("False"): return VAR(false);
|
||||||
|
case TK("None"): return vm->None;
|
||||||
|
case TK("..."): return vm->Ellipsis;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
if(match(TK("@num"))) return get_value(prev());
|
|
||||||
if(match(TK("@str"))) return get_value(prev());
|
|
||||||
if(match(TK("True"))) return VAR(true);
|
|
||||||
if(match(TK("False"))) return VAR(false);
|
|
||||||
if(match(TK("None"))) return vm->None;
|
|
||||||
if(match(TK("..."))) return vm->Ellipsis;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -858,7 +857,8 @@ public:
|
|||||||
this->lexer = std::make_unique<Lexer>(
|
this->lexer = std::make_unique<Lexer>(
|
||||||
make_sp<SourceData>(source, filename, mode)
|
make_sp<SourceData>(source, filename, mode)
|
||||||
);
|
);
|
||||||
if(rules.empty()) init_pratt_rules();
|
// TODO: check if already initialized
|
||||||
|
init_pratt_rules();
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeObject_ compile(){
|
CodeObject_ compile(){
|
||||||
@ -883,7 +883,7 @@ public:
|
|||||||
return code;
|
return code;
|
||||||
}else if(mode()==JSON_MODE){
|
}else if(mode()==JSON_MODE){
|
||||||
PyObject* value = read_literal();
|
PyObject* value = read_literal();
|
||||||
if(value != nullptr) emit(OP_LOAD_CONST, code->add_const(value));
|
if(value != nullptr) ctx()->emit(OP_LOAD_CONST, ctx()->add_const(value), prev().line);
|
||||||
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");
|
||||||
|
35
src/expr.h
35
src/expr.h
@ -31,12 +31,7 @@ struct CodeEmitContext{
|
|||||||
CodeObject_ co;
|
CodeObject_ co;
|
||||||
VM* vm;
|
VM* vm;
|
||||||
stack<Expr_> s_expr;
|
stack<Expr_> s_expr;
|
||||||
|
|
||||||
CodeEmitContext(VM* vm, CodeObject_ co): co(co) {}
|
CodeEmitContext(VM* vm, CodeObject_ co): co(co) {}
|
||||||
CodeEmitContext(const CodeEmitContext&) = delete;
|
|
||||||
CodeEmitContext& operator=(const CodeEmitContext&) = delete;
|
|
||||||
CodeEmitContext(CodeEmitContext&&) = delete;
|
|
||||||
CodeEmitContext& operator=(CodeEmitContext&&) = delete;
|
|
||||||
|
|
||||||
int curr_block_i = 0;
|
int curr_block_i = 0;
|
||||||
bool is_compiling_class = false;
|
bool is_compiling_class = false;
|
||||||
@ -101,12 +96,11 @@ struct CodeEmitContext{
|
|||||||
|
|
||||||
// PASS
|
// PASS
|
||||||
struct NameExpr: Expr{
|
struct NameExpr: Expr{
|
||||||
Str name;
|
StrName name;
|
||||||
NameScope scope;
|
NameScope scope;
|
||||||
NameExpr(const Str& name, NameScope scope): name(name), scope(scope) {}
|
NameExpr(StrName name, NameScope scope): name(name), scope(scope) {}
|
||||||
NameExpr(Str&& name, NameScope scope): name(std::move(name)), scope(scope) {}
|
|
||||||
|
|
||||||
Str str() const override { return "$" + name; }
|
Str str() const override { return "$" + name.str(); }
|
||||||
|
|
||||||
void emit(CodeEmitContext* ctx) override {
|
void emit(CodeEmitContext* ctx) override {
|
||||||
int index = ctx->add_name(name);
|
int index = ctx->add_name(name);
|
||||||
@ -246,7 +240,7 @@ struct LiteralExpr: Expr{
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void emit(CodeEmitContext* ctx) override {
|
PyObject* to_object(CodeEmitContext* ctx){
|
||||||
VM* vm = ctx->vm;
|
VM* vm = ctx->vm;
|
||||||
PyObject* obj = nullptr;
|
PyObject* obj = nullptr;
|
||||||
if(std::holds_alternative<i64>(value)){
|
if(std::holds_alternative<i64>(value)){
|
||||||
@ -258,6 +252,11 @@ struct LiteralExpr: Expr{
|
|||||||
if(std::holds_alternative<Str>(value)){
|
if(std::holds_alternative<Str>(value)){
|
||||||
obj = VAR(std::get<Str>(value));
|
obj = VAR(std::get<Str>(value));
|
||||||
}
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emit(CodeEmitContext* ctx) override {
|
||||||
|
PyObject* obj = to_object(ctx);
|
||||||
if(obj == nullptr) UNREACHABLE();
|
if(obj == nullptr) UNREACHABLE();
|
||||||
int index = ctx->add_const(obj);
|
int index = ctx->add_const(obj);
|
||||||
ctx->emit(OP_LOAD_CONST, index, line);
|
ctx->emit(OP_LOAD_CONST, index, line);
|
||||||
@ -287,7 +286,7 @@ struct NegatedExpr: Expr{
|
|||||||
obj = VAR(std::get<f64>(lit->value));
|
obj = VAR(std::get<f64>(lit->value));
|
||||||
}
|
}
|
||||||
if(obj != nullptr){
|
if(obj != nullptr){
|
||||||
ctx->emit(OP_LOAD_CONST, ctx()->add_const(obj), line);
|
ctx->emit(OP_LOAD_CONST, ctx->add_const(obj), line);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,21 +361,25 @@ struct SequenceExpr: Expr{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ListExpr: SequenceExpr{
|
struct ListExpr: SequenceExpr{
|
||||||
|
using SequenceExpr::SequenceExpr;
|
||||||
Str str() const override { return "list()"; }
|
Str str() const override { return "list()"; }
|
||||||
Opcode opcode() const override { return OP_BUILD_LIST; }
|
Opcode opcode() const override { return OP_BUILD_LIST; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DictExpr: SequenceExpr{
|
struct DictExpr: SequenceExpr{
|
||||||
|
using SequenceExpr::SequenceExpr;
|
||||||
Str str() const override { return "dict()"; }
|
Str str() const override { return "dict()"; }
|
||||||
Opcode opcode() const override { return OP_BUILD_MAP; }
|
Opcode opcode() const override { return OP_BUILD_DICT; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SetExpr: SequenceExpr{
|
struct SetExpr: SequenceExpr{
|
||||||
|
using SequenceExpr::SequenceExpr;
|
||||||
Str str() const override { return "set()"; }
|
Str str() const override { return "set()"; }
|
||||||
Opcode opcode() const override { return OP_BUILD_SET; }
|
Opcode opcode() const override { return OP_BUILD_SET; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TupleExpr: SequenceExpr{
|
struct TupleExpr: SequenceExpr{
|
||||||
|
using SequenceExpr::SequenceExpr;
|
||||||
Str str() const override { return "tuple()"; }
|
Str str() const override { return "tuple()"; }
|
||||||
Opcode opcode() const override { return OP_BUILD_TUPLE; }
|
Opcode opcode() const override { return OP_BUILD_TUPLE; }
|
||||||
|
|
||||||
@ -432,7 +435,8 @@ struct CompExpr: Expr{
|
|||||||
ctx->enter_block(FOR_LOOP);
|
ctx->enter_block(FOR_LOOP);
|
||||||
ctx->emit(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE);
|
ctx->emit(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE);
|
||||||
bool ok = vars->emit_store(ctx);
|
bool ok = vars->emit_store(ctx);
|
||||||
if(!ok) SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
|
// this error occurs in `vars` instead of this line, but...nevermind
|
||||||
|
if(!ok) UNREACHABLE(); // TODO: raise a SyntaxError instead
|
||||||
if(cond){
|
if(cond){
|
||||||
cond->emit(ctx);
|
cond->emit(ctx);
|
||||||
int patch = ctx->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
|
int patch = ctx->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
|
||||||
@ -449,16 +453,19 @@ struct CompExpr: Expr{
|
|||||||
struct ListCompExpr: CompExpr{
|
struct ListCompExpr: CompExpr{
|
||||||
Opcode op0() override { return OP_BUILD_LIST; }
|
Opcode op0() override { return OP_BUILD_LIST; }
|
||||||
Opcode op1() override { return OP_LIST_APPEND; }
|
Opcode op1() override { return OP_LIST_APPEND; }
|
||||||
|
Str str() const override { return "listcomp()"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DictCompExpr: CompExpr{
|
struct DictCompExpr: CompExpr{
|
||||||
Opcode op0() override { return OP_BUILD_DI CT; }
|
Opcode op0() override { return OP_BUILD_DICT; }
|
||||||
Opcode op1() override { return OP_DICT_ADD; }
|
Opcode op1() override { return OP_DICT_ADD; }
|
||||||
|
Str str() const override { return "dictcomp()"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SetCompExpr: CompExpr{
|
struct SetCompExpr: CompExpr{
|
||||||
Opcode op0() override { return OP_BUILD_SET; }
|
Opcode op0() override { return OP_BUILD_SET; }
|
||||||
Opcode op1() override { return OP_SET_ADD; }
|
Opcode op1() override { return OP_SET_ADD; }
|
||||||
|
Str str() const override { return "setcomp()"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LambdaExpr: Expr{
|
struct LambdaExpr: Expr{
|
||||||
|
12
src/frame.h
12
src/frame.h
@ -53,14 +53,14 @@ struct Frame {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
void pop(){
|
void pop(){
|
||||||
#if DEBUG_EXTRA_CHECK
|
#if DEBUG_MODE
|
||||||
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
#endif
|
#endif
|
||||||
_data.pop_back();
|
_data.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* popx(){
|
PyObject* popx(){
|
||||||
#if DEBUG_EXTRA_CHECK
|
#if DEBUG_MODE
|
||||||
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
#endif
|
#endif
|
||||||
PyObject* ret = _data.back();
|
PyObject* ret = _data.back();
|
||||||
@ -69,21 +69,21 @@ struct Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyObject*& top(){
|
PyObject*& top(){
|
||||||
#if DEBUG_EXTRA_CHECK
|
#if DEBUG_MODE
|
||||||
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
#endif
|
#endif
|
||||||
return _data.back();
|
return _data.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject*& top_1(){
|
PyObject*& top_1(){
|
||||||
#if DEBUG_EXTRA_CHECK
|
#if DEBUG_MODE
|
||||||
if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
|
if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
|
||||||
#endif
|
#endif
|
||||||
return _data[_data.size()-2];
|
return _data[_data.size()-2];
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject*& top_2(){
|
PyObject*& top_2(){
|
||||||
#if DEBUG_EXTRA_CHECK
|
#if DEBUG_MODE
|
||||||
if(_data.size() < 3) throw std::runtime_error("_data.size() < 3");
|
if(_data.size() < 3) throw std::runtime_error("_data.size() < 3");
|
||||||
#endif
|
#endif
|
||||||
return _data[_data.size()-3];
|
return _data[_data.size()-3];
|
||||||
@ -115,7 +115,7 @@ struct Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int _exit_block(int i){
|
int _exit_block(int i){
|
||||||
if(co->blocks[i].type == FOR_LOOP) _pop();
|
if(co->blocks[i].type == FOR_LOOP) pop();
|
||||||
else if(co->blocks[i].type == TRY_EXCEPT) on_try_block_exit();
|
else if(co->blocks[i].type == TRY_EXCEPT) on_try_block_exit();
|
||||||
return co->blocks[i].parent;
|
return co->blocks[i].parent;
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,8 @@ public:
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ArrayIter : public BaseIter {
|
class ArrayIter : public BaseIter {
|
||||||
int index;
|
|
||||||
PyObject* ref;
|
PyObject* ref;
|
||||||
|
int index;
|
||||||
public:
|
public:
|
||||||
ArrayIter(VM* vm, PyObject* ref) : BaseIter(vm), ref(ref), index(0) {}
|
ArrayIter(VM* vm, PyObject* ref) : BaseIter(vm), ref(ref), index(0) {}
|
||||||
|
|
||||||
@ -43,10 +43,10 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class StringIter : public BaseIter {
|
class StringIter : public BaseIter {
|
||||||
int index = 0;
|
|
||||||
PyObject* ref;
|
PyObject* ref;
|
||||||
|
int index;
|
||||||
public:
|
public:
|
||||||
StringIter(VM* vm, PyObject* ref) : BaseIter(vm), ref(ref) {}
|
StringIter(VM* vm, PyObject* ref) : BaseIter(vm), ref(ref), index(0) {}
|
||||||
|
|
||||||
PyObject* next() override{
|
PyObject* next() override{
|
||||||
Str* str = &OBJ_GET(Str, ref);
|
Str* str = &OBJ_GET(Str, ref);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "namedict.h"
|
#include "namedict.h"
|
||||||
#include "tuplelist.h"
|
#include "tuplelist.h"
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
@ -142,9 +141,14 @@ struct Py_ : PyObject {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define OBJ_GET(T, obj) (((Py_<T>*)(obj))->_value)
|
#define OBJ_GET(T, obj) (((Py_<T>*)(obj))->_value)
|
||||||
#define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__))
|
|
||||||
#define OBJ_MARK(obj) if(!is_tagged(obj)) obj->_mark()
|
#define OBJ_MARK(obj) if(!is_tagged(obj)) obj->_mark()
|
||||||
|
|
||||||
|
#if DEBUG_NO_BUILTIN_MODULES
|
||||||
|
#define OBJ_NAME(obj) Str("<?>")
|
||||||
|
#else
|
||||||
|
#define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__))
|
||||||
|
#endif
|
||||||
|
|
||||||
const int kTpIntIndex = 2;
|
const int kTpIntIndex = 2;
|
||||||
const int kTpFloatIndex = 3;
|
const int kTpFloatIndex = 3;
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@ inline void init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/************ PyBool ************/
|
/************ PyBool ************/
|
||||||
_vm->bind_static_method<1>("bool", "__new__", CPP_LAMBDA(vm->asBool(args[0])));
|
_vm->bind_static_method<1>("bool", "__new__", CPP_LAMBDA(VAR(vm->asBool(args[0]))));
|
||||||
|
|
||||||
_vm->bind_method<0>("bool", "__repr__", [](VM* vm, Args& args) {
|
_vm->bind_method<0>("bool", "__repr__", [](VM* vm, Args& args) {
|
||||||
bool val = CAST(bool, args[0]);
|
bool val = CAST(bool, args[0]);
|
||||||
|
140
src/vm.h
140
src/vm.h
@ -93,7 +93,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Frame* top_frame() const {
|
Frame* top_frame() const {
|
||||||
#if DEBUG_EXTRA_CHECK
|
#if DEBUG_MODE
|
||||||
if(callstack.empty()) UNREACHABLE();
|
if(callstack.empty()) UNREACHABLE();
|
||||||
#endif
|
#endif
|
||||||
return callstack.top().get();
|
return callstack.top().get();
|
||||||
@ -166,14 +166,18 @@ public:
|
|||||||
if(_module == nullptr) _module = _main;
|
if(_module == nullptr) _module = _main;
|
||||||
try {
|
try {
|
||||||
CodeObject_ code = compile(source, filename, mode);
|
CodeObject_ code = compile(source, filename, mode);
|
||||||
// if(_module == _main) std::cout << disassemble(code) << '\n';
|
if(_module == _main) std::cout << disassemble(code) << '\n';
|
||||||
return _exec(code, _module);
|
return _exec(code, _module);
|
||||||
}catch (const Exception& e){
|
}catch (const Exception& e){
|
||||||
*_stderr << e.summary() << '\n';
|
*_stderr << e.summary() << '\n';
|
||||||
}catch (const std::exception& e) {
|
|
||||||
|
}
|
||||||
|
#if !DEBUG_MODE
|
||||||
|
catch (const std::exception& e) {
|
||||||
*_stderr << "An std::exception occurred! It could be a bug.\n";
|
*_stderr << "An std::exception occurred! It could be a bug.\n";
|
||||||
*_stderr << e.what() << '\n';
|
*_stderr << e.what() << '\n';
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
callstack = {};
|
callstack = {};
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -289,6 +293,7 @@ public:
|
|||||||
void NameError(StrName name){ _error("NameError", "name " + name.str().escape(true) + " is not defined"); }
|
void NameError(StrName name){ _error("NameError", "name " + name.str().escape(true) + " is not defined"); }
|
||||||
|
|
||||||
void AttributeError(PyObject* obj, StrName name){
|
void AttributeError(PyObject* obj, StrName name){
|
||||||
|
// OBJ_NAME calls getattr, which may lead to a infinite recursion
|
||||||
_error("AttributeError", "type " + OBJ_NAME(_t(obj)).escape(true) + " has no attribute " + name.str().escape(true));
|
_error("AttributeError", "type " + OBJ_NAME(_t(obj)).escape(true) + " has no attribute " + name.str().escape(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,74 +556,73 @@ inline PyObject* VM::new_module(StrName name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline Str VM::disassemble(CodeObject_ co){
|
inline Str VM::disassemble(CodeObject_ co){
|
||||||
return "";
|
auto pad = [](const Str& s, const int n){
|
||||||
// auto pad = [](const Str& s, const int n){
|
if(s.size() >= n) return s.substr(0, n);
|
||||||
// if(s.size() >= n) return s.substr(0, n);
|
return s + std::string(n - s.size(), ' ');
|
||||||
// return s + std::string(n - s.size(), ' ');
|
};
|
||||||
// };
|
|
||||||
|
|
||||||
// std::vector<int> jumpTargets;
|
std::vector<int> jumpTargets;
|
||||||
// for(auto byte : co->codes){
|
for(auto byte : co->codes){
|
||||||
// if(byte.op == OP_JUMP_ABSOLUTE || byte.op == OP_POP_JUMP_IF_FALSE){
|
if(byte.op == OP_JUMP_ABSOLUTE || byte.op == OP_POP_JUMP_IF_FALSE){
|
||||||
// jumpTargets.push_back(byte.arg);
|
jumpTargets.push_back(byte.arg);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// StrStream ss;
|
StrStream ss;
|
||||||
// ss << std::string(54, '-') << '\n';
|
ss << std::string(54, '-') << '\n';
|
||||||
// ss << co->name << ":\n";
|
ss << co->name << ":\n";
|
||||||
// int prev_line = -1;
|
int prev_line = -1;
|
||||||
// for(int i=0; i<co->codes.size(); i++){
|
for(int i=0; i<co->codes.size(); i++){
|
||||||
// const Bytecode& byte = co->codes[i];
|
const Bytecode& byte = co->codes[i];
|
||||||
// if(byte.op == OP_NO_OP) continue;
|
if(byte.op == OP_NO_OP) continue;
|
||||||
// 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{
|
||||||
// if(prev_line != -1) ss << "\n";
|
if(prev_line != -1) ss << "\n";
|
||||||
// prev_line = byte.line;
|
prev_line = byte.line;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// std::string pointer;
|
std::string pointer;
|
||||||
// if(std::find(jumpTargets.begin(), jumpTargets.end(), i) != jumpTargets.end()){
|
if(std::find(jumpTargets.begin(), jumpTargets.end(), i) != jumpTargets.end()){
|
||||||
// pointer = "-> ";
|
pointer = "-> ";
|
||||||
// }else{
|
}else{
|
||||||
// pointer = " ";
|
pointer = " ";
|
||||||
// }
|
}
|
||||||
// ss << pad(line, 8) << pointer << pad(std::to_string(i), 3);
|
ss << pad(line, 8) << pointer << pad(std::to_string(i), 3);
|
||||||
// ss << " " << pad(OP_NAMES[byte.op], 20) << " ";
|
ss << " " << pad(OP_NAMES[byte.op], 20) << " ";
|
||||||
// // ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5);
|
// ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5);
|
||||||
// std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
|
std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
|
||||||
// if(byte.op == OP_LOAD_CONST){
|
if(byte.op == OP_LOAD_CONST){
|
||||||
// argStr += " (" + CAST(Str, asRepr(co->consts[byte.arg])) + ")";
|
argStr += " (" + CAST(Str, asRepr(co->consts[byte.arg])) + ")";
|
||||||
// }
|
}
|
||||||
// if(byte.op == OP_LOAD_NAME_REF || byte.op == OP_LOAD_NAME || byte.op == OP_RAISE || byte.op == OP_STORE_NAME){
|
if(byte.op == OP_LOAD_NAME || byte.op == OP_STORE_LOCAL || byte.op == OP_STORE_GLOBAL){
|
||||||
// argStr += " (" + co->names[byte.arg].first.str().escape(true) + ")";
|
argStr += " (" + co->names[byte.arg].str().escape(true) + ")";
|
||||||
// }
|
}
|
||||||
// ss << argStr;
|
ss << argStr;
|
||||||
// // ss << pad(argStr, 20); // may overflow
|
// ss << pad(argStr, 20); // may overflow
|
||||||
// // ss << co->blocks[byte.block].to_string();
|
// ss << co->blocks[byte.block].to_string();
|
||||||
// if(i != co->codes.size() - 1) ss << '\n';
|
if(i != co->codes.size() - 1) ss << '\n';
|
||||||
// }
|
}
|
||||||
// StrStream consts;
|
StrStream consts;
|
||||||
// consts << "co_consts: ";
|
consts << "co_consts: ";
|
||||||
// consts << CAST(Str, asRepr(VAR(co->consts)));
|
consts << CAST(Str, asRepr(VAR(co->consts)));
|
||||||
|
|
||||||
// StrStream names;
|
StrStream names;
|
||||||
// names << "co_names: ";
|
names << "co_names: ";
|
||||||
// List list;
|
List list;
|
||||||
// for(int i=0; i<co->names.size(); i++){
|
for(int i=0; i<co->names.size(); i++){
|
||||||
// list.push_back(VAR(co->names[i].first.str()));
|
list.push_back(VAR(co->names[i].str()));
|
||||||
// }
|
}
|
||||||
// names << CAST(Str, asRepr(VAR(list)));
|
names << CAST(Str, asRepr(VAR(list)));
|
||||||
// ss << '\n' << consts.str() << '\n' << names.str() << '\n';
|
ss << '\n' << consts.str() << '\n' << names.str() << '\n';
|
||||||
|
|
||||||
// for(int i=0; i<co->consts.size(); i++){
|
for(int i=0; i<co->consts.size(); i++){
|
||||||
// PyObject* obj = co->consts[i];
|
PyObject* obj = co->consts[i];
|
||||||
// if(is_type(obj, tp_function)){
|
if(is_type(obj, tp_function)){
|
||||||
// const auto& f = CAST(Function&, obj);
|
const auto& f = CAST(Function&, obj);
|
||||||
// ss << disassemble(f.code);
|
ss << disassemble(f.code);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// return Str(ss.str());
|
return Str(ss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void VM::init_builtin_types(){
|
inline void VM::init_builtin_types(){
|
||||||
@ -877,7 +881,7 @@ inline PyObject* VM::_exec(){
|
|||||||
}catch(HandledException& e){
|
}catch(HandledException& e){
|
||||||
continue;
|
continue;
|
||||||
}catch(UnhandledException& e){
|
}catch(UnhandledException& e){
|
||||||
PyObject* obj = frame->pop();
|
PyObject* obj = frame->popx();
|
||||||
Exception& _e = CAST(Exception&, obj);
|
Exception& _e = CAST(Exception&, obj);
|
||||||
_e.st_push(frame->snapshot());
|
_e.st_push(frame->snapshot());
|
||||||
callstack.pop();
|
callstack.pop();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user