mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-23 21:10:19 +00:00
reimpl Str
This commit is contained in:
parent
7324f897b5
commit
c07ae35b8e
16
src/ceval.h
16
src/ceval.h
@ -33,7 +33,7 @@ __NEXT_STEP:;
|
||||
case OP_ROT_TWO: std::swap(frame->top(), frame->top_1()); DISPATCH();
|
||||
case OP_PRINT_EXPR: {
|
||||
PyObject* obj = frame->top(); // use top() to avoid accidental gc
|
||||
if(obj != None) *_stdout << CAST(Str, asRepr(obj)) << '\n';
|
||||
if(obj != None) *_stdout << CAST(Str&, asRepr(obj)) << '\n';
|
||||
frame->pop();
|
||||
} DISPATCH();
|
||||
/*****************************************/
|
||||
@ -168,7 +168,7 @@ __NEXT_STEP:;
|
||||
frame->push(VAR(std::move(items)));
|
||||
} DISPATCH();
|
||||
case OP_BUILD_STRING: {
|
||||
StrStream ss; // asStr() may run extra bytecode
|
||||
std::stringstream ss; // asStr() may run extra bytecode
|
||||
for(int i=byte.arg-1; i>=0; i--) ss << CAST(Str&, asStr(frame->top_n(i)));
|
||||
frame->pop_n(byte.arg);
|
||||
frame->push(VAR(ss.str()));
|
||||
@ -232,7 +232,7 @@ __NEXT_STEP:;
|
||||
case OP_GOTO: {
|
||||
StrName label = frame->co->names[byte.arg];
|
||||
auto it = frame->co->labels.find(label);
|
||||
if(it == frame->co->labels.end()) _error("KeyError", "label " + label.str().escape(true) + " not found");
|
||||
if(it == frame->co->labels.end()) _error("KeyError", fmt("label ", label.escape(), " not found"));
|
||||
frame->jump_abs_break(it->second);
|
||||
} DISPATCH();
|
||||
/*****************************************/
|
||||
@ -317,13 +317,13 @@ __NEXT_STEP:;
|
||||
auto it = _lazy_modules.find(name);
|
||||
if(it == _lazy_modules.end()){
|
||||
bool ok = false;
|
||||
source = _read_file_cwd(name.str() + ".py", &ok);
|
||||
if(!ok) _error("ImportError", "module " + name.str().escape(true) + " not found");
|
||||
source = _read_file_cwd(fmt(name, ".py"), &ok);
|
||||
if(!ok) _error("ImportError", fmt("module ", name.escape(), " not found"));
|
||||
}else{
|
||||
source = it->second;
|
||||
_lazy_modules.erase(it);
|
||||
}
|
||||
CodeObject_ code = compile(source, name.str(), EXEC_MODE);
|
||||
CodeObject_ code = compile(source, name.sv(), EXEC_MODE);
|
||||
PyObject* new_mod = new_module(name);
|
||||
_exec(code, new_mod);
|
||||
new_mod->attr()._try_perfect_rehash();
|
||||
@ -335,7 +335,7 @@ __NEXT_STEP:;
|
||||
case OP_IMPORT_STAR: {
|
||||
PyObject* obj = frame->popx();
|
||||
for(auto& [name, value]: obj->attr().items()){
|
||||
Str s = name.str();
|
||||
std::string_view s = name.sv();
|
||||
if(s.empty() || s[0] == '_') continue;
|
||||
frame->f_globals().set(name, value);
|
||||
}
|
||||
@ -416,7 +416,7 @@ __NEXT_STEP:;
|
||||
_error(type, msg);
|
||||
} DISPATCH();
|
||||
case OP_RE_RAISE: _raise(); DISPATCH();
|
||||
default: throw std::runtime_error(OP_NAMES[byte.op] + std::string(" is not implemented"));
|
||||
default: throw std::runtime_error(fmt(OP_NAMES[byte.op], " is not implemented"));
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
20
src/cffi.h
20
src/cffi.h
@ -131,14 +131,14 @@ struct TypeDB{
|
||||
return index == 0 ? nullptr : &_by_index[index-1];
|
||||
}
|
||||
|
||||
const TypeInfo* get(const char name[]) const {
|
||||
const TypeInfo* get(std::string_view name) const {
|
||||
auto it = _by_name.find(name);
|
||||
if(it == _by_name.end()) return nullptr;
|
||||
return get(it->second);
|
||||
}
|
||||
|
||||
const TypeInfo* get(const Str& s) const {
|
||||
return get(s.c_str());
|
||||
return get(s.sv());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@ -203,7 +203,7 @@ struct Pointer{
|
||||
|
||||
vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) {
|
||||
Pointer& self = CAST(Pointer&, args[0]);
|
||||
StrStream ss;
|
||||
std::stringstream ss;
|
||||
ss << "<" << self.ctype->name;
|
||||
for(int i=0; i<self.level; i++) ss << "*";
|
||||
ss << " at " << (i64)self.ptr << ">";
|
||||
@ -319,7 +319,7 @@ struct Pointer{
|
||||
Pointer _to(VM* vm, StrName name){
|
||||
auto it = ctype->members.find(name);
|
||||
if(it == ctype->members.end()){
|
||||
vm->AttributeError(Str("struct '") + ctype->name + "' has no member " + name.str().escape(true));
|
||||
vm->AttributeError(fmt("struct '", ctype->name, "' has no member ", name.escape()));
|
||||
}
|
||||
const MemberInfo& info = it->second;
|
||||
return {info.type, level, ptr+info.offset};
|
||||
@ -390,7 +390,7 @@ struct CType{
|
||||
vm->bind_static_method<1>(type, "__new__", [](VM* vm, Args& args) {
|
||||
const Str& name = CAST(Str&, args[0]);
|
||||
const TypeInfo* type = _type_db.get(name);
|
||||
if(type == nullptr) vm->TypeError("unknown type: " + name.escape(true));
|
||||
if(type == nullptr) vm->TypeError("unknown type: " + name.escape());
|
||||
return VAR_T(CType, type);
|
||||
});
|
||||
|
||||
@ -432,22 +432,22 @@ inline void add_module_c(VM* vm){
|
||||
Pointer& self = CAST(Pointer&, args[0]);
|
||||
const Str& name = CAST(Str&, args[1]);
|
||||
int level = 0;
|
||||
for(int i=name.size()-1; i>=0; i--){
|
||||
for(int i=name.length()-1; i>=0; i--){
|
||||
if(name[i] == '*') level++;
|
||||
else break;
|
||||
}
|
||||
if(level == 0) vm->TypeError("expect a pointer type, such as 'int*'");
|
||||
Str type_s = name.substr(0, name.size()-level);
|
||||
Str type_s = name.substr(0, name.length()-level);
|
||||
const TypeInfo* type = _type_db.get(type_s);
|
||||
if(type == nullptr) vm->TypeError("unknown type: " + type_s.escape(true));
|
||||
if(type == nullptr) vm->TypeError("unknown type: " + type_s.escape());
|
||||
return VAR_T(Pointer, type, level, self.ptr);
|
||||
});
|
||||
|
||||
vm->bind_func<1>(mod, "sizeof", [](VM* vm, Args& args) {
|
||||
const Str& name = CAST(Str&, args[0]);
|
||||
if(name.find('*') != Str::npos) return VAR(sizeof(void*));
|
||||
if(name.index("*") != -1) return VAR(sizeof(void*));
|
||||
const TypeInfo* type = _type_db.get(name);
|
||||
if(type == nullptr) vm->TypeError("unknown type: " + name.escape(true));
|
||||
if(type == nullptr) vm->TypeError("unknown type: " + name.escape());
|
||||
return VAR(type->size);
|
||||
});
|
||||
|
||||
|
@ -112,9 +112,9 @@ class Compiler {
|
||||
|
||||
void consume(TokenIndex expected) {
|
||||
if (!match(expected)){
|
||||
StrStream ss;
|
||||
ss << "expected '" << TK_STR(expected) << "', but got '" << TK_STR(curr().type) << "'";
|
||||
SyntaxError(ss.str());
|
||||
SyntaxError(
|
||||
fmt("expected '", TK_STR(expected), "', but got '", TK_STR(curr().type), "'")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ class Compiler {
|
||||
_compile_f_args(e->decl, false);
|
||||
consume(TK(":"));
|
||||
}
|
||||
e->decl->code = push_context(lexer->src, e->decl->name.str());
|
||||
e->decl->code = push_context(lexer->src, e->decl->name.sv());
|
||||
EXPR(false); // https://github.com/blueloveTH/pocketpy/issues/37
|
||||
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||
pop_context();
|
||||
@ -775,7 +775,7 @@ __SUBSCR_END:
|
||||
if(mode()!=EXEC_MODE) SyntaxError("'label' is only available in EXEC_MODE");
|
||||
consume(TK(".")); consume(TK("@id"));
|
||||
bool ok = ctx()->add_label(prev().str());
|
||||
if(!ok) SyntaxError("label " + prev().str().escape(true) + " already exists");
|
||||
if(!ok) SyntaxError("label " + prev().str().escape() + " already exists");
|
||||
consume_end_stmt();
|
||||
} break;
|
||||
case TK("goto"):
|
||||
@ -877,7 +877,7 @@ __SUBSCR_END:
|
||||
if(match(TK("->"))){
|
||||
if(!match(TK("None"))) consume(TK("@id"));
|
||||
}
|
||||
decl->code = push_context(lexer->src, decl->name.str());
|
||||
decl->code = push_context(lexer->src, decl->name.sv());
|
||||
compile_block_body();
|
||||
pop_context();
|
||||
ctx()->emit(OP_LOAD_FUNCTION, ctx()->add_func_decl(decl), prev().line);
|
||||
@ -928,7 +928,7 @@ __SUBSCR_END:
|
||||
void IndentationError(Str msg){ lexer->throw_err("IndentationError", msg, curr().line, curr().start); }
|
||||
|
||||
public:
|
||||
Compiler(VM* vm, const char* source, Str filename, CompileMode mode){
|
||||
Compiler(VM* vm, const Str& source, const Str& filename, CompileMode mode){
|
||||
this->vm = vm;
|
||||
this->used = false;
|
||||
this->lexer = std::make_unique<Lexer>(
|
||||
|
23
src/error.h
23
src/error.h
@ -38,14 +38,15 @@ struct SourceData {
|
||||
return {_start, i};
|
||||
}
|
||||
|
||||
SourceData(const char* source, Str filename, CompileMode mode) {
|
||||
SourceData(const Str& source, const Str& filename, CompileMode mode) {
|
||||
int index = 0;
|
||||
// Skip utf8 BOM if there is any.
|
||||
if (strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3;
|
||||
if (strncmp(source.begin(), "\xEF\xBB\xBF", 3) == 0) index += 3;
|
||||
// Remove all '\r'
|
||||
StrStream ss;
|
||||
while(*source != '\0'){
|
||||
if(*source != '\r') ss << *source;
|
||||
source++;
|
||||
std::stringstream ss;
|
||||
while(index < source.length()){
|
||||
if(source[index] != '\r') ss << source[index];
|
||||
index++;
|
||||
}
|
||||
|
||||
this->filename = filename;
|
||||
@ -55,14 +56,14 @@ struct SourceData {
|
||||
}
|
||||
|
||||
Str snapshot(int lineno, const char* cursor=nullptr){
|
||||
StrStream ss;
|
||||
std::stringstream ss;
|
||||
ss << " " << "File \"" << filename << "\", line " << lineno << '\n';
|
||||
std::pair<const char*,const char*> pair = get_line(lineno);
|
||||
Str line = "<?>";
|
||||
int removed_spaces = 0;
|
||||
if(pair.first && pair.second){
|
||||
line = Str(pair.first, pair.second-pair.first).lstrip();
|
||||
removed_spaces = pair.second - pair.first - line.size();
|
||||
removed_spaces = pair.second - pair.first - line.length();
|
||||
if(line.empty()) line = "<?>";
|
||||
}
|
||||
ss << " " << line;
|
||||
@ -91,11 +92,11 @@ public:
|
||||
|
||||
Str summary() const {
|
||||
StackTrace st(stacktrace);
|
||||
StrStream ss;
|
||||
std::stringstream ss;
|
||||
if(is_re) ss << "Traceback (most recent call last):\n";
|
||||
while(!st.empty()) { ss << st.top() << '\n'; st.pop(); }
|
||||
if (!msg.empty()) ss << type.str() << ": " << msg;
|
||||
else ss << type.str();
|
||||
if (!msg.empty()) ss << type.sv() << ": " << msg;
|
||||
else ss << type.sv();
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
76
src/expr.h
76
src/expr.h
@ -15,7 +15,7 @@ struct Expr{
|
||||
int line = 0;
|
||||
virtual ~Expr() = default;
|
||||
virtual void emit(CodeEmitContext* ctx) = 0;
|
||||
virtual Str str() const = 0;
|
||||
virtual std::string str() const = 0;
|
||||
|
||||
virtual bool is_starred() const { return false; }
|
||||
virtual bool is_literal() const { return false; }
|
||||
@ -23,7 +23,7 @@ struct Expr{
|
||||
virtual bool is_attrib() const { return false; }
|
||||
|
||||
// for OP_DELETE_XXX
|
||||
virtual bool emit_del(CodeEmitContext* ctx) { return false; }
|
||||
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; }
|
||||
|
||||
// for OP_STORE_XXX
|
||||
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) { return false; }
|
||||
@ -64,8 +64,8 @@ struct CodeEmitContext{
|
||||
expr->emit(this);
|
||||
}
|
||||
|
||||
Str _log_s_expr(){
|
||||
StrStream ss;
|
||||
std::string _log_s_expr(){
|
||||
std::stringstream ss;
|
||||
for(auto& e: s_expr.data()) ss << e->str() << " ";
|
||||
return ss.str();
|
||||
}
|
||||
@ -118,7 +118,7 @@ struct NameExpr: Expr{
|
||||
NameScope scope;
|
||||
NameExpr(StrName name, NameScope scope): name(name), scope(scope) {}
|
||||
|
||||
Str str() const override { return "$" + name.str(); }
|
||||
std::string str() const override { return fmt("Name(", name.escape(), ")"); }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
int index = ctx->add_name(name);
|
||||
@ -161,7 +161,7 @@ struct NameExpr: Expr{
|
||||
struct StarredExpr: Expr{
|
||||
Expr_ child;
|
||||
StarredExpr(Expr_&& child): child(std::move(child)) {}
|
||||
Str str() const override { return "*"; }
|
||||
std::string str() const override { return "Starred()"; }
|
||||
|
||||
bool is_starred() const override { return true; }
|
||||
|
||||
@ -180,7 +180,7 @@ struct StarredExpr: Expr{
|
||||
struct NotExpr: Expr{
|
||||
Expr_ child;
|
||||
NotExpr(Expr_&& child): child(std::move(child)) {}
|
||||
Str str() const override { return "not"; }
|
||||
std::string str() const override { return "Not()"; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
child->emit(ctx);
|
||||
@ -192,7 +192,7 @@ struct NotExpr: Expr{
|
||||
struct AndExpr: Expr{
|
||||
Expr_ lhs;
|
||||
Expr_ rhs;
|
||||
Str str() const override { return "and"; }
|
||||
std::string str() const override { return "And()"; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
lhs->emit(ctx);
|
||||
@ -206,7 +206,7 @@ struct AndExpr: Expr{
|
||||
struct OrExpr: Expr{
|
||||
Expr_ lhs;
|
||||
Expr_ rhs;
|
||||
Str str() const override { return "or"; }
|
||||
std::string str() const override { return "Or()"; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
lhs->emit(ctx);
|
||||
@ -220,7 +220,7 @@ struct OrExpr: Expr{
|
||||
struct Literal0Expr: Expr{
|
||||
TokenIndex token;
|
||||
Literal0Expr(TokenIndex token): token(token) {}
|
||||
Str str() const override { return TK_STR(token); }
|
||||
std::string str() const override { return TK_STR(token); }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
switch (token) {
|
||||
@ -239,7 +239,7 @@ struct Literal0Expr: Expr{
|
||||
struct LiteralExpr: Expr{
|
||||
TokenValue value;
|
||||
LiteralExpr(TokenValue value): value(value) {}
|
||||
Str str() const override {
|
||||
std::string str() const override {
|
||||
if(std::holds_alternative<i64>(value)){
|
||||
return std::to_string(std::get<i64>(value));
|
||||
}
|
||||
@ -249,7 +249,8 @@ struct LiteralExpr: Expr{
|
||||
}
|
||||
|
||||
if(std::holds_alternative<Str>(value)){
|
||||
return std::get<Str>(value).escape(true);
|
||||
Str s = std::get<Str>(value).escape();
|
||||
return s.str();
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
@ -285,7 +286,7 @@ struct LiteralExpr: Expr{
|
||||
struct NegatedExpr: Expr{
|
||||
Expr_ child;
|
||||
NegatedExpr(Expr_&& child): child(std::move(child)) {}
|
||||
Str str() const override { return "-"; }
|
||||
std::string str() const override { return "Negated()"; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
VM* vm = ctx->vm;
|
||||
@ -318,7 +319,7 @@ struct SliceExpr: Expr{
|
||||
Expr_ start;
|
||||
Expr_ stop;
|
||||
Expr_ step;
|
||||
Str str() const override { return "slice()"; }
|
||||
std::string str() const override { return "Slice()"; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
if(start){
|
||||
@ -346,7 +347,7 @@ struct SliceExpr: Expr{
|
||||
struct DictItemExpr: Expr{
|
||||
Expr_ key;
|
||||
Expr_ value;
|
||||
Str str() const override { return "k:v"; }
|
||||
std::string str() const override { return "DictItem()"; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
value->emit(ctx);
|
||||
@ -368,7 +369,7 @@ struct SequenceExpr: Expr{
|
||||
|
||||
struct ListExpr: SequenceExpr{
|
||||
using SequenceExpr::SequenceExpr;
|
||||
Str str() const override { return "list()"; }
|
||||
std::string str() const override { return "List()"; }
|
||||
Opcode opcode() const override { return OP_BUILD_LIST; }
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
@ -376,7 +377,7 @@ struct ListExpr: SequenceExpr{
|
||||
|
||||
struct DictExpr: SequenceExpr{
|
||||
using SequenceExpr::SequenceExpr;
|
||||
Str str() const override { return "dict()"; }
|
||||
std::string str() const override { return "Dict()"; }
|
||||
Opcode opcode() const override { return OP_BUILD_DICT; }
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
@ -384,13 +385,13 @@ struct DictExpr: SequenceExpr{
|
||||
|
||||
struct SetExpr: SequenceExpr{
|
||||
using SequenceExpr::SequenceExpr;
|
||||
Str str() const override { return "set()"; }
|
||||
std::string str() const override { return "Set()"; }
|
||||
Opcode opcode() const override { return OP_BUILD_SET; }
|
||||
};
|
||||
|
||||
struct TupleExpr: SequenceExpr{
|
||||
using SequenceExpr::SequenceExpr;
|
||||
Str str() const override { return "tuple()"; }
|
||||
std::string str() const override { return "Tuple()"; }
|
||||
Opcode opcode() const override { return OP_BUILD_TUPLE; }
|
||||
|
||||
bool emit_store(CodeEmitContext* ctx) override {
|
||||
@ -467,25 +468,25 @@ struct CompExpr: Expr{
|
||||
struct ListCompExpr: CompExpr{
|
||||
Opcode op0() override { return OP_BUILD_LIST; }
|
||||
Opcode op1() override { return OP_LIST_APPEND; }
|
||||
Str str() const override { return "listcomp()"; }
|
||||
std::string str() const override { return "ListComp()"; }
|
||||
};
|
||||
|
||||
struct DictCompExpr: CompExpr{
|
||||
Opcode op0() override { return OP_BUILD_DICT; }
|
||||
Opcode op1() override { return OP_DICT_ADD; }
|
||||
Str str() const override { return "dictcomp()"; }
|
||||
std::string str() const override { return "DictComp()"; }
|
||||
};
|
||||
|
||||
struct SetCompExpr: CompExpr{
|
||||
Opcode op0() override { return OP_BUILD_SET; }
|
||||
Opcode op1() override { return OP_SET_ADD; }
|
||||
Str str() const override { return "setcomp()"; }
|
||||
std::string str() const override { return "SetComp()"; }
|
||||
};
|
||||
|
||||
struct LambdaExpr: Expr{
|
||||
FuncDecl_ decl;
|
||||
NameScope scope;
|
||||
Str str() const override { return "<lambda>"; }
|
||||
std::string str() const override { return "Lambda()"; }
|
||||
|
||||
LambdaExpr(NameScope scope){
|
||||
this->decl = make_sp<FuncDecl>();
|
||||
@ -502,21 +503,21 @@ struct LambdaExpr: Expr{
|
||||
struct FStringExpr: Expr{
|
||||
Str src;
|
||||
FStringExpr(const Str& src): src(src) {}
|
||||
Str str() const override {
|
||||
return "f" + src.escape(true);
|
||||
std::string str() const override {
|
||||
return fmt("f", src.escape());
|
||||
}
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
VM* vm = ctx->vm;
|
||||
static const std::regex pattern(R"(\{(.*?)\})");
|
||||
std::sregex_iterator begin(src.begin(), src.end(), pattern);
|
||||
std::sregex_iterator end;
|
||||
std::cregex_iterator begin(src.begin(), src.end(), pattern);
|
||||
std::cregex_iterator end;
|
||||
int size = 0;
|
||||
int i = 0;
|
||||
for(auto it = begin; it != end; it++) {
|
||||
std::smatch m = *it;
|
||||
std::cmatch m = *it;
|
||||
if (i < m.position()) {
|
||||
std::string literal = src.substr(i, m.position() - i);
|
||||
Str literal = src.substr(i, m.position() - i);
|
||||
ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(literal)), line);
|
||||
size++;
|
||||
}
|
||||
@ -527,8 +528,8 @@ struct FStringExpr: Expr{
|
||||
size++;
|
||||
i = (int)(m.position() + m.length());
|
||||
}
|
||||
if (i < src.size()) {
|
||||
std::string literal = src.substr(i, src.size() - i);
|
||||
if (i < src.length()) {
|
||||
Str literal = src.substr(i, src.length() - i);
|
||||
ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(literal)), line);
|
||||
size++;
|
||||
}
|
||||
@ -539,7 +540,7 @@ struct FStringExpr: Expr{
|
||||
struct SubscrExpr: Expr{
|
||||
Expr_ a;
|
||||
Expr_ b;
|
||||
Str str() const override { return "a[b]"; }
|
||||
std::string str() const override { return "Subscr()"; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override{
|
||||
a->emit(ctx);
|
||||
@ -567,7 +568,7 @@ struct AttribExpr: Expr{
|
||||
Str b;
|
||||
AttribExpr(Expr_ a, const Str& b): a(std::move(a)), b(b) {}
|
||||
AttribExpr(Expr_ a, Str&& b): a(std::move(a)), b(std::move(b)) {}
|
||||
Str str() const override { return "a.b"; }
|
||||
std::string str() const override { return "Attrib()"; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override{
|
||||
a->emit(ctx);
|
||||
@ -603,7 +604,7 @@ struct CallExpr: Expr{
|
||||
Expr_ callable;
|
||||
std::vector<Expr_> args;
|
||||
std::vector<std::pair<Str, Expr_>> kwargs;
|
||||
Str str() const override { return "call(...)"; }
|
||||
std::string str() const override { return "Call()"; }
|
||||
|
||||
bool need_unpack() const {
|
||||
for(auto& item: args) if(item->is_starred()) return true;
|
||||
@ -643,7 +644,7 @@ struct BinaryExpr: Expr{
|
||||
TokenIndex op;
|
||||
Expr_ lhs;
|
||||
Expr_ rhs;
|
||||
Str str() const override { return TK_STR(op); }
|
||||
std::string str() const override { return TK_STR(op); }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
lhs->emit(ctx);
|
||||
@ -683,10 +684,7 @@ struct TernaryExpr: Expr{
|
||||
Expr_ cond;
|
||||
Expr_ true_expr;
|
||||
Expr_ false_expr;
|
||||
|
||||
Str str() const override {
|
||||
return "cond ? t : f";
|
||||
}
|
||||
std::string str() const override { return "Ternary()"; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
cond->emit(ctx);
|
||||
|
@ -43,8 +43,8 @@ struct Frame {
|
||||
return co->src->snapshot(line);
|
||||
}
|
||||
|
||||
Str stack_info(){
|
||||
StrStream ss;
|
||||
std::string stack_info(){
|
||||
std::stringstream ss;
|
||||
ss << id << " [";
|
||||
for(int i=0; i<_data.size(); i++){
|
||||
ss << (i64)_data[i];
|
||||
|
8
src/gc.h
8
src/gc.h
@ -37,7 +37,7 @@ struct ManagedHeap{
|
||||
template<typename T>
|
||||
PyObject* gcnew(Type type, T&& val){
|
||||
using __T = Py_<std::decay_t<T>>;
|
||||
PyObject* obj = new(pool128.alloc<__T>()) __T(type, std::forward<T>(val));
|
||||
PyObject* obj = new(pool64.alloc<__T>()) __T(type, std::forward<T>(val));
|
||||
gen.push_back(obj);
|
||||
gc_counter++;
|
||||
return obj;
|
||||
@ -46,7 +46,7 @@ struct ManagedHeap{
|
||||
template<typename T>
|
||||
PyObject* _new(Type type, T&& val){
|
||||
using __T = Py_<std::decay_t<T>>;
|
||||
PyObject* obj = new(pool128.alloc<__T>()) __T(type, std::forward<T>(val));
|
||||
PyObject* obj = new(pool64.alloc<__T>()) __T(type, std::forward<T>(val));
|
||||
obj->gc.enabled = false;
|
||||
_no_gc.push_back(obj);
|
||||
return obj;
|
||||
@ -57,7 +57,7 @@ struct ManagedHeap{
|
||||
#endif
|
||||
|
||||
~ManagedHeap(){
|
||||
for(PyObject* obj: _no_gc) obj->~PyObject(), pool128.dealloc(obj);
|
||||
for(PyObject* obj: _no_gc) obj->~PyObject(), pool64.dealloc(obj);
|
||||
#if DEBUG_GC_STATS
|
||||
for(auto& [type, count]: deleted){
|
||||
std::cout << "GC: " << obj_type_name(vm, type) << "=" << count << std::endl;
|
||||
@ -75,7 +75,7 @@ struct ManagedHeap{
|
||||
#if DEBUG_GC_STATS
|
||||
deleted[obj->type] += 1;
|
||||
#endif
|
||||
obj->~PyObject(), pool128.dealloc(obj);
|
||||
obj->~PyObject(), pool64.dealloc(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
13
src/lexer.h
13
src/lexer.h
@ -57,12 +57,13 @@ struct Token{
|
||||
TokenValue value;
|
||||
|
||||
Str str() const { return Str(start, length);}
|
||||
std::string_view sv() const { return std::string_view(start, length);}
|
||||
|
||||
Str info() const {
|
||||
StrStream ss;
|
||||
Str raw = str();
|
||||
if (raw == Str("\n")) raw = "\\n";
|
||||
ss << line << ": " << TK_STR(type) << " '" << raw << "'";
|
||||
std::string info() const {
|
||||
std::stringstream ss;
|
||||
ss << line << ": " << TK_STR(type) << " '" << (
|
||||
sv()=="\n" ? "\\n" : sv()
|
||||
) << "'";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
@ -171,7 +172,7 @@ struct Lexer {
|
||||
curr_char--;
|
||||
while(true){
|
||||
unsigned char c = peekchar();
|
||||
int u8bytes = utf8len(c);
|
||||
int u8bytes = utf8len(c, true);
|
||||
if(u8bytes == 0) return 1;
|
||||
if(u8bytes == 1){
|
||||
if(isalpha(c) || c=='_' || isdigit(c)) {
|
||||
|
@ -87,7 +87,7 @@ while(!_items[i].first.empty()) { \
|
||||
PyObject* operator[](StrName key) const {
|
||||
bool ok; uint16_t i;
|
||||
HASH_PROBE(key, ok, i);
|
||||
if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
|
||||
if(!ok) throw std::out_of_range(fmt("NameDict key not found: ", key));
|
||||
return _items[i].second;
|
||||
}
|
||||
|
||||
@ -159,7 +159,7 @@ while(!_items[i].first.empty()) { \
|
||||
void erase(StrName key){
|
||||
bool ok; uint16_t i;
|
||||
HASH_PROBE(key, ok, i);
|
||||
if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
|
||||
if(!ok) throw std::out_of_range(fmt("NameDict key not found: ", key));
|
||||
_items[i].first = StrName();
|
||||
_items[i].second = nullptr;
|
||||
_size--;
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace pkpy {
|
||||
|
||||
inline CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) {
|
||||
Compiler compiler(this, source.c_str(), filename, mode);
|
||||
Compiler compiler(this, source, filename, mode);
|
||||
try{
|
||||
return compiler.compile();
|
||||
}catch(Exception& e){
|
||||
@ -71,7 +71,7 @@ inline void init_builtins(VM* _vm) {
|
||||
if(!vm->isinstance(args[1], type)){
|
||||
Str _0 = obj_type_name(vm, OBJ_GET(Type, vm->_t(args[1])));
|
||||
Str _1 = obj_type_name(vm, type);
|
||||
vm->TypeError("super(): " + _0.escape(true) + " is not an instance of " + _1.escape(true));
|
||||
vm->TypeError("super(): " + _0.escape() + " is not an instance of " + _1.escape());
|
||||
}
|
||||
Type base = vm->_all_types[type].base;
|
||||
return vm->heap.gcnew(vm->tp_super, Super(args[1], base));
|
||||
@ -150,7 +150,7 @@ inline void init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_vm->bind_builtin_func<1>("hex", [](VM* vm, Args& args) {
|
||||
StrStream ss;
|
||||
std::stringstream ss;
|
||||
ss << std::hex << CAST(i64, args[0]);
|
||||
return VAR("0x" + ss.str());
|
||||
});
|
||||
@ -169,14 +169,14 @@ inline void init_builtins(VM* _vm) {
|
||||
std::vector<StrName> keys = t_attr.keys();
|
||||
names.insert(keys.begin(), keys.end());
|
||||
List ret;
|
||||
for (StrName name : names) ret.push_back(VAR(name.str()));
|
||||
for (StrName name : names) ret.push_back(VAR(name.sv()));
|
||||
return VAR(std::move(ret));
|
||||
});
|
||||
|
||||
_vm->bind_method<0>("object", "__repr__", [](VM* vm, Args& args) {
|
||||
PyObject* self = args[0];
|
||||
if(is_tagged(self)) self = nullptr;
|
||||
StrStream ss;
|
||||
std::stringstream ss;
|
||||
ss << "<" << OBJ_NAME(vm->_t(self)) << " object at " << std::hex << self << ">";
|
||||
return VAR(ss.str());
|
||||
});
|
||||
@ -241,7 +241,7 @@ inline void init_builtins(VM* _vm) {
|
||||
if(parsed != s.length()) throw std::invalid_argument("<?>");
|
||||
return VAR(val);
|
||||
}catch(std::invalid_argument&){
|
||||
vm->ValueError("invalid literal for int(): " + s.escape(true));
|
||||
vm->ValueError("invalid literal for int(): " + s.escape());
|
||||
}
|
||||
}
|
||||
vm->TypeError("int() argument must be a int, float, bool or str");
|
||||
@ -297,7 +297,7 @@ inline void init_builtins(VM* _vm) {
|
||||
_vm->bind_method<0>("float", "__repr__", [](VM* vm, Args& args) {
|
||||
f64 val = CAST(f64, args[0]);
|
||||
if(std::isinf(val) || std::isnan(val)) return VAR(std::to_string(val));
|
||||
StrStream ss;
|
||||
std::stringstream ss;
|
||||
ss << std::setprecision(std::numeric_limits<f64>::max_digits10-1-2) << val;
|
||||
std::string s = ss.str();
|
||||
if(std::all_of(s.begin()+1, s.end(), isdigit)) s += ".0";
|
||||
@ -335,7 +335,7 @@ inline void init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind_method<0>("str", "__repr__", [](VM* vm, Args& args) {
|
||||
const Str& _self = CAST(Str&, args[0]);
|
||||
return VAR(_self.escape(true));
|
||||
return VAR(_self.escape());
|
||||
});
|
||||
|
||||
_vm->bind_method<0>("str", "__json__", [](VM* vm, Args& args) {
|
||||
@ -405,7 +405,7 @@ inline void init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind_method<1>("str", "join", [](VM* vm, Args& args) {
|
||||
const Str& self = CAST(Str&, args[0]);
|
||||
StrStream ss;
|
||||
FastStrStream ss;
|
||||
PyObject* obj = vm->asList(args[1]);
|
||||
const List& list = CAST(List&, obj);
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
@ -639,8 +639,8 @@ struct ReMatch {
|
||||
|
||||
i64 start;
|
||||
i64 end;
|
||||
std::smatch m;
|
||||
ReMatch(i64 start, i64 end, std::smatch m) : start(start), end(end), m(m) {}
|
||||
std::cmatch m;
|
||||
ReMatch(i64 start, i64 end, std::cmatch m) : start(start), end(end), m(m) {}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||
vm->bind_method<-1>(type, "__init__", CPP_NOT_IMPLEMENTED());
|
||||
@ -661,15 +661,13 @@ struct ReMatch {
|
||||
}
|
||||
};
|
||||
|
||||
inline PyObject* _regex_search(const Str& _pattern, const Str& _string, bool fromStart, VM* vm){
|
||||
std::string pattern = _pattern.str();
|
||||
std::string string = _string.str();
|
||||
std::regex re(pattern);
|
||||
std::smatch m;
|
||||
if(std::regex_search(string, m, re)){
|
||||
if(fromStart && m.position() != 0) return vm->None;
|
||||
i64 start = _string._u8_index(m.position());
|
||||
i64 end = _string._u8_index(m.position() + m.length());
|
||||
inline PyObject* _regex_search(const Str& pattern, const Str& string, bool from_start, VM* vm){
|
||||
std::regex re(pattern.begin(), pattern.end());
|
||||
std::cmatch m;
|
||||
if(std::regex_search(string.begin(), string.end(), m, re)){
|
||||
if(from_start && m.position() != 0) return vm->None;
|
||||
i64 start = string._byte_index_to_unicode(m.position());
|
||||
i64 end = string._byte_index_to_unicode(m.position() + m.length());
|
||||
return VAR_T(ReMatch, start, end, m);
|
||||
}
|
||||
return vm->None;
|
||||
@ -694,18 +692,17 @@ inline void add_module_re(VM* vm){
|
||||
vm->bind_func<3>(mod, "sub", [](VM* vm, Args& args) {
|
||||
const Str& pattern = CAST(Str&, args[0]);
|
||||
const Str& repl = CAST(Str&, args[1]);
|
||||
const Str& _string = CAST(Str&, args[2]);
|
||||
std::regex re(pattern.str());
|
||||
std::string string = _string.str();
|
||||
return VAR(std::regex_replace(string, re, repl));
|
||||
const Str& string = CAST(Str&, args[2]);
|
||||
std::regex re(pattern.begin(), pattern.end());
|
||||
return VAR(std::regex_replace(string.str(), re, repl.str()));
|
||||
});
|
||||
|
||||
vm->bind_func<2>(mod, "split", [](VM* vm, Args& args) {
|
||||
std::string pattern = CAST(Str&, args[0]).str();
|
||||
std::string string = CAST(Str&, args[1]).str();
|
||||
std::regex re(pattern);
|
||||
std::sregex_token_iterator it(string.begin(), string.end(), re, -1);
|
||||
std::sregex_token_iterator end;
|
||||
const Str& pattern = CAST(Str&, args[0]);
|
||||
const Str& string = CAST(Str&, args[1]);
|
||||
std::regex re(pattern.begin(), pattern.end());
|
||||
std::cregex_token_iterator it(string.begin(), string.end(), re, -1);
|
||||
std::cregex_token_iterator end;
|
||||
List vec;
|
||||
for(; it != end; ++it){
|
||||
vec.push_back(VAR(it->str()));
|
||||
@ -863,8 +860,8 @@ extern "C" {
|
||||
pkpy::PyObject* val = vm->_main->attr().try_get(name);
|
||||
if(val == nullptr) return nullptr;
|
||||
try{
|
||||
pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(val));
|
||||
return strdup(repr.c_str());
|
||||
pkpy::Str repr = pkpy::CAST(pkpy::Str&, vm->asRepr(val));
|
||||
return repr.c_str_dup();
|
||||
}catch(...){
|
||||
return nullptr;
|
||||
}
|
||||
@ -879,8 +876,8 @@ extern "C" {
|
||||
pkpy::PyObject* ret = vm->exec(source, "<eval>", pkpy::EVAL_MODE);
|
||||
if(ret == nullptr) return nullptr;
|
||||
try{
|
||||
pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(ret));
|
||||
return strdup(repr.c_str());
|
||||
pkpy::Str repr = pkpy::CAST(pkpy::Str&, vm->asRepr(ret));
|
||||
return repr.c_str_dup();
|
||||
}catch(...){
|
||||
return nullptr;
|
||||
}
|
||||
@ -917,12 +914,12 @@ extern "C" {
|
||||
///
|
||||
/// Return a json representing the result.
|
||||
char* pkpy_vm_read_output(pkpy::VM* vm){
|
||||
if(vm->use_stdio) return nullptr;
|
||||
pkpy::StrStream* s_out = (pkpy::StrStream*)(vm->_stdout);
|
||||
pkpy::StrStream* s_err = (pkpy::StrStream*)(vm->_stderr);
|
||||
if(vm->is_stdio_used()) return nullptr;
|
||||
std::stringstream* s_out = (std::stringstream*)(vm->_stdout);
|
||||
std::stringstream* s_err = (std::stringstream*)(vm->_stderr);
|
||||
pkpy::Str _stdout = s_out->str();
|
||||
pkpy::Str _stderr = s_err->str();
|
||||
pkpy::StrStream ss;
|
||||
std::stringstream ss;
|
||||
ss << '{' << "\"stdout\": " << _stdout.escape(false);
|
||||
ss << ", " << "\"stderr\": " << _stderr.escape(false) << '}';
|
||||
s_out->str(""); s_err->str("");
|
||||
@ -961,7 +958,7 @@ extern "C" {
|
||||
std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++);
|
||||
pkpy::PyObject* obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod);
|
||||
vm->bind_func<-1>(obj, name, [ret_code, f_header](pkpy::VM* vm, const pkpy::Args& args){
|
||||
pkpy::StrStream ss;
|
||||
std::stringstream ss;
|
||||
ss << f_header;
|
||||
for(int i=0; i<args.size(); i++){
|
||||
ss << ' ';
|
||||
|
138
src/str.h
138
src/str.h
@ -2,18 +2,19 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "memory.h"
|
||||
#include "vector.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
typedef std::stringstream StrStream;
|
||||
|
||||
inline int utf8len(unsigned char c){
|
||||
// TODO: check error if return 0
|
||||
inline int utf8len(unsigned char c, bool suppress=false){
|
||||
if((c & 0b10000000) == 0) return 1;
|
||||
if((c & 0b11100000) == 0b11000000) return 2;
|
||||
if((c & 0b11110000) == 0b11100000) return 3;
|
||||
if((c & 0b11111000) == 0b11110000) return 4;
|
||||
if((c & 0b11111100) == 0b11111000) return 5;
|
||||
if((c & 0b11111110) == 0b11111100) return 6;
|
||||
if(!suppress) throw std::runtime_error("invalid utf8 char: " + std::to_string(c));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -21,9 +22,8 @@ struct Str{
|
||||
int size;
|
||||
bool is_ascii;
|
||||
char* data;
|
||||
uint16_t _cached_sn_index = 0;
|
||||
|
||||
Str(): size(0), is_ascii(true), data((char*)pool64.alloc(0)) {}
|
||||
Str(): size(0), is_ascii(true), data(nullptr) {}
|
||||
|
||||
Str(int size, bool is_ascii): size(size), is_ascii(is_ascii) {
|
||||
data = (char*)pool64.alloc(size);
|
||||
@ -64,6 +64,13 @@ struct Str{
|
||||
other.size = 0;
|
||||
}
|
||||
|
||||
const char* begin() const { return data; }
|
||||
const char* end() const { return data + size; }
|
||||
char operator[](int idx) const { return data[idx]; }
|
||||
int length() const { return size; }
|
||||
bool empty() const { return size == 0; }
|
||||
size_t hash() const{ return std::hash<std::string_view>()(sv()); }
|
||||
|
||||
Str& operator=(const Str& other){
|
||||
if(data!=nullptr) pool64.dealloc(data);
|
||||
size = other.size;
|
||||
@ -86,18 +93,6 @@ struct Str{
|
||||
if(data!=nullptr) pool64.dealloc(data);
|
||||
}
|
||||
|
||||
char operator[](int idx) const {
|
||||
return data[idx];
|
||||
}
|
||||
|
||||
int length() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t hash() const{
|
||||
return std::hash<std::string_view>()(sv());
|
||||
}
|
||||
|
||||
Str operator+(const Str& other) const {
|
||||
Str ret(size + other.size, is_ascii && other.is_ascii);
|
||||
memcpy(ret.data, data, size);
|
||||
@ -116,7 +111,7 @@ struct Str{
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Str& str){
|
||||
os.write(str.data, str.size);
|
||||
if(str.data!=nullptr) os.write(str.data, str.size);
|
||||
return os;
|
||||
}
|
||||
|
||||
@ -136,6 +131,16 @@ struct Str{
|
||||
return size < other.size;
|
||||
}
|
||||
|
||||
bool operator<(const std::string_view& other) const {
|
||||
int ret = strncmp(data, other.data(), std::min(size, (int)other.size()));
|
||||
if(ret != 0) return ret < 0;
|
||||
return size < (int)other.size();
|
||||
}
|
||||
|
||||
friend bool operator<(const std::string_view& other, const Str& str){
|
||||
return str > other;
|
||||
}
|
||||
|
||||
bool operator>(const Str& other) const {
|
||||
int ret = strncmp(data, other.data, std::min(size, other.size));
|
||||
if(ret != 0) return ret > 0;
|
||||
@ -176,7 +181,7 @@ struct Str{
|
||||
}
|
||||
|
||||
Str lstrip() const {
|
||||
std::string copy = str();
|
||||
std::string copy(data, size);
|
||||
copy.erase(copy.begin(), std::find_if(copy.begin(), copy.end(), [](char c) {
|
||||
// std::isspace(c) does not working on windows (Debug)
|
||||
return c != ' ' && c != '\t' && c != '\r' && c != '\n';
|
||||
@ -184,8 +189,8 @@ struct Str{
|
||||
return Str(copy);
|
||||
}
|
||||
|
||||
Str escape(bool single_quote) const {
|
||||
StrStream ss;
|
||||
Str escape(bool single_quote=true) const {
|
||||
std::stringstream ss;
|
||||
ss << (single_quote ? '\'' : '"');
|
||||
for (int i=0; i<length(); i++) {
|
||||
char c = this->operator[](i);
|
||||
@ -215,31 +220,32 @@ struct Str{
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
int index(const Str& sub) const {
|
||||
auto p = std::search(data, data + size, sub.data, sub.data + sub.size);
|
||||
int index(const Str& sub, int start=0) const {
|
||||
auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size);
|
||||
if(p == data + size) return -1;
|
||||
return p - data;
|
||||
}
|
||||
|
||||
Str replace(const Str& old, const Str& new_) const {
|
||||
StrStream ss;
|
||||
int i = 0;
|
||||
while(i < size){
|
||||
int j = index(old);
|
||||
if(j == -1){
|
||||
ss << substr(i, size - i);
|
||||
std::stringstream ss;
|
||||
int start = 0;
|
||||
while(true){
|
||||
int i = index(old, start);
|
||||
if(i == -1){
|
||||
ss << substr(start, size - start);
|
||||
break;
|
||||
}
|
||||
ss << substr(i, j - i);
|
||||
ss << substr(start, i - start);
|
||||
ss << new_;
|
||||
i = j + old.size;
|
||||
start = i + old.size;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/*************unicode*************/
|
||||
|
||||
int _u8_index(int i) const{
|
||||
// TODO: check error
|
||||
int _unicode_index_to_byte(int i) const{
|
||||
if(is_ascii) return i;
|
||||
int j = 0;
|
||||
while(i > 0){
|
||||
@ -249,28 +255,39 @@ struct Str{
|
||||
return j;
|
||||
}
|
||||
|
||||
int _byte_index_to_unicode(int n) const{
|
||||
if(is_ascii) return n;
|
||||
int cnt = 0;
|
||||
for(int i=0; i<n; i++){
|
||||
if((data[i] & 0xC0) != 0x80) cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
Str u8_getitem(int i) const{
|
||||
i = _u8_index(i);
|
||||
i = _unicode_index_to_byte(i);
|
||||
return substr(i, utf8len(data[i]));
|
||||
}
|
||||
|
||||
Str u8_slice(int start, int end) const{
|
||||
// TODO: optimize this
|
||||
start = _u8_index(start);
|
||||
end = _u8_index(end);
|
||||
start = _unicode_index_to_byte(start);
|
||||
end = _unicode_index_to_byte(end);
|
||||
return substr(start, end - start);
|
||||
}
|
||||
|
||||
int u8_length() const {
|
||||
if(is_ascii) return size;
|
||||
int ret = 0;
|
||||
for(int i=0; i<size; i++){
|
||||
if((data[i] & 0xC0) != 0x80) ret++;
|
||||
}
|
||||
return ret;
|
||||
return _byte_index_to_unicode(size);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
inline std::string fmt(Args&&... args) {
|
||||
std::stringstream ss;
|
||||
(ss << ... << args);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
const uint32_t kLoRangeA[] = {170,186,443,448,660,1488,1519,1568,1601,1646,1649,1749,1774,1786,1791,1808,1810,1869,1969,1994,2048,2112,2144,2208,2230,2308,2365,2384,2392,2418,2437,2447,2451,2474,2482,2486,2493,2510,2524,2527,2544,2556,2565,2575,2579,2602,2610,2613,2616,2649,2654,2674,2693,2703,2707,2730,2738,2741,2749,2768,2784,2809,2821,2831,2835,2858,2866,2869,2877,2908,2911,2929,2947,2949,2958,2962,2969,2972,2974,2979,2984,2990,3024,3077,3086,3090,3114,3133,3160,3168,3200,3205,3214,3218,3242,3253,3261,3294,3296,3313,3333,3342,3346,3389,3406,3412,3423,3450,3461,3482,3507,3517,3520,3585,3634,3648,3713,3716,3718,3724,3749,3751,3762,3773,3776,3804,3840,3904,3913,3976,4096,4159,4176,4186,4193,4197,4206,4213,4238,4352,4682,4688,4696,4698,4704,4746,4752,4786,4792,4800,4802,4808,4824,4882,4888,4992,5121,5743,5761,5792,5873,5888,5902,5920,5952,5984,5998,6016,6108,6176,6212,6272,6279,6314,6320,6400,6480,6512,6528,6576,6656,6688,6917,6981,7043,7086,7098,7168,7245,7258,7401,7406,7413,7418,8501,11568,11648,11680,11688,11696,11704,11712,11720,11728,11736,12294,12348,12353,12447,12449,12543,12549,12593,12704,12784,13312,19968,40960,40982,42192,42240,42512,42538,42606,42656,42895,42999,43003,43011,43015,43020,43072,43138,43250,43259,43261,43274,43312,43360,43396,43488,43495,43514,43520,43584,43588,43616,43633,43642,43646,43697,43701,43705,43712,43714,43739,43744,43762,43777,43785,43793,43808,43816,43968,44032,55216,55243,63744,64112,64285,64287,64298,64312,64318,64320,64323,64326,64467,64848,64914,65008,65136,65142,65382,65393,65440,65474,65482,65490,65498,65536,65549,65576,65596,65599,65616,65664,66176,66208,66304,66349,66370,66384,66432,66464,66504,66640,66816,66864,67072,67392,67424,67584,67592,67594,67639,67644,67647,67680,67712,67808,67828,67840,67872,67968,68030,68096,68112,68117,68121,68192,68224,68288,68297,68352,68416,68448,68480,68608,68864,69376,69415,69424,69600,69635,69763,69840,69891,69956,69968,70006,70019,70081,70106,70108,70144,70163,70272,70280,70282,70287,70303,70320,70405,70415,70419,70442,70450,70453,70461,70480,70493,70656,70727,70751,70784,70852,70855,71040,71128,71168,71236,71296,71352,71424,71680,71935,72096,72106,72161,72163,72192,72203,72250,72272,72284,72349,72384,72704,72714,72768,72818,72960,72968,72971,73030,73056,73063,73066,73112,73440,73728,74880,77824,82944,92160,92736,92880,92928,93027,93053,93952,94032,94208,100352,110592,110928,110948,110960,113664,113776,113792,113808,123136,123214,123584,124928,126464,126469,126497,126500,126503,126505,126516,126521,126523,126530,126535,126537,126539,126541,126545,126548,126551,126553,126555,126557,126559,126561,126564,126567,126572,126580,126585,126590,126592,126603,126625,126629,126635,131072,173824,177984,178208,183984,194560};
|
||||
const uint32_t kLoRangeB[] = {170,186,443,451,660,1514,1522,1599,1610,1647,1747,1749,1775,1788,1791,1808,1839,1957,1969,2026,2069,2136,2154,2228,2237,2361,2365,2384,2401,2432,2444,2448,2472,2480,2482,2489,2493,2510,2525,2529,2545,2556,2570,2576,2600,2608,2611,2614,2617,2652,2654,2676,2701,2705,2728,2736,2739,2745,2749,2768,2785,2809,2828,2832,2856,2864,2867,2873,2877,2909,2913,2929,2947,2954,2960,2965,2970,2972,2975,2980,2986,3001,3024,3084,3088,3112,3129,3133,3162,3169,3200,3212,3216,3240,3251,3257,3261,3294,3297,3314,3340,3344,3386,3389,3406,3414,3425,3455,3478,3505,3515,3517,3526,3632,3635,3653,3714,3716,3722,3747,3749,3760,3763,3773,3780,3807,3840,3911,3948,3980,4138,4159,4181,4189,4193,4198,4208,4225,4238,4680,4685,4694,4696,4701,4744,4749,4784,4789,4798,4800,4805,4822,4880,4885,4954,5007,5740,5759,5786,5866,5880,5900,5905,5937,5969,5996,6000,6067,6108,6210,6264,6276,6312,6314,6389,6430,6509,6516,6571,6601,6678,6740,6963,6987,7072,7087,7141,7203,7247,7287,7404,7411,7414,7418,8504,11623,11670,11686,11694,11702,11710,11718,11726,11734,11742,12294,12348,12438,12447,12538,12543,12591,12686,12730,12799,19893,40943,40980,42124,42231,42507,42527,42539,42606,42725,42895,42999,43009,43013,43018,43042,43123,43187,43255,43259,43262,43301,43334,43388,43442,43492,43503,43518,43560,43586,43595,43631,43638,43642,43695,43697,43702,43709,43712,43714,43740,43754,43762,43782,43790,43798,43814,43822,44002,55203,55238,55291,64109,64217,64285,64296,64310,64316,64318,64321,64324,64433,64829,64911,64967,65019,65140,65276,65391,65437,65470,65479,65487,65495,65500,65547,65574,65594,65597,65613,65629,65786,66204,66256,66335,66368,66377,66421,66461,66499,66511,66717,66855,66915,67382,67413,67431,67589,67592,67637,67640,67644,67669,67702,67742,67826,67829,67861,67897,68023,68031,68096,68115,68119,68149,68220,68252,68295,68324,68405,68437,68466,68497,68680,68899,69404,69415,69445,69622,69687,69807,69864,69926,69956,70002,70006,70066,70084,70106,70108,70161,70187,70278,70280,70285,70301,70312,70366,70412,70416,70440,70448,70451,70457,70461,70480,70497,70708,70730,70751,70831,70853,70855,71086,71131,71215,71236,71338,71352,71450,71723,71935,72103,72144,72161,72163,72192,72242,72250,72272,72329,72349,72440,72712,72750,72768,72847,72966,72969,73008,73030,73061,73064,73097,73112,73458,74649,75075,78894,83526,92728,92766,92909,92975,93047,93071,94026,94032,100343,101106,110878,110930,110951,111355,113770,113788,113800,113817,123180,123214,123627,125124,126467,126495,126498,126500,126503,126514,126519,126521,126523,126530,126535,126537,126539,126543,126546,126548,126551,126553,126555,126557,126559,126562,126564,126570,126578,126583,126588,126590,126601,126619,126627,126633,126651,173782,177972,178205,183969,191456,195101};
|
||||
|
||||
@ -289,15 +306,19 @@ struct StrName {
|
||||
StrName(uint16_t index): index(index) {}
|
||||
StrName(const char* s): index(get(s).index) {}
|
||||
StrName(const Str& s){
|
||||
if(s._cached_sn_index != 0){
|
||||
index = s._cached_sn_index;
|
||||
} else {
|
||||
index = get(s.sv()).index;
|
||||
}
|
||||
}
|
||||
const Str& str() const { return _r_interned[index-1]; }
|
||||
std::string_view sv() const { return _r_interned[index-1].sv(); }
|
||||
bool empty() const { return index == 0; }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const StrName& sn){
|
||||
return os << sn.sv();
|
||||
}
|
||||
|
||||
Str escape() const {
|
||||
return _r_interned[index-1].escape();
|
||||
}
|
||||
|
||||
bool operator==(const StrName& other) const noexcept {
|
||||
return this->index == other.index;
|
||||
}
|
||||
@ -327,6 +348,31 @@ struct StrName {
|
||||
}
|
||||
};
|
||||
|
||||
struct FastStrStream{
|
||||
pod_vector<const Str*> parts;
|
||||
|
||||
FastStrStream& operator<<(const Str& s){
|
||||
parts.push_back(&s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Str str() const{
|
||||
int len = 0;
|
||||
bool is_ascii = true;
|
||||
for(auto& s: parts){
|
||||
len += s->length();
|
||||
is_ascii &= s->is_ascii;
|
||||
}
|
||||
Str result(len, is_ascii);
|
||||
char* p = result.data;
|
||||
for(auto& s: parts){
|
||||
memcpy(p, s->data, s->length());
|
||||
p += s->length();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::map<Str, uint16_t, std::less<>> StrName::_interned;
|
||||
inline std::vector<Str> StrName::_r_interned;
|
||||
|
||||
|
86
src/vm.h
86
src/vm.h
@ -71,7 +71,8 @@ public:
|
||||
PyObject* builtins; // builtins module
|
||||
PyObject* _main; // __main__ module
|
||||
|
||||
bool use_stdio;
|
||||
std::stringstream _stdout_buffer;
|
||||
std::stringstream _stderr_buffer;
|
||||
std::ostream* _stdout;
|
||||
std::ostream* _stderr;
|
||||
int recursionlimit = 1000;
|
||||
@ -85,18 +86,13 @@ public:
|
||||
|
||||
VM(bool use_stdio) : heap(this){
|
||||
this->vm = this;
|
||||
this->use_stdio = use_stdio;
|
||||
if(use_stdio){
|
||||
this->_stdout = &std::cout;
|
||||
this->_stderr = &std::cerr;
|
||||
}else{
|
||||
this->_stdout = new StrStream();
|
||||
this->_stderr = new StrStream();
|
||||
}
|
||||
|
||||
this->_stdout = use_stdio ? &std::cout : &_stdout_buffer;
|
||||
this->_stderr = use_stdio ? &std::cerr : &_stderr_buffer;
|
||||
init_builtin_types();
|
||||
}
|
||||
|
||||
bool is_stdio_used() const { return _stdout == &std::cout; }
|
||||
|
||||
Frame* top_frame() const {
|
||||
#if DEBUG_EXTRA_CHECK
|
||||
if(callstack.empty()) UNREACHABLE();
|
||||
@ -116,7 +112,7 @@ public:
|
||||
PyObject* self;
|
||||
PyObject* iter_f = get_unbound_method(obj, __iter__, &self, false);
|
||||
if(self != _py_null) return call(iter_f, Args{self});
|
||||
TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable");
|
||||
TypeError(OBJ_NAME(_t(obj)).escape() + " object is not iterable");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -210,7 +206,7 @@ public:
|
||||
PyTypeInfo info{
|
||||
.obj = obj,
|
||||
.base = base,
|
||||
.name = (mod!=nullptr && mod!=builtins) ? Str(OBJ_NAME(mod)+"."+name.str()): name.str()
|
||||
.name = (mod!=nullptr && mod!=builtins) ? Str(OBJ_NAME(mod)+"."+name.sv()): name.sv()
|
||||
};
|
||||
if(mod != nullptr) mod->attr().set(name, obj);
|
||||
_all_types.push_back(info);
|
||||
@ -226,7 +222,7 @@ public:
|
||||
PyObject* obj = builtins->attr().try_get(type);
|
||||
if(obj == nullptr){
|
||||
for(auto& t: _all_types) if(t.name == type) return t.obj;
|
||||
throw std::runtime_error("type not found: " + type);
|
||||
throw std::runtime_error(fmt("type not found: ", type));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@ -293,18 +289,18 @@ public:
|
||||
void ZeroDivisionError(){ _error("ZeroDivisionError", "division by zero"); }
|
||||
void IndexError(const Str& msg){ _error("IndexError", msg); }
|
||||
void ValueError(const Str& msg){ _error("ValueError", msg); }
|
||||
void NameError(StrName name){ _error("NameError", "name " + name.str().escape(true) + " is not defined"); }
|
||||
void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); }
|
||||
|
||||
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", fmt("type ", OBJ_NAME(_t(obj)).escape(), " has no attribute ", name.escape()));
|
||||
}
|
||||
|
||||
void AttributeError(Str msg){ _error("AttributeError", msg); }
|
||||
|
||||
void check_type(PyObject* obj, Type type){
|
||||
if(is_type(obj, type)) return;
|
||||
TypeError("expected " + OBJ_NAME(_t(type)).escape(true) + ", but got " + OBJ_NAME(_t(obj)).escape(true));
|
||||
TypeError("expected " + OBJ_NAME(_t(type)).escape() + ", but got " + OBJ_NAME(_t(obj)).escape());
|
||||
}
|
||||
|
||||
PyObject* _t(Type t){
|
||||
@ -317,13 +313,7 @@ public:
|
||||
return _all_types[OBJ_GET(Type, _t(obj->type)).index].obj;
|
||||
}
|
||||
|
||||
~VM() {
|
||||
heap.collect();
|
||||
if(!use_stdio){
|
||||
delete _stdout;
|
||||
delete _stderr;
|
||||
}
|
||||
}
|
||||
~VM() { heap.collect(); }
|
||||
|
||||
CodeObject_ compile(Str source, Str filename, CompileMode mode);
|
||||
PyObject* num_negated(PyObject* obj);
|
||||
@ -363,14 +353,6 @@ inline void CodeObject::optimize(VM* vm){
|
||||
uint32_t base_n = (uint32_t)(names.size() / kLocalsLoadFactor + 0.5);
|
||||
perfect_locals_capacity = find_next_capacity(base_n);
|
||||
perfect_hash_seed = find_perfect_hash_seed(perfect_locals_capacity, names);
|
||||
|
||||
// pre-compute sn in co_consts
|
||||
for(int i=0; i<consts.size(); i++){
|
||||
if(is_type(consts[i], vm->tp_str)){
|
||||
Str& s = OBJ_GET(Str, consts[i]);
|
||||
s._cached_sn_index = StrName::get(s.c_str()).index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEF_NATIVE_2(Str, tp_str)
|
||||
@ -482,6 +464,10 @@ inline PyObject* py_var(VM* vm, std::string val){
|
||||
return VAR(Str(std::move(val)));
|
||||
}
|
||||
|
||||
inline PyObject* py_var(VM* vm, std::string_view val){
|
||||
return VAR(Str(val));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void _check_py_class(VM* vm, PyObject* obj){
|
||||
vm->check_type(obj, T::_type(vm));
|
||||
@ -493,7 +479,7 @@ inline PyObject* VM::num_negated(PyObject* obj){
|
||||
}else if(is_float(obj)){
|
||||
return VAR(-CAST(f64, obj));
|
||||
}
|
||||
TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape(true));
|
||||
TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -503,7 +489,7 @@ inline f64 VM::num_to_float(PyObject* obj){
|
||||
} else if (is_int(obj)){
|
||||
return (f64)CAST(i64, obj);
|
||||
}
|
||||
TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape(true));
|
||||
TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -540,7 +526,7 @@ inline i64 VM::hash(PyObject* obj){
|
||||
f64 val = CAST(f64, obj);
|
||||
return (i64)std::hash<f64>()(val);
|
||||
}
|
||||
TypeError("unhashable type: " + OBJ_NAME(_t(obj)).escape(true));
|
||||
TypeError("unhashable type: " + OBJ_NAME(_t(obj)).escape());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -551,7 +537,7 @@ inline PyObject* VM::asRepr(PyObject* obj){
|
||||
|
||||
inline PyObject* VM::new_module(StrName name) {
|
||||
PyObject* obj = heap._new<DummyModule>(tp_module, DummyModule());
|
||||
obj->attr().set(__name__, VAR(name.str()));
|
||||
obj->attr().set(__name__, VAR(name.sv()));
|
||||
// we do not allow override in order to avoid memory leak
|
||||
// it is because Module objects are not garbage collected
|
||||
if(_modules.contains(name)) UNREACHABLE();
|
||||
@ -571,7 +557,7 @@ inline Str VM::disassemble(CodeObject_ co){
|
||||
jumpTargets.push_back(byte.arg);
|
||||
}
|
||||
}
|
||||
StrStream ss;
|
||||
std::stringstream ss;
|
||||
int prev_line = -1;
|
||||
for(int i=0; i<co->codes.size(); i++){
|
||||
const Bytecode& byte = co->codes[i];
|
||||
@ -594,23 +580,23 @@ inline Str VM::disassemble(CodeObject_ co){
|
||||
std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
|
||||
switch(byte.op){
|
||||
case OP_LOAD_CONST:
|
||||
argStr += " (" + CAST(Str, asRepr(co->consts[byte.arg])) + ")";
|
||||
argStr += fmt(" (", CAST(Str, asRepr(co->consts[byte.arg])), ")");
|
||||
break;
|
||||
case OP_LOAD_NAME: case OP_LOAD_GLOBAL:
|
||||
case OP_STORE_LOCAL: case OP_STORE_GLOBAL:
|
||||
case OP_LOAD_ATTR: case OP_LOAD_METHOD: case OP_STORE_ATTR: case OP_DELETE_ATTR:
|
||||
case OP_IMPORT_NAME: case OP_BEGIN_CLASS:
|
||||
case OP_DELETE_LOCAL: case OP_DELETE_GLOBAL:
|
||||
argStr += " (" + co->names[byte.arg].str() + ")";
|
||||
argStr += fmt(" (", co->names[byte.arg].sv(), ")");
|
||||
break;
|
||||
case OP_BINARY_OP:
|
||||
argStr += " (" + BINARY_SPECIAL_METHODS[byte.arg].str() + ")";
|
||||
argStr += fmt(" (", BINARY_SPECIAL_METHODS[byte.arg], ")");
|
||||
break;
|
||||
case OP_COMPARE_OP:
|
||||
argStr += " (" + COMPARE_SPECIAL_METHODS[byte.arg].str() + ")";
|
||||
argStr += fmt(" (", COMPARE_SPECIAL_METHODS[byte.arg], ")");
|
||||
break;
|
||||
case OP_BITWISE_OP:
|
||||
argStr += " (" + BITWISE_SPECIAL_METHODS[byte.arg].str() + ")";
|
||||
argStr += fmt(" (", BITWISE_SPECIAL_METHODS[byte.arg], ")");
|
||||
break;
|
||||
}
|
||||
ss << pad(argStr, 40); // may overflow
|
||||
@ -619,21 +605,21 @@ inline Str VM::disassemble(CodeObject_ co){
|
||||
}
|
||||
|
||||
#if !DEBUG_DIS_EXEC_MIN
|
||||
StrStream consts;
|
||||
std::stringstream consts;
|
||||
consts << "co_consts: ";
|
||||
consts << CAST(Str, asRepr(VAR(co->consts)));
|
||||
consts << CAST(Str&, asRepr(VAR(co->consts)));
|
||||
|
||||
StrStream names;
|
||||
std::stringstream names;
|
||||
names << "co_names: ";
|
||||
List list;
|
||||
for(int i=0; i<co->names.size(); i++){
|
||||
list.push_back(VAR(co->names[i].str()));
|
||||
list.push_back(VAR(co->names[i].sv()));
|
||||
}
|
||||
names << CAST(Str, asRepr(VAR(list)));
|
||||
ss << '\n' << consts.str() << '\n' << names.str();
|
||||
#endif
|
||||
for(auto& decl: co->func_decls){
|
||||
ss << "\n\n" << "Disassembly of " << decl->name.str() << ":\n";
|
||||
ss << "\n\n" << "Disassembly of " << decl->name << ":\n";
|
||||
ss << disassemble(decl->code);
|
||||
}
|
||||
return Str(ss.str());
|
||||
@ -733,7 +719,7 @@ inline PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, boo
|
||||
locals->set(name, args[i++]);
|
||||
continue;
|
||||
}
|
||||
TypeError("missing positional argument " + name.str().escape(true));
|
||||
TypeError(fmt("missing positional argument ", name.escape()));
|
||||
}
|
||||
|
||||
locals->update(fn.decl->kwargs);
|
||||
@ -756,7 +742,7 @@ inline PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, boo
|
||||
for(int i=0; i<kwargs.size(); i+=2){
|
||||
const Str& key = CAST(Str&, kwargs[i]);
|
||||
if(!fn.decl->kwargs.contains(key)){
|
||||
TypeError(key.escape(true) + " is an invalid keyword argument for " + fn.decl->name.str() + "()");
|
||||
TypeError(fmt(key.escape(), " is an invalid keyword argument for ", fn.decl->name, "()"));
|
||||
}
|
||||
locals->set(key, kwargs[i+1]);
|
||||
}
|
||||
@ -774,7 +760,7 @@ inline PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, boo
|
||||
args.extend_self(self);
|
||||
return call(call_f, std::move(args), kwargs, false);
|
||||
}
|
||||
TypeError(OBJ_NAME(_t(callable)).escape(true) + " object is not callable");
|
||||
TypeError(OBJ_NAME(_t(callable)).escape() + " object is not callable");
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -880,7 +866,7 @@ inline void VM::setattr(PyObject* obj, StrName name, T&& value){
|
||||
if(descr_set != nullptr){
|
||||
call(descr_set, Args{cls_var, obj, std::forward<T>(value)});
|
||||
}else{
|
||||
TypeError("readonly attribute: " + name.str().escape(true));
|
||||
TypeError(fmt("readonly attribute: ", name.escape()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user