mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
some fix
This commit is contained in:
parent
81c4853f04
commit
c2be07b9cc
@ -2,6 +2,6 @@ python prebuild.py
|
|||||||
|
|
||||||
SRC=$(find src/ -name "*.cpp")
|
SRC=$(find src/ -name "*.cpp")
|
||||||
|
|
||||||
FLAGS="-std=c++17 -Og -stdlib=libc++ -Iinclude -frtti -Wfatal-errors -g -DDEBUG"
|
FLAGS="-std=c++17 -O0 -stdlib=libc++ -Iinclude -frtti -Wfatal-errors -g -DDEBUG"
|
||||||
|
|
||||||
clang++ $FLAGS -o main src2/main.cpp $SRC
|
clang++ $FLAGS -o main src2/main.cpp $SRC
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#define PK_DEBUG_MEMORY_POOL 0
|
#define PK_DEBUG_MEMORY_POOL 0
|
||||||
#define PK_DEBUG_NO_AUTO_GC 0
|
#define PK_DEBUG_NO_AUTO_GC 0
|
||||||
#define PK_DEBUG_GC_STATS 0
|
#define PK_DEBUG_GC_STATS 0
|
||||||
|
#define PK_DEBUG_COMPILER 0
|
||||||
|
|
||||||
#ifndef PK_DEBUG_PRECOMPILED_EXEC
|
#ifndef PK_DEBUG_PRECOMPILED_EXEC
|
||||||
#define PK_DEBUG_PRECOMPILED_EXEC 0
|
#define PK_DEBUG_PRECOMPILED_EXEC 0
|
||||||
|
@ -165,7 +165,10 @@ struct vector {
|
|||||||
|
|
||||||
int capacity() const { return _capacity; }
|
int capacity() const { return _capacity; }
|
||||||
|
|
||||||
T& back() { return _data[_size - 1]; }
|
T& back() {
|
||||||
|
assert(_size > 0);
|
||||||
|
return _data[_size - 1];
|
||||||
|
}
|
||||||
|
|
||||||
T* begin() const { return _data; }
|
T* begin() const { return _data; }
|
||||||
|
|
||||||
@ -173,9 +176,15 @@ struct vector {
|
|||||||
|
|
||||||
T* data() const { return _data; }
|
T* data() const { return _data; }
|
||||||
|
|
||||||
T& operator[] (int i) { return _data[i]; }
|
T& operator[] (int i) {
|
||||||
|
assert(i >= 0 && i < _size);
|
||||||
|
return _data[i];
|
||||||
|
}
|
||||||
|
|
||||||
const T& operator[] (int i) const { return _data[i]; }
|
const T& operator[] (int i) const {
|
||||||
|
assert(i >= 0 && i < _size);
|
||||||
|
return _data[i];
|
||||||
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
std::destroy(begin(), end());
|
std::destroy(begin(), end());
|
||||||
|
@ -24,23 +24,33 @@ struct Compiler {
|
|||||||
VM* vm;
|
VM* vm;
|
||||||
bool unknown_global_scope; // for eval/exec() call
|
bool unknown_global_scope; // for eval/exec() call
|
||||||
// for parsing token stream
|
// for parsing token stream
|
||||||
int i = 0;
|
int __i = 0;
|
||||||
|
|
||||||
const Token& tk(int i) const noexcept{ return lexer.nexts[i]; }
|
const Token& tk(int i) const noexcept{ return lexer.nexts[i]; }
|
||||||
const Token& prev() const noexcept{ return tk(i - 1); }
|
const Token& prev() const noexcept{ return tk(__i - 1); }
|
||||||
const Token& curr() const noexcept{ return tk(i); }
|
const Token& curr() const noexcept{ return tk(__i); }
|
||||||
const Token& next() const noexcept{ return tk(i + 1); }
|
const Token& next() const noexcept{ return tk(__i + 1); }
|
||||||
|
|
||||||
const Token& err() const noexcept{
|
const Token& err() const noexcept{
|
||||||
if(i >= lexer.nexts.size()) return prev();
|
if(__i >= lexer.nexts.size()) return prev();
|
||||||
return curr();
|
return curr();
|
||||||
}
|
}
|
||||||
|
|
||||||
void advance(int delta = 1) noexcept{ i += delta; }
|
void advance(int delta = 1) noexcept{
|
||||||
|
__i += delta;
|
||||||
|
#if PK_DEBUG_COMPILER
|
||||||
|
if(__i>=0 && __i<lexer.nexts.size()){
|
||||||
|
printf("%s:%d %s %s\n",
|
||||||
|
lexer.src->filename.c_str(),
|
||||||
|
curr().line,
|
||||||
|
TK_STR(curr().type),
|
||||||
|
curr().str().escape().c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
CodeEmitContext* ctx() noexcept{ return &contexts.back(); }
|
CodeEmitContext* ctx() noexcept{ return &contexts.back(); }
|
||||||
vector<Expr*>& s_expr() noexcept{ return ctx()->s_expr; }
|
|
||||||
|
|
||||||
CompileMode mode() const noexcept{ return lexer.src->mode; }
|
CompileMode mode() const noexcept{ return lexer.src->mode; }
|
||||||
|
|
||||||
NameScope name_scope() const noexcept;
|
NameScope name_scope() const noexcept;
|
||||||
|
@ -60,7 +60,7 @@ struct CodeEmitContext{
|
|||||||
VM* vm;
|
VM* vm;
|
||||||
FuncDecl_ func; // optional
|
FuncDecl_ func; // optional
|
||||||
CodeObject_ co; // 1 CodeEmitContext <=> 1 CodeObject_
|
CodeObject_ co; // 1 CodeEmitContext <=> 1 CodeObject_
|
||||||
vector<Expr*> s_expr;
|
vector<Expr*> _s_expr;
|
||||||
int level;
|
int level;
|
||||||
vector<StrName> global_names;
|
vector<StrName> global_names;
|
||||||
|
|
||||||
@ -75,8 +75,6 @@ struct CodeEmitContext{
|
|||||||
int get_loop() const noexcept;
|
int get_loop() const noexcept;
|
||||||
CodeBlock* enter_block(CodeBlockType type) noexcept;
|
CodeBlock* enter_block(CodeBlockType type) noexcept;
|
||||||
void exit_block() noexcept;
|
void exit_block() noexcept;
|
||||||
void emit_expr(bool emit = true) noexcept; // clear the expression stack and generate bytecode
|
|
||||||
void emit_decorators(int count) noexcept;
|
|
||||||
int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual = false) noexcept;
|
int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual = false) noexcept;
|
||||||
void revert_last_emit_() noexcept;
|
void revert_last_emit_() noexcept;
|
||||||
int emit_int(i64 value, int line) noexcept;
|
int emit_int(i64 value, int line) noexcept;
|
||||||
@ -88,6 +86,59 @@ struct CodeEmitContext{
|
|||||||
int add_func_decl(FuncDecl_ decl) noexcept;
|
int add_func_decl(FuncDecl_ decl) noexcept;
|
||||||
void emit_store_name(NameScope scope, StrName name, int line) noexcept;
|
void emit_store_name(NameScope scope, StrName name, int line) noexcept;
|
||||||
void try_merge_for_iter_store(int) noexcept;
|
void try_merge_for_iter_store(int) noexcept;
|
||||||
|
// emit top -> pop -> delete
|
||||||
|
void s_emit_top() noexcept{
|
||||||
|
s_debug_info("s_emit_top");
|
||||||
|
Expr* e = _s_expr.popx_back();
|
||||||
|
e->emit_(this);
|
||||||
|
delete_expr(e);
|
||||||
|
}
|
||||||
|
// push
|
||||||
|
void s_push(Expr* expr) noexcept{
|
||||||
|
s_debug_info("s_push");
|
||||||
|
_s_expr.push_back(expr);
|
||||||
|
}
|
||||||
|
// top
|
||||||
|
Expr* s_top() noexcept{
|
||||||
|
return _s_expr.back();
|
||||||
|
}
|
||||||
|
// size
|
||||||
|
int s_size() const noexcept{
|
||||||
|
return _s_expr.size();
|
||||||
|
}
|
||||||
|
// pop -> delete
|
||||||
|
void s_pop() noexcept{
|
||||||
|
s_debug_info("s_pop");
|
||||||
|
Expr* e = _s_expr.popx_back();
|
||||||
|
delete_expr(e);
|
||||||
|
}
|
||||||
|
// pop move
|
||||||
|
Expr* s_popx() noexcept{
|
||||||
|
s_debug_info("s_popx");
|
||||||
|
return _s_expr.popx_back();
|
||||||
|
}
|
||||||
|
// clean
|
||||||
|
void s_clean() noexcept{
|
||||||
|
s_debug_info("s_clean");
|
||||||
|
for(Expr* e: _s_expr) delete_expr(e);
|
||||||
|
_s_expr.clear();
|
||||||
|
}
|
||||||
|
// emit decorators
|
||||||
|
void s_emit_decorators(int count) noexcept;
|
||||||
|
// debug stack
|
||||||
|
#if PK_DEBUG_COMPILER
|
||||||
|
void s_debug_info(const char* op) noexcept{
|
||||||
|
SStream ss;
|
||||||
|
for(int i=0; i<s_size(); i++) {
|
||||||
|
Expr* e = _s_expr[i];
|
||||||
|
ss << typeid(*e).name();
|
||||||
|
if(i != s_size() - 1) ss << ", ";
|
||||||
|
}
|
||||||
|
printf("[%s] %s\n", ss.str().c_str(), op);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void s_debug_info(const char*) noexcept{}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NameExpr : Expr {
|
struct NameExpr : Expr {
|
||||||
|
@ -103,6 +103,7 @@ struct Lexer {
|
|||||||
vector<Token> nexts;
|
vector<Token> nexts;
|
||||||
small_vector_2<int, 8> indents;
|
small_vector_2<int, 8> indents;
|
||||||
int brackets_level = 0;
|
int brackets_level = 0;
|
||||||
|
bool used = false;
|
||||||
|
|
||||||
char peekchar() const noexcept { return *curr_char; }
|
char peekchar() const noexcept { return *curr_char; }
|
||||||
|
|
||||||
|
@ -33,14 +33,14 @@ struct Exception {
|
|||||||
PyObject* _self; // weak reference
|
PyObject* _self; // weak reference
|
||||||
|
|
||||||
struct Frame {
|
struct Frame {
|
||||||
SourceData* src; // weak ref
|
std::shared_ptr<SourceData> src; // weak ref
|
||||||
int lineno;
|
int lineno;
|
||||||
const char* cursor;
|
const char* cursor;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
Str snapshot() const { return src->snapshot(lineno, cursor, name); }
|
Str snapshot() const { return src->snapshot(lineno, cursor, name); }
|
||||||
|
|
||||||
Frame(SourceData* src, int lineno, const char* cursor, std::string_view name) :
|
Frame(std::shared_ptr<SourceData> src, int lineno, const char* cursor, std::string_view name) :
|
||||||
src(src), lineno(lineno), cursor(cursor), name(name) {}
|
src(src), lineno(lineno), cursor(cursor), name(name) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ struct TopLevelException : std::exception {
|
|||||||
|
|
||||||
struct Error{
|
struct Error{
|
||||||
const char* type;
|
const char* type;
|
||||||
SourceData* src;
|
std::shared_ptr<SourceData> src;
|
||||||
int lineno;
|
int lineno;
|
||||||
const char* cursor;
|
const char* cursor;
|
||||||
char msg[100];
|
char msg[100];
|
||||||
|
@ -39,13 +39,7 @@ def test_dir(path):
|
|||||||
print('CPython:', str(sys.version).replace('\n', ''))
|
print('CPython:', str(sys.version).replace('\n', ''))
|
||||||
print('System:', '64-bit' if sys.maxsize > 2**32 else '32-bit')
|
print('System:', '64-bit' if sys.maxsize > 2**32 else '32-bit')
|
||||||
|
|
||||||
if len(sys.argv) == 2:
|
def test_repl():
|
||||||
assert 'benchmark' in sys.argv[1]
|
|
||||||
test_dir('benchmarks/')
|
|
||||||
else:
|
|
||||||
test_dir('tests/')
|
|
||||||
|
|
||||||
# test interactive mode
|
|
||||||
print("[REPL Test Enabled]")
|
print("[REPL Test Enabled]")
|
||||||
if sys.platform in ['linux', 'darwin']:
|
if sys.platform in ['linux', 'darwin']:
|
||||||
cmd = './main'
|
cmd = './main'
|
||||||
@ -74,4 +68,13 @@ exit()
|
|||||||
assert 'ans_1: 3' in res.stdout, res.stdout
|
assert 'ans_1: 3' in res.stdout, res.stdout
|
||||||
assert 'ans_2: abc' in res.stdout, res.stdout
|
assert 'ans_2: abc' in res.stdout, res.stdout
|
||||||
|
|
||||||
|
|
||||||
|
if len(sys.argv) == 2:
|
||||||
|
assert 'benchmark' in sys.argv[1]
|
||||||
|
test_dir('benchmarks/')
|
||||||
|
else:
|
||||||
|
test_dir('tests/')
|
||||||
|
# test_repl()
|
||||||
|
|
||||||
|
|
||||||
print("ALL TESTS PASSED")
|
print("ALL TESTS PASSED")
|
||||||
|
@ -391,9 +391,10 @@ StrName StrName::get(std::string_view s) {
|
|||||||
|
|
||||||
Str SStream::str() {
|
Str SStream::str() {
|
||||||
// after this call, the buffer is no longer valid
|
// after this call, the buffer is no longer valid
|
||||||
buffer.reserve(buffer.size() + 1); // allocate one more byte for '\0'
|
buffer.push_back('\0');
|
||||||
buffer[buffer.size()] = '\0'; // set '\0'
|
auto detached = buffer.detach();
|
||||||
return Str(buffer.detach());
|
detached.second--; // remove the last '\0'
|
||||||
|
return Str(detached);
|
||||||
}
|
}
|
||||||
|
|
||||||
SStream& SStream::operator<< (const Str& s) {
|
SStream& SStream::operator<< (const Str& s) {
|
||||||
|
@ -6,7 +6,7 @@ namespace pkpy {
|
|||||||
|
|
||||||
#define consume(expected) if(!match(expected)) return SyntaxError("expected '%s', got '%s'", TK_STR(expected), TK_STR(curr().type));
|
#define consume(expected) if(!match(expected)) return SyntaxError("expected '%s', got '%s'", TK_STR(expected), TK_STR(curr().type));
|
||||||
#define consume_end_stmt() if(!match_end_stmt()) return SyntaxError("expected statement end")
|
#define consume_end_stmt() if(!match_end_stmt()) return SyntaxError("expected statement end")
|
||||||
#define check(B) err = B; if(err) return err
|
#define check(B) if((err = B)) return err
|
||||||
|
|
||||||
PrattRule Compiler::rules[kTokenCount];
|
PrattRule Compiler::rules[kTokenCount];
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ NameScope Compiler::name_scope() const noexcept{
|
|||||||
|
|
||||||
CodeObject_ Compiler::push_global_context() noexcept{
|
CodeObject_ Compiler::push_global_context() noexcept{
|
||||||
CodeObject_ co = std::make_shared<CodeObject>(lexer.src, lexer.src->filename);
|
CodeObject_ co = std::make_shared<CodeObject>(lexer.src, lexer.src->filename);
|
||||||
co->start_line = i == 0 ? 1 : prev().line;
|
co->start_line = __i == 0 ? 1 : prev().line;
|
||||||
contexts.push_back(CodeEmitContext(vm, co, contexts.size()));
|
contexts.push_back(CodeEmitContext(vm, co, contexts.size()));
|
||||||
return co;
|
return co;
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ CodeObject_ Compiler::push_global_context() noexcept{
|
|||||||
FuncDecl_ Compiler::push_f_context(Str name) noexcept{
|
FuncDecl_ Compiler::push_f_context(Str name) noexcept{
|
||||||
FuncDecl_ decl = std::make_shared<FuncDecl>();
|
FuncDecl_ decl = std::make_shared<FuncDecl>();
|
||||||
decl->code = std::make_shared<CodeObject>(lexer.src, name);
|
decl->code = std::make_shared<CodeObject>(lexer.src, name);
|
||||||
decl->code->start_line = i == 0 ? 1 : prev().line;
|
decl->code->start_line = __i == 0 ? 1 : prev().line;
|
||||||
decl->nested = name_scope() == NAME_LOCAL;
|
decl->nested = name_scope() == NAME_LOCAL;
|
||||||
contexts.push_back(CodeEmitContext(vm, decl->code, contexts.size()));
|
contexts.push_back(CodeEmitContext(vm, decl->code, contexts.size()));
|
||||||
contexts.back().func = decl;
|
contexts.back().func = decl;
|
||||||
@ -34,13 +34,13 @@ FuncDecl_ Compiler::push_f_context(Str name) noexcept{
|
|||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::pop_context() noexcept{
|
Error* Compiler::pop_context() noexcept{
|
||||||
assert(s_expr().empty());
|
assert(ctx()->s_size() == 0);
|
||||||
// add a `return None` in the end as a guard
|
// add a `return None` in the end as a guard
|
||||||
// previously, we only do this if the last opcode is not a return
|
// previously, we only do this if the last opcode is not a return
|
||||||
// however, this is buggy...since there may be a jump to the end (out of bound) even if the last opcode is a return
|
// however, this is buggy...since there may be a jump to the end (out of bound) even if the last opcode is a return
|
||||||
ctx()->emit_(OP_RETURN_VALUE, 1, BC_KEEPLINE, true);
|
ctx()->emit_(OP_RETURN_VALUE, 1, BC_KEEPLINE, true);
|
||||||
// find the last valid token
|
// find the last valid token
|
||||||
int j = i - 1;
|
int j = __i - 1;
|
||||||
while(tk(j).type == TK("@eol") || tk(j).type == TK("@dedent") || tk(j).type == TK("@eof"))
|
while(tk(j).type == TK("@eol") || tk(j).type == TK("@dedent") || tk(j).type == TK("@eof"))
|
||||||
j--;
|
j--;
|
||||||
ctx()->co->end_line = tk(j).line;
|
ctx()->co->end_line = tk(j).line;
|
||||||
@ -205,8 +205,8 @@ Error* Compiler::EXPR_TUPLE(bool allow_slice) noexcept{
|
|||||||
} while(match(TK(",")));
|
} while(match(TK(",")));
|
||||||
TupleExpr* e = make_expr<TupleExpr>(count);
|
TupleExpr* e = make_expr<TupleExpr>(count);
|
||||||
for(int i=count-1; i>=0; i--)
|
for(int i=count-1; i>=0; i--)
|
||||||
e->items[i] = s_expr().popx_back();
|
e->items[i] = ctx()->s_popx();
|
||||||
s_expr().push_back(e);
|
ctx()->s_push(e);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,40 +214,40 @@ Error* Compiler::EXPR_VARS() noexcept{
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
do {
|
do {
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
s_expr().push_back(make_expr<NameExpr>(prev().str(), name_scope()));
|
ctx()->s_push(make_expr<NameExpr>(prev().str(), name_scope()));
|
||||||
count += 1;
|
count += 1;
|
||||||
} while(match(TK(",")));
|
} while(match(TK(",")));
|
||||||
if(count > 1){
|
if(count > 1){
|
||||||
TupleExpr* e = make_expr<TupleExpr>(count);
|
TupleExpr* e = make_expr<TupleExpr>(count);
|
||||||
for(int i=count-1; i>=0; i--)
|
for(int i=count-1; i>=0; i--)
|
||||||
e->items[i] = s_expr().popx_back();
|
e->items[i] = ctx()->s_popx();
|
||||||
s_expr().push_back(e);
|
ctx()->s_push(e);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprLiteral() noexcept{
|
Error* Compiler::exprLiteral() noexcept{
|
||||||
s_expr().push_back(make_expr<LiteralExpr>(prev().value));
|
ctx()->s_push(make_expr<LiteralExpr>(prev().value));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprLong() noexcept{
|
Error* Compiler::exprLong() noexcept{
|
||||||
s_expr().push_back(make_expr<LongExpr>(prev().str()));
|
ctx()->s_push(make_expr<LongExpr>(prev().str()));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprImag() noexcept{
|
Error* Compiler::exprImag() noexcept{
|
||||||
s_expr().push_back(make_expr<ImagExpr>(std::get<f64>(prev().value)));
|
ctx()->s_push(make_expr<ImagExpr>(std::get<f64>(prev().value)));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprBytes() noexcept{
|
Error* Compiler::exprBytes() noexcept{
|
||||||
s_expr().push_back(make_expr<BytesExpr>(std::get<Str>(prev().value)));
|
ctx()->s_push(make_expr<BytesExpr>(std::get<Str>(prev().value)));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprFString() noexcept{
|
Error* Compiler::exprFString() noexcept{
|
||||||
s_expr().push_back(make_expr<FStringExpr>(std::get<Str>(prev().value)));
|
ctx()->s_push(make_expr<FStringExpr>(std::get<Str>(prev().value)));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,38 +261,38 @@ Error* Compiler::exprLambda() noexcept{
|
|||||||
}
|
}
|
||||||
// https://github.com/pocketpy/pocketpy/issues/37
|
// https://github.com/pocketpy/pocketpy/issues/37
|
||||||
check(parse_expression(PREC_LAMBDA + 1));
|
check(parse_expression(PREC_LAMBDA + 1));
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||||
check(pop_context());
|
check(pop_context());
|
||||||
LambdaExpr* e = make_expr<LambdaExpr>(decl);
|
LambdaExpr* e = make_expr<LambdaExpr>(decl);
|
||||||
e->line = line;
|
e->line = line;
|
||||||
s_expr().push_back(e);
|
ctx()->s_push(e);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprOr() noexcept{
|
Error* Compiler::exprOr() noexcept{
|
||||||
auto e = make_expr<OrExpr>();
|
auto e = make_expr<OrExpr>();
|
||||||
e->lhs = s_expr().popx_back();
|
e->lhs = ctx()->s_popx();
|
||||||
Error* err = parse_expression(PREC_LOGICAL_OR + 1);
|
Error* err = parse_expression(PREC_LOGICAL_OR + 1);
|
||||||
if(err){
|
if(err){
|
||||||
delete_expr(e);
|
delete_expr(e);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
e->rhs = s_expr().popx_back();
|
e->rhs = ctx()->s_popx();
|
||||||
s_expr().push_back(e);
|
ctx()->s_push(e);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprAnd() noexcept{
|
Error* Compiler::exprAnd() noexcept{
|
||||||
auto e = make_expr<AndExpr>();
|
auto e = make_expr<AndExpr>();
|
||||||
e->lhs = s_expr().popx_back();
|
e->lhs = ctx()->s_popx();
|
||||||
Error* err = parse_expression(PREC_LOGICAL_AND + 1);
|
Error* err = parse_expression(PREC_LOGICAL_AND + 1);
|
||||||
if(err){
|
if(err){
|
||||||
delete_expr(e);
|
delete_expr(e);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
e->rhs = s_expr().popx_back();
|
e->rhs = ctx()->s_popx();
|
||||||
s_expr().push_back(e);
|
ctx()->s_push(e);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,31 +305,31 @@ Error* Compiler::exprTernary() noexcept{
|
|||||||
check(parse_expression(PREC_TERNARY + 1)); // [true_expr, cond, false_expr]
|
check(parse_expression(PREC_TERNARY + 1)); // [true_expr, cond, false_expr]
|
||||||
auto e = make_expr<TernaryExpr>();
|
auto e = make_expr<TernaryExpr>();
|
||||||
e->line = line;
|
e->line = line;
|
||||||
e->false_expr = s_expr().popx_back();
|
e->false_expr = ctx()->s_popx();
|
||||||
e->cond = s_expr().popx_back();
|
e->cond = ctx()->s_popx();
|
||||||
e->true_expr = s_expr().popx_back();
|
e->true_expr = ctx()->s_popx();
|
||||||
s_expr().push_back(e);
|
ctx()->s_push(e);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprBinaryOp() noexcept{
|
Error* Compiler::exprBinaryOp() noexcept{
|
||||||
auto e = make_expr<BinaryExpr>(prev().type);
|
auto e = make_expr<BinaryExpr>(prev().type);
|
||||||
e->lhs = s_expr().popx_back();
|
e->lhs = ctx()->s_popx();
|
||||||
Error* err = parse_expression(rules[e->op].precedence + 1);
|
Error* err = parse_expression(rules[e->op].precedence + 1);
|
||||||
if(err){
|
if(err){
|
||||||
delete_expr(e);
|
delete_expr(e);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
e->rhs = s_expr().popx_back();
|
e->rhs = ctx()->s_popx();
|
||||||
s_expr().push_back(std::move(e));
|
ctx()->s_push(std::move(e));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprNot() noexcept{
|
Error* Compiler::exprNot() noexcept{
|
||||||
Error* err;
|
Error* err;
|
||||||
check(parse_expression(PREC_LOGICAL_NOT + 1));
|
check(parse_expression(PREC_LOGICAL_NOT + 1));
|
||||||
NotExpr* e = make_expr<NotExpr>(s_expr().popx_back());
|
NotExpr* e = make_expr<NotExpr>(ctx()->s_popx());
|
||||||
s_expr().push_back(e);
|
ctx()->s_push(e);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,10 +338,10 @@ Error* Compiler::exprUnaryOp() noexcept{
|
|||||||
TokenIndex op = prev().type;
|
TokenIndex op = prev().type;
|
||||||
check(parse_expression(PREC_UNARY + 1));
|
check(parse_expression(PREC_UNARY + 1));
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case TK("-"): s_expr().push_back(make_expr<NegatedExpr>(s_expr().popx_back())); break;
|
case TK("-"): ctx()->s_push(make_expr<NegatedExpr>(ctx()->s_popx())); break;
|
||||||
case TK("~"): s_expr().push_back(make_expr<InvertExpr>(s_expr().popx_back())); break;
|
case TK("~"): ctx()->s_push(make_expr<InvertExpr>(ctx()->s_popx())); break;
|
||||||
case TK("*"): s_expr().push_back(make_expr<StarredExpr>(s_expr().popx_back(), 1)); break;
|
case TK("*"): ctx()->s_push(make_expr<StarredExpr>(ctx()->s_popx(), 1)); break;
|
||||||
case TK("**"): s_expr().push_back(make_expr<StarredExpr>(s_expr().popx_back(), 2)); break;
|
case TK("**"): ctx()->s_push(make_expr<StarredExpr>(ctx()->s_popx(), 2)); break;
|
||||||
default: assert(false);
|
default: assert(false);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -353,9 +353,9 @@ Error* Compiler::exprGroup() noexcept{
|
|||||||
check(EXPR_TUPLE()); // () is just for change precedence
|
check(EXPR_TUPLE()); // () is just for change precedence
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
consume(TK(")"));
|
consume(TK(")"));
|
||||||
if(s_expr().back()->is_tuple()) return NULL;
|
if(ctx()->s_top()->is_tuple()) return NULL;
|
||||||
Expr* g = make_expr<GroupedExpr>(s_expr().popx_back());
|
Expr* g = make_expr<GroupedExpr>(ctx()->s_popx());
|
||||||
s_expr().push_back(g);
|
ctx()->s_push(g);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,11 +372,11 @@ Error* Compiler::consume_comp(Opcode op0, Opcode op1) noexcept{
|
|||||||
has_cond = true;
|
has_cond = true;
|
||||||
}
|
}
|
||||||
CompExpr* ce = make_expr<CompExpr>(op0, op1);
|
CompExpr* ce = make_expr<CompExpr>(op0, op1);
|
||||||
if(has_cond) ce->cond = s_expr().popx_back();
|
if(has_cond) ce->cond = ctx()->s_popx();
|
||||||
ce->iter = s_expr().popx_back();
|
ce->iter = ctx()->s_popx();
|
||||||
ce->vars = s_expr().popx_back();
|
ce->vars = ctx()->s_popx();
|
||||||
ce->expr = s_expr().popx_back();
|
ce->expr = ctx()->s_popx();
|
||||||
s_expr().push_back(ce);
|
ctx()->s_push(ce);
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -401,8 +401,8 @@ Error* Compiler::exprList() noexcept{
|
|||||||
ListExpr* e = make_expr<ListExpr>(count);
|
ListExpr* e = make_expr<ListExpr>(count);
|
||||||
e->line = line; // override line
|
e->line = line; // override line
|
||||||
for(int i=count-1; i>=0; i--)
|
for(int i=count-1; i>=0; i--)
|
||||||
e->items[i] = s_expr().popx_back();
|
e->items[i] = ctx()->s_popx();
|
||||||
s_expr().push_back(e);
|
ctx()->s_push(e);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,30 +414,31 @@ Error* Compiler::exprMap() noexcept{
|
|||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
if(curr().type == TK("}")) break;
|
if(curr().type == TK("}")) break;
|
||||||
check(EXPR()); // [key]
|
check(EXPR()); // [key]
|
||||||
int star_level = s_expr().back()->star_level();
|
int star_level = ctx()->s_top()->star_level();
|
||||||
if(star_level == 2 || curr().type == TK(":")) { parsing_dict = true; }
|
if(star_level == 2 || curr().type == TK(":")) { parsing_dict = true; }
|
||||||
if(parsing_dict) {
|
if(parsing_dict) {
|
||||||
if(star_level == 2) {
|
if(star_level == 2) {
|
||||||
DictItemExpr* dict_item = make_expr<DictItemExpr>();
|
DictItemExpr* dict_item = make_expr<DictItemExpr>();
|
||||||
dict_item->key = NULL;
|
dict_item->key = NULL;
|
||||||
dict_item->value = s_expr().popx_back();
|
dict_item->value = ctx()->s_popx();
|
||||||
s_expr().push_back(dict_item);
|
ctx()->s_push(dict_item);
|
||||||
} else {
|
} else {
|
||||||
consume(TK(":"));
|
consume(TK(":"));
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
DictItemExpr* dict_item = make_expr<DictItemExpr>();
|
DictItemExpr* dict_item = make_expr<DictItemExpr>();
|
||||||
dict_item->value = s_expr().popx_back();
|
dict_item->value = ctx()->s_popx();
|
||||||
dict_item->key = s_expr().popx_back();
|
dict_item->key = ctx()->s_popx();
|
||||||
s_expr().push_back(dict_item);
|
ctx()->s_push(dict_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
count += 1;
|
count += 1;
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
if(count == 1 && match(TK("for"))) {
|
if(count == 1 && match(TK("for"))) {
|
||||||
if(parsing_dict)
|
if(parsing_dict){
|
||||||
check(consume_comp(OP_BUILD_DICT, OP_DICT_ADD));
|
check(consume_comp(OP_BUILD_DICT, OP_DICT_ADD));
|
||||||
else
|
}else{
|
||||||
check(consume_comp(OP_BUILD_SET, OP_SET_ADD));
|
check(consume_comp(OP_BUILD_SET, OP_SET_ADD));
|
||||||
|
}
|
||||||
consume(TK("}"));
|
consume(TK("}"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -452,16 +453,16 @@ Error* Compiler::exprMap() noexcept{
|
|||||||
se = make_expr<SetExpr>(count);
|
se = make_expr<SetExpr>(count);
|
||||||
}
|
}
|
||||||
for(int i=count-1; i>=0; i--)
|
for(int i=count-1; i>=0; i--)
|
||||||
se->items[i] = s_expr().popx_back();
|
se->items[i] = ctx()->s_popx();
|
||||||
s_expr().push_back(se);
|
ctx()->s_push(se);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprCall() noexcept{
|
Error* Compiler::exprCall() noexcept{
|
||||||
Error* err;
|
Error* err;
|
||||||
CallExpr* e = make_expr<CallExpr>();
|
CallExpr* e = make_expr<CallExpr>();
|
||||||
e->callable = s_expr().popx_back();
|
e->callable = ctx()->s_popx();
|
||||||
s_expr().push_back(e); // push onto the stack in advance
|
ctx()->s_push(e); // push onto the stack in advance
|
||||||
do {
|
do {
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
if(curr().type == TK(")")) break;
|
if(curr().type == TK(")")) break;
|
||||||
@ -470,16 +471,16 @@ Error* Compiler::exprCall() noexcept{
|
|||||||
StrName key(prev().sv());
|
StrName key(prev().sv());
|
||||||
consume(TK("="));
|
consume(TK("="));
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
e->kwargs.push_back({key, s_expr().popx_back()});
|
e->kwargs.push_back({key, ctx()->s_popx()});
|
||||||
} else {
|
} else {
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
if(s_expr().back()->star_level() == 2) {
|
if(ctx()->s_top()->star_level() == 2) {
|
||||||
// **kwargs
|
// **kwargs
|
||||||
e->kwargs.push_back({"**", s_expr().popx_back()});
|
e->kwargs.push_back({"**", ctx()->s_popx()});
|
||||||
} else {
|
} else {
|
||||||
// positional argument
|
// positional argument
|
||||||
if(!e->kwargs.empty()) return SyntaxError("positional argument follows keyword argument");
|
if(!e->kwargs.empty()) return SyntaxError("positional argument follows keyword argument");
|
||||||
e->args.push_back(s_expr().popx_back());
|
e->args.push_back(ctx()->s_popx());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
@ -492,32 +493,32 @@ Error* Compiler::exprName() noexcept{
|
|||||||
StrName name(prev().sv());
|
StrName name(prev().sv());
|
||||||
NameScope scope = name_scope();
|
NameScope scope = name_scope();
|
||||||
if(ctx()->global_names.contains(name)) { scope = NAME_GLOBAL; }
|
if(ctx()->global_names.contains(name)) { scope = NAME_GLOBAL; }
|
||||||
s_expr().push_back(make_expr<NameExpr>(name, scope));
|
ctx()->s_push(make_expr<NameExpr>(name, scope));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprAttrib() noexcept{
|
Error* Compiler::exprAttrib() noexcept{
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
s_expr().push_back(make_expr<AttribExpr>(s_expr().popx_back(), StrName::get(prev().sv())));
|
ctx()->s_push(make_expr<AttribExpr>(ctx()->s_popx(), StrName::get(prev().sv())));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprSlice0() noexcept{
|
Error* Compiler::exprSlice0() noexcept{
|
||||||
Error* err;
|
Error* err;
|
||||||
SliceExpr* slice = make_expr<SliceExpr>();
|
SliceExpr* slice = make_expr<SliceExpr>();
|
||||||
s_expr().push_back(slice); // push onto the stack in advance
|
ctx()->s_push(slice); // push onto the stack in advance
|
||||||
if(is_expression()) { // :<stop>
|
if(is_expression()) { // :<stop>
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
slice->stop = s_expr().popx_back();
|
slice->stop = ctx()->s_popx();
|
||||||
// try optional step
|
// try optional step
|
||||||
if(match(TK(":"))) { // :<stop>:<step>
|
if(match(TK(":"))) { // :<stop>:<step>
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
slice->step = s_expr().popx_back();
|
slice->step = ctx()->s_popx();
|
||||||
}
|
}
|
||||||
} else if(match(TK(":"))) {
|
} else if(match(TK(":"))) {
|
||||||
if(is_expression()) { // ::<step>
|
if(is_expression()) { // ::<step>
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
slice->step = s_expr().popx_back();
|
slice->step = ctx()->s_popx();
|
||||||
} // else ::
|
} // else ::
|
||||||
} // else :
|
} // else :
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -526,38 +527,40 @@ Error* Compiler::exprSlice0() noexcept{
|
|||||||
Error* Compiler::exprSlice1() noexcept{
|
Error* Compiler::exprSlice1() noexcept{
|
||||||
Error* err;
|
Error* err;
|
||||||
SliceExpr* slice = make_expr<SliceExpr>();
|
SliceExpr* slice = make_expr<SliceExpr>();
|
||||||
slice->start = s_expr().popx_back();
|
slice->start = ctx()->s_popx();
|
||||||
s_expr().push_back(slice); // push onto the stack in advance
|
ctx()->s_push(slice); // push onto the stack in advance
|
||||||
if(is_expression()) { // <start>:<stop>
|
if(is_expression()) { // <start>:<stop>
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
slice->stop = s_expr().popx_back();
|
slice->stop = ctx()->s_popx();
|
||||||
// try optional step
|
// try optional step
|
||||||
if(match(TK(":"))) { // <start>:<stop>:<step>
|
if(match(TK(":"))) { // <start>:<stop>:<step>
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
slice->step = s_expr().popx_back();
|
slice->step = ctx()->s_popx();
|
||||||
}
|
}
|
||||||
} else if(match(TK(":"))) { // <start>::<step>
|
} else if(match(TK(":"))) { // <start>::<step>
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
slice->step = s_expr().popx_back();
|
slice->step = ctx()->s_popx();
|
||||||
} // else <start>:
|
} // else <start>:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprSubscr() noexcept{
|
Error* Compiler::exprSubscr() noexcept{
|
||||||
Error* err;
|
Error* err;
|
||||||
SubscrExpr* e = make_expr<SubscrExpr>();
|
int line = prev().line;
|
||||||
s_expr().push_back(e);
|
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
e->lhs = s_expr().popx_back(); // a
|
|
||||||
check(EXPR_TUPLE(true));
|
check(EXPR_TUPLE(true));
|
||||||
e->rhs = s_expr().popx_back(); // a[<expr>]
|
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
consume(TK("]"));
|
consume(TK("]")); // [lhs, rhs]
|
||||||
|
SubscrExpr* e = make_expr<SubscrExpr>();
|
||||||
|
e->line = line;
|
||||||
|
e->rhs = ctx()->s_popx(); // [lhs]
|
||||||
|
e->lhs = ctx()->s_popx(); // []
|
||||||
|
ctx()->s_push(e);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::exprLiteral0() noexcept{
|
Error* Compiler::exprLiteral0() noexcept{
|
||||||
s_expr().push_back(make_expr<Literal0Expr>(prev().type));
|
ctx()->s_push(make_expr<Literal0Expr>(prev().type));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -697,7 +700,7 @@ Error* Compiler::parse_expression(int precedence, bool allow_slice) noexcept{
|
|||||||
Error* Compiler::compile_if_stmt() noexcept{
|
Error* Compiler::compile_if_stmt() noexcept{
|
||||||
Error* err;
|
Error* err;
|
||||||
check(EXPR()); // condition
|
check(EXPR()); // condition
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
int patch = ctx()->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
|
int patch = ctx()->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
|
||||||
err = compile_block_body();
|
err = compile_block_body();
|
||||||
if(err) return err;
|
if(err) return err;
|
||||||
@ -721,7 +724,7 @@ Error* Compiler::compile_while_loop() noexcept{
|
|||||||
Error* err;
|
Error* err;
|
||||||
CodeBlock* block = ctx()->enter_block(CodeBlockType::WHILE_LOOP);
|
CodeBlock* block = ctx()->enter_block(CodeBlockType::WHILE_LOOP);
|
||||||
check(EXPR()); // condition
|
check(EXPR()); // condition
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
int patch = ctx()->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
|
int patch = ctx()->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
|
||||||
check(compile_block_body());
|
check(compile_block_body());
|
||||||
ctx()->emit_(OP_LOOP_CONTINUE, ctx()->get_loop(), BC_KEEPLINE, true);
|
ctx()->emit_(OP_LOOP_CONTINUE, ctx()->get_loop(), BC_KEEPLINE, true);
|
||||||
@ -740,11 +743,11 @@ Error* Compiler::compile_for_loop() noexcept{
|
|||||||
check(EXPR_VARS()); // [vars]
|
check(EXPR_VARS()); // [vars]
|
||||||
consume(TK("in"));
|
consume(TK("in"));
|
||||||
check(EXPR_TUPLE()); // [vars, iter]
|
check(EXPR_TUPLE()); // [vars, iter]
|
||||||
ctx()->emit_expr(); // [vars]
|
ctx()->s_emit_top(); // [vars]
|
||||||
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, BC_KEEPLINE);
|
||||||
CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP);
|
CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP);
|
||||||
int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
|
int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
|
||||||
Expr* vars = s_expr().popx_back();
|
Expr* vars = ctx()->s_popx();
|
||||||
bool ok = vars->emit_store(ctx());
|
bool ok = vars->emit_store(ctx());
|
||||||
delete_expr(vars);
|
delete_expr(vars);
|
||||||
if(!ok) return SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
|
if(!ok) return SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
|
||||||
@ -776,7 +779,7 @@ Error* Compiler::compile_try_except() noexcept{
|
|||||||
consume(TK("except"));
|
consume(TK("except"));
|
||||||
if(is_expression()) {
|
if(is_expression()) {
|
||||||
check(EXPR()); // push assumed type on to the stack
|
check(EXPR()); // push assumed type on to the stack
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
ctx()->emit_(OP_EXCEPTION_MATCH, BC_NOARG, prev().line);
|
ctx()->emit_(OP_EXCEPTION_MATCH, BC_NOARG, prev().line);
|
||||||
if(match(TK("as"))) {
|
if(match(TK("as"))) {
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
@ -836,10 +839,6 @@ Error* Compiler::compile_decorated() noexcept{
|
|||||||
if(!match_newlines_repl()) return SyntaxError();
|
if(!match_newlines_repl()) return SyntaxError();
|
||||||
} while(match(TK("@")));
|
} while(match(TK("@")));
|
||||||
|
|
||||||
array<Expr*> decorators(count);
|
|
||||||
for(int i = count - 1; i >= 0; i--)
|
|
||||||
decorators[i] = s_expr().popx_back();
|
|
||||||
|
|
||||||
if(match(TK("class"))) {
|
if(match(TK("class"))) {
|
||||||
check(compile_class(count));
|
check(compile_class(count));
|
||||||
} else {
|
} else {
|
||||||
@ -863,7 +862,7 @@ Error* Compiler::try_compile_assignment(bool* is_assign) noexcept{
|
|||||||
case TK("&="):
|
case TK("&="):
|
||||||
case TK("|="):
|
case TK("|="):
|
||||||
case TK("^="): {
|
case TK("^="): {
|
||||||
Expr* lhs_p = s_expr().back();
|
Expr* lhs_p = ctx()->s_top();
|
||||||
if(lhs_p->is_starred()) return SyntaxError();
|
if(lhs_p->is_starred()) return SyntaxError();
|
||||||
if(ctx()->is_compiling_class){
|
if(ctx()->is_compiling_class){
|
||||||
return SyntaxError("can't use inplace operator in class definition");
|
return SyntaxError("can't use inplace operator in class definition");
|
||||||
@ -873,14 +872,15 @@ Error* Compiler::try_compile_assignment(bool* is_assign) noexcept{
|
|||||||
// a.x += 1; a should be evaluated only once
|
// a.x += 1; a should be evaluated only once
|
||||||
// -1 to remove =; inplace=true
|
// -1 to remove =; inplace=true
|
||||||
auto e = make_expr<BinaryExpr>(prev().type - 1, true);
|
auto e = make_expr<BinaryExpr>(prev().type - 1, true);
|
||||||
e->lhs = s_expr().popx_back();
|
e->lhs = ctx()->s_popx();
|
||||||
check(EXPR_TUPLE());
|
check(EXPR_TUPLE());
|
||||||
e->rhs = s_expr().popx_back();
|
e->rhs = ctx()->s_popx();
|
||||||
if(e->rhs->is_starred()) return SyntaxError();
|
if(e->rhs->is_starred()) return SyntaxError();
|
||||||
e->emit_(ctx());
|
e->emit_(ctx());
|
||||||
bool ok = lhs_p->emit_store_inplace(ctx());
|
bool ok = lhs_p->emit_store_inplace(ctx());
|
||||||
if(!ok) return SyntaxError();
|
if(!ok) return SyntaxError();
|
||||||
*is_assign = true;
|
*is_assign = true;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
case TK("="): {
|
case TK("="): {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
@ -889,16 +889,17 @@ Error* Compiler::try_compile_assignment(bool* is_assign) noexcept{
|
|||||||
n += 1;
|
n += 1;
|
||||||
}
|
}
|
||||||
// stack size is n+1
|
// stack size is n+1
|
||||||
ctx()->emit_expr(); // emit and pop
|
ctx()->s_emit_top(); // emit and pop
|
||||||
for(int j = 1; j < n; j++)
|
for(int j = 1; j < n; j++)
|
||||||
ctx()->emit_(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
for(int j = 0; j < n; j++) {
|
for(int j = 0; j < n; j++) {
|
||||||
auto e = s_expr().popx_back();
|
auto e = ctx()->s_popx();
|
||||||
if(e->is_starred()) return SyntaxError();
|
if(e->is_starred()) return SyntaxError();
|
||||||
bool ok = e->emit_store(ctx());
|
bool ok = e->emit_store(ctx());
|
||||||
if(!ok) return SyntaxError();
|
if(!ok) return SyntaxError();
|
||||||
}
|
}
|
||||||
*is_assign = true;
|
*is_assign = true;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
default: *is_assign = false;
|
default: *is_assign = false;
|
||||||
}
|
}
|
||||||
@ -928,14 +929,14 @@ Error* Compiler::compile_stmt() noexcept{
|
|||||||
case TK("yield"):
|
case TK("yield"):
|
||||||
if(contexts.size() <= 1) return SyntaxError("'yield' outside function");
|
if(contexts.size() <= 1) return SyntaxError("'yield' outside function");
|
||||||
check(EXPR_TUPLE());
|
check(EXPR_TUPLE());
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line);
|
ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK("yield from"):
|
case TK("yield from"):
|
||||||
if(contexts.size() <= 1) return SyntaxError("'yield from' outside function");
|
if(contexts.size() <= 1) return SyntaxError("'yield from' outside function");
|
||||||
check(EXPR_TUPLE());
|
check(EXPR_TUPLE());
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
|
|
||||||
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, kw_line);
|
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, kw_line);
|
||||||
ctx()->enter_block(CodeBlockType::FOR_LOOP);
|
ctx()->enter_block(CodeBlockType::FOR_LOOP);
|
||||||
@ -950,7 +951,7 @@ Error* Compiler::compile_stmt() noexcept{
|
|||||||
ctx()->emit_(OP_RETURN_VALUE, 1, kw_line);
|
ctx()->emit_(OP_RETURN_VALUE, 1, kw_line);
|
||||||
} else {
|
} else {
|
||||||
check(EXPR_TUPLE());
|
check(EXPR_TUPLE());
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, kw_line);
|
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, kw_line);
|
||||||
}
|
}
|
||||||
@ -968,12 +969,12 @@ Error* Compiler::compile_stmt() noexcept{
|
|||||||
/*************************************************/
|
/*************************************************/
|
||||||
case TK("assert"): {
|
case TK("assert"): {
|
||||||
check(EXPR()); // condition
|
check(EXPR()); // condition
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
int index = ctx()->emit_(OP_POP_JUMP_IF_TRUE, BC_NOARG, kw_line);
|
int index = ctx()->emit_(OP_POP_JUMP_IF_TRUE, BC_NOARG, kw_line);
|
||||||
int has_msg = 0;
|
int has_msg = 0;
|
||||||
if(match(TK(","))) {
|
if(match(TK(","))) {
|
||||||
check(EXPR()); // message
|
check(EXPR()); // message
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
has_msg = 1;
|
has_msg = 1;
|
||||||
}
|
}
|
||||||
ctx()->emit_(OP_RAISE_ASSERT, has_msg, kw_line);
|
ctx()->emit_(OP_RAISE_ASSERT, has_msg, kw_line);
|
||||||
@ -990,19 +991,19 @@ Error* Compiler::compile_stmt() noexcept{
|
|||||||
break;
|
break;
|
||||||
case TK("raise"): {
|
case TK("raise"): {
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
ctx()->emit_(OP_RAISE, BC_NOARG, kw_line);
|
ctx()->emit_(OP_RAISE, BC_NOARG, kw_line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
} break;
|
} break;
|
||||||
case TK("del"): {
|
case TK("del"): {
|
||||||
check(EXPR_TUPLE());
|
check(EXPR_TUPLE());
|
||||||
Expr* e = s_expr().popx_back();
|
Expr* e = ctx()->s_popx();
|
||||||
if(!e->emit_del(ctx())) return SyntaxError();
|
if(!e->emit_del(ctx())) return SyntaxError();
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
} break;
|
} break;
|
||||||
case TK("with"): {
|
case TK("with"): {
|
||||||
check(EXPR()); // [ <expr> ]
|
check(EXPR()); // [ <expr> ]
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
ctx()->enter_block(CodeBlockType::CONTEXT_MANAGER);
|
ctx()->enter_block(CodeBlockType::CONTEXT_MANAGER);
|
||||||
Expr* as_name = nullptr;
|
Expr* as_name = nullptr;
|
||||||
if(match(TK("as"))) {
|
if(match(TK("as"))) {
|
||||||
@ -1045,13 +1046,13 @@ Error* Compiler::compile_stmt() noexcept{
|
|||||||
|
|
||||||
bool is_typed_name = false; // e.g. x: int
|
bool is_typed_name = false; // e.g. x: int
|
||||||
// eat variable's type hint if it is a single name
|
// eat variable's type hint if it is a single name
|
||||||
if(s_expr().back()->is_name()) {
|
if(ctx()->s_top()->is_name()) {
|
||||||
if(match(TK(":"))) {
|
if(match(TK(":"))) {
|
||||||
check(consume_type_hints());
|
check(consume_type_hints());
|
||||||
is_typed_name = true;
|
is_typed_name = true;
|
||||||
|
|
||||||
if(ctx()->is_compiling_class) {
|
if(ctx()->is_compiling_class) {
|
||||||
NameExpr* ne = static_cast<NameExpr*>(s_expr().back());
|
NameExpr* ne = static_cast<NameExpr*>(ctx()->s_top());
|
||||||
ctx()->emit_(OP_ADD_CLASS_ANNOTATION, ne->name.index, BC_KEEPLINE);
|
ctx()->emit_(OP_ADD_CLASS_ANNOTATION, ne->name.index, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1059,18 +1060,18 @@ Error* Compiler::compile_stmt() noexcept{
|
|||||||
bool is_assign = false;
|
bool is_assign = false;
|
||||||
check(try_compile_assignment(&is_assign));
|
check(try_compile_assignment(&is_assign));
|
||||||
if(!is_assign) {
|
if(!is_assign) {
|
||||||
if(!s_expr().empty() && s_expr().back()->is_starred()) {
|
if(ctx()->s_size() > 0 && ctx()->s_top()->is_starred()) {
|
||||||
return SyntaxError();
|
return SyntaxError();
|
||||||
}
|
}
|
||||||
if(!is_typed_name) {
|
if(!is_typed_name) {
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
if((mode() == CELL_MODE || mode() == REPL_MODE) && name_scope() == NAME_GLOBAL) {
|
if((mode() == CELL_MODE || mode() == REPL_MODE) && name_scope() == NAME_GLOBAL) {
|
||||||
ctx()->emit_(OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE);
|
||||||
} else {
|
} else {
|
||||||
ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx()->emit_expr(false);
|
ctx()->s_pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
@ -1083,7 +1084,7 @@ Error* Compiler::compile_stmt() noexcept{
|
|||||||
Error* Compiler::consume_type_hints() noexcept{
|
Error* Compiler::consume_type_hints() noexcept{
|
||||||
Error* err;
|
Error* err;
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
Expr* e = s_expr().popx_back();
|
Expr* e = ctx()->s_popx();
|
||||||
delete_expr(e);
|
delete_expr(e);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1096,7 +1097,7 @@ Error* Compiler::compile_class(int decorators) noexcept{
|
|||||||
if(match(TK("("))) {
|
if(match(TK("("))) {
|
||||||
if(is_expression()) {
|
if(is_expression()) {
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
base = s_expr().popx_back();
|
base = ctx()->s_popx();
|
||||||
}
|
}
|
||||||
consume(TK(")"));
|
consume(TK(")"));
|
||||||
}
|
}
|
||||||
@ -1114,10 +1115,9 @@ Error* Compiler::compile_class(int decorators) noexcept{
|
|||||||
check(compile_block_body());
|
check(compile_block_body());
|
||||||
ctx()->is_compiling_class = false;
|
ctx()->is_compiling_class = false;
|
||||||
|
|
||||||
assert(s_expr().size() == decorators);
|
|
||||||
if(decorators > 0) {
|
if(decorators > 0) {
|
||||||
ctx()->emit_(OP_BEGIN_CLASS_DECORATION, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_BEGIN_CLASS_DECORATION, BC_NOARG, BC_KEEPLINE);
|
||||||
ctx()->emit_decorators(decorators);
|
ctx()->s_emit_decorators(decorators);
|
||||||
ctx()->emit_(OP_END_CLASS_DECORATION, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_END_CLASS_DECORATION, BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1209,8 +1209,7 @@ Error* Compiler::compile_function(int decorators) noexcept{
|
|||||||
}
|
}
|
||||||
ctx()->emit_(OP_LOAD_FUNCTION, ctx()->add_func_decl(decl), prev().line);
|
ctx()->emit_(OP_LOAD_FUNCTION, ctx()->add_func_decl(decl), prev().line);
|
||||||
|
|
||||||
assert(s_expr().size() == decorators);
|
ctx()->s_emit_decorators(decorators);
|
||||||
ctx()->emit_decorators(decorators);
|
|
||||||
|
|
||||||
if(!ctx()->is_compiling_class) {
|
if(!ctx()->is_compiling_class) {
|
||||||
auto e = make_expr<NameExpr>(decl_name, name_scope());
|
auto e = make_expr<NameExpr>(decl_name, name_scope());
|
||||||
@ -1273,11 +1272,15 @@ Compiler::Compiler(VM* vm, std::string_view source, const Str& filename, Compile
|
|||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::compile(CodeObject_* out) noexcept{
|
Error* Compiler::compile(CodeObject_* out) noexcept{
|
||||||
assert(i == 0); // make sure it is the first time to compile
|
assert(__i == 0); // make sure it is the first time to compile
|
||||||
|
|
||||||
Error* err;
|
Error* err;
|
||||||
check(lexer.run());
|
check(lexer.run());
|
||||||
|
|
||||||
|
// for(int i=0; i<lexer.nexts.size(); i++){
|
||||||
|
// printf("%s: %s\n", TK_STR(tk(i).type), tk(i).str().escape().c_str());
|
||||||
|
// }
|
||||||
|
|
||||||
CodeObject_ code = push_global_context();
|
CodeObject_ code = push_global_context();
|
||||||
|
|
||||||
advance(); // skip @sof, so prev() is always valid
|
advance(); // skip @sof, so prev() is always valid
|
||||||
@ -1285,7 +1288,7 @@ Error* Compiler::compile(CodeObject_* out) noexcept{
|
|||||||
|
|
||||||
if(mode() == EVAL_MODE) {
|
if(mode() == EVAL_MODE) {
|
||||||
check(EXPR_TUPLE());
|
check(EXPR_TUPLE());
|
||||||
ctx()->emit_expr();
|
ctx()->s_emit_top();
|
||||||
consume(TK("@eof"));
|
consume(TK("@eof"));
|
||||||
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||||
check(pop_context());
|
check(pop_context());
|
||||||
@ -1293,7 +1296,7 @@ Error* Compiler::compile(CodeObject_* out) noexcept{
|
|||||||
return NULL;
|
return NULL;
|
||||||
} else if(mode() == JSON_MODE) {
|
} else if(mode() == JSON_MODE) {
|
||||||
check(EXPR());
|
check(EXPR());
|
||||||
Expr* e = s_expr().popx_back();
|
Expr* e = ctx()->s_popx();
|
||||||
if(!e->is_json_object()) return SyntaxError("expect a JSON object, literal or array");
|
if(!e->is_json_object()) return SyntaxError("expect a JSON object, literal or array");
|
||||||
consume(TK("@eof"));
|
consume(TK("@eof"));
|
||||||
e->emit_(ctx());
|
e->emit_(ctx());
|
||||||
@ -1314,7 +1317,7 @@ Error* Compiler::compile(CodeObject_* out) noexcept{
|
|||||||
|
|
||||||
Compiler::~Compiler(){
|
Compiler::~Compiler(){
|
||||||
for(CodeEmitContext& ctx: contexts){
|
for(CodeEmitContext& ctx: contexts){
|
||||||
for(Expr* e: ctx.s_expr) delete_expr(e);
|
ctx.s_clean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,18 +40,11 @@ void CodeEmitContext::exit_block() noexcept{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the expression stack and generate bytecode
|
void CodeEmitContext::s_emit_decorators(int count) noexcept{
|
||||||
void CodeEmitContext::emit_expr(bool emit) noexcept{
|
assert(s_size() >= count);
|
||||||
// assert(s_expr.size() == 1);
|
|
||||||
Expr* e = s_expr.popx_back();
|
|
||||||
if(emit) e->emit_(this);
|
|
||||||
delete_expr(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeEmitContext::emit_decorators(int count) noexcept{
|
|
||||||
// [obj]
|
// [obj]
|
||||||
for(int i=0; i<count; i++) {
|
for(int i=0; i<count; i++) {
|
||||||
Expr* deco = s_expr.popx_back();
|
Expr* deco = s_popx();
|
||||||
deco->emit_(this); // [obj, f]
|
deco->emit_(this); // [obj, f]
|
||||||
emit_(OP_ROT_TWO, BC_NOARG, deco->line); // [f, obj]
|
emit_(OP_ROT_TWO, BC_NOARG, deco->line); // [f, obj]
|
||||||
emit_(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE); // [f, obj, NULL]
|
emit_(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE); // [f, obj, NULL]
|
||||||
|
@ -501,7 +501,7 @@ Error* Lexer::lex_one_token(bool* eof) noexcept{
|
|||||||
Error* Lexer::_error(bool lexer_err, const char* type, const char* msg, va_list args, i64 userdata) noexcept{
|
Error* Lexer::_error(bool lexer_err, const char* type, const char* msg, va_list args, i64 userdata) noexcept{
|
||||||
PK_THREAD_LOCAL Error err;
|
PK_THREAD_LOCAL Error err;
|
||||||
err.type = type;
|
err.type = type;
|
||||||
err.src = src.get();
|
err.src = src;
|
||||||
if(lexer_err){
|
if(lexer_err){
|
||||||
err.lineno = current_line;
|
err.lineno = current_line;
|
||||||
err.cursor = curr_char;
|
err.cursor = curr_char;
|
||||||
@ -529,16 +529,19 @@ Error* Lexer::SyntaxError(const char* fmt, ...) noexcept{
|
|||||||
Lexer::Lexer(VM* vm, std::shared_ptr<SourceData> src) noexcept : vm(vm), src(src){
|
Lexer::Lexer(VM* vm, std::shared_ptr<SourceData> src) noexcept : vm(vm), src(src){
|
||||||
this->token_start = src->source.c_str();
|
this->token_start = src->source.c_str();
|
||||||
this->curr_char = src->source.c_str();
|
this->curr_char = src->source.c_str();
|
||||||
this->nexts.push_back(Token{TK("@sof"), token_start, 0, current_line, brackets_level, {}});
|
|
||||||
this->indents.push_back(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Lexer::run() noexcept{
|
Error* Lexer::run() noexcept{
|
||||||
|
assert(!this->used);
|
||||||
|
this->used = true;
|
||||||
if(src->is_precompiled) {
|
if(src->is_precompiled) {
|
||||||
from_precompiled();
|
from_precompiled();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
assert(curr_char == src->source.c_str());
|
// push initial tokens
|
||||||
|
this->nexts.push_back(Token{TK("@sof"), token_start, 0, current_line, brackets_level, {}});
|
||||||
|
this->indents.push_back(0);
|
||||||
|
|
||||||
bool eof = false;
|
bool eof = false;
|
||||||
while(!eof) {
|
while(!eof) {
|
||||||
Error* err = lex_one_token(&eof);
|
Error* err = lex_one_token(&eof);
|
||||||
|
@ -182,7 +182,9 @@ PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject
|
|||||||
#endif
|
#endif
|
||||||
CodeObject_ code = compile(source, filename, mode);
|
CodeObject_ code = compile(source, filename, mode);
|
||||||
return _exec(code, _module);
|
return _exec(code, _module);
|
||||||
} catch(TopLevelException e) { stderr_write(e.summary() + "\n"); } catch(const std::exception& e) {
|
} catch(TopLevelException e) {
|
||||||
|
stderr_write(e.summary() + "\n");
|
||||||
|
} catch(const std::exception& e) {
|
||||||
Str msg = "An std::exception occurred! It could be a bug.\n";
|
Str msg = "An std::exception occurred! It could be a bug.\n";
|
||||||
msg = msg + e.what() + "\n";
|
msg = msg + e.what() + "\n";
|
||||||
stderr_write(msg);
|
stderr_write(msg);
|
||||||
@ -1374,12 +1376,13 @@ PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn, any userdata,
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn, any userdata, BindType bt) {
|
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn, any userdata, BindType bt) {
|
||||||
CodeObject_ co;
|
char buffer[256];
|
||||||
try {
|
int length = snprintf(buffer, sizeof(buffer), "def %s : pass", sig);
|
||||||
// fn(a, b, *c, d=1) -> None
|
std::string_view source(buffer, length);
|
||||||
co = compile(_S("def ", sig, " : pass"), "<bind>", EXEC_MODE);
|
// fn(a, b, *c, d=1) -> None
|
||||||
} catch(TopLevelException) { throw std::runtime_error("invalid signature: " + std::string(sig)); }
|
CodeObject_ co = compile(source, "<bind>", EXEC_MODE);
|
||||||
if(co->func_decls.size() != 1) { throw std::runtime_error("expected 1 function declaration"); }
|
assert(co->func_decls.size() == 1);
|
||||||
|
|
||||||
FuncDecl_ decl = co->func_decls[0];
|
FuncDecl_ decl = co->func_decls[0];
|
||||||
decl->docstring = docstring;
|
decl->docstring = docstring;
|
||||||
PyObject* f_obj = heap.gcnew<NativeFunc>(tp_native_func, fn, decl, std::move(userdata));
|
PyObject* f_obj = heap.gcnew<NativeFunc>(tp_native_func, fn, decl, std::move(userdata));
|
||||||
@ -1455,7 +1458,7 @@ void VM::__raise_exc(bool re_raise) {
|
|||||||
int current_line = frame->co->lines[actual_ip].lineno; // current line
|
int current_line = frame->co->lines[actual_ip].lineno; // current line
|
||||||
auto current_f_name = frame->co->name.sv(); // current function name
|
auto current_f_name = frame->co->name.sv(); // current function name
|
||||||
if(frame->_callable == nullptr) current_f_name = ""; // not in a function
|
if(frame->_callable == nullptr) current_f_name = ""; // not in a function
|
||||||
e.st_push(frame->co->src.get(), current_line, nullptr, current_f_name);
|
e.st_push(frame->co->src, current_line, nullptr, current_f_name);
|
||||||
|
|
||||||
if(next_ip >= 0) {
|
if(next_ip >= 0) {
|
||||||
throw InternalException(InternalExceptionType::Handled, next_ip);
|
throw InternalException(InternalExceptionType::Handled, next_ip);
|
||||||
|
@ -39,3 +39,42 @@ def fib(n):
|
|||||||
return fib(n-1) + fib(n-2)
|
return fib(n-1) + fib(n-2)
|
||||||
|
|
||||||
assert fib(32) == 2178309
|
assert fib(32) == 2178309
|
||||||
|
|
||||||
|
def wrapped(cls):
|
||||||
|
return int
|
||||||
|
|
||||||
|
@wrapped
|
||||||
|
@wrapped
|
||||||
|
@wrapped
|
||||||
|
@wrapped
|
||||||
|
class A:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert A('123') == 123
|
||||||
|
|
||||||
|
# validate the decorator order
|
||||||
|
res = []
|
||||||
|
|
||||||
|
def w(x):
|
||||||
|
res.append('w')
|
||||||
|
return x
|
||||||
|
|
||||||
|
def w1(x):
|
||||||
|
res.append('w1')
|
||||||
|
return x
|
||||||
|
|
||||||
|
def w2(x):
|
||||||
|
res.append('w2')
|
||||||
|
return x
|
||||||
|
|
||||||
|
@w
|
||||||
|
@w1
|
||||||
|
@w2
|
||||||
|
def f():
|
||||||
|
pass
|
||||||
|
|
||||||
|
f()
|
||||||
|
assert res == ['w2', 'w1', 'w']
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,15 +15,3 @@ assert asdict(A(1, '555')) == {'x': 1, 'y': '555'}
|
|||||||
assert A(1, 'N') == A(1, 'N')
|
assert A(1, 'N') == A(1, 'N')
|
||||||
assert A(1, 'N') != A(1, 'M')
|
assert A(1, 'N') != A(1, 'M')
|
||||||
|
|
||||||
def wrapped(cls):
|
|
||||||
return int
|
|
||||||
|
|
||||||
@wrapped
|
|
||||||
@wrapped
|
|
||||||
@wrapped
|
|
||||||
@wrapped
|
|
||||||
class A:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
assert A('123') == 123
|
|
||||||
|
@ -1,2 +1,5 @@
|
|||||||
|
assert eval("1+2") == 3
|
||||||
|
|
||||||
code = compile("1+2", "<eval>", "eval")
|
code = compile("1+2", "<eval>", "eval")
|
||||||
|
# print(code)
|
||||||
assert eval(code) == 3
|
assert eval(code) == 3
|
||||||
|
Loading…
x
Reference in New Issue
Block a user