mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-22 12:30:19 +00:00
up
This commit is contained in:
parent
449fb9a2f8
commit
d54cd84138
@ -8,7 +8,7 @@ with open("src/opcodes.h", "rt", encoding='utf-8') as f:
|
|||||||
pipeline = [
|
pipeline = [
|
||||||
["common.h", "memory.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
|
["common.h", "memory.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
|
||||||
["obj.h", "codeobject.h", "frame.h"],
|
["obj.h", "codeobject.h", "frame.h"],
|
||||||
["gc.h", "vm.h", "ref.h", "ceval.h", "compiler.h", "repl.h"],
|
["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"],
|
||||||
["iter.h", "cffi.h", "io.h", "_generated.h", "pocketpy.h"]
|
["iter.h", "cffi.h", "io.h", "_generated.h", "pocketpy.h"]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include "ref.h"
|
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
@ -135,10 +134,11 @@ inline PyObject* VM::run_frame(Frame* frame){
|
|||||||
PyObject* cls = frame->top();
|
PyObject* cls = frame->top();
|
||||||
cls->attr().set(name.first, std::move(obj));
|
cls->attr().set(name.first, std::move(obj));
|
||||||
} continue;
|
} continue;
|
||||||
case OP_RETURN_VALUE: return frame->pop_value(this);
|
case OP_RETURN_VALUE: return frame->popx();
|
||||||
case OP_PRINT_EXPR: {
|
case OP_PRINT_EXPR: {
|
||||||
PyObject* expr = frame->top_value(this);
|
PyObject* expr = frame->top(); // use top() here to avoid accidental gc
|
||||||
if(expr != None) *_stdout << CAST(Str, asRepr(expr)) << '\n';
|
if(expr != None) *_stdout << CAST(Str, asRepr(expr)) << '\n';
|
||||||
|
frame->pop();
|
||||||
} continue;
|
} continue;
|
||||||
case OP_POP_TOP: frame->_pop(); continue;
|
case OP_POP_TOP: frame->_pop(); continue;
|
||||||
case OP_BINARY_OP: {
|
case OP_BINARY_OP: {
|
||||||
@ -239,7 +239,7 @@ inline PyObject* VM::run_frame(Frame* frame){
|
|||||||
PyObject* obj = frame->pop_value(this);
|
PyObject* obj = frame->pop_value(this);
|
||||||
call(frame->top_1(), "add", Args{obj});
|
call(frame->top_1(), "add", Args{obj});
|
||||||
} continue;
|
} continue;
|
||||||
case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue;
|
case OP_DUP_TOP: frame->push(frame->top()); continue;
|
||||||
case OP_UNARY_STAR: {
|
case OP_UNARY_STAR: {
|
||||||
if(byte.arg > 0){ // rvalue
|
if(byte.arg > 0){ // rvalue
|
||||||
frame->top() = VAR(StarWrapper(frame->top_value(this), true));
|
frame->top() = VAR(StarWrapper(frame->top_value(this), true));
|
||||||
|
@ -5,12 +5,7 @@
|
|||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
enum NameScope {
|
enum NameScope { NAME_LOCAL, NAME_GLOBAL };
|
||||||
NAME_LOCAL = 0,
|
|
||||||
NAME_GLOBAL,
|
|
||||||
NAME_ATTR,
|
|
||||||
NAME_SPECIAL,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Opcode {
|
enum Opcode {
|
||||||
#define OPCODE(name) OP_##name,
|
#define OPCODE(name) OP_##name,
|
||||||
|
197
src/compiler.h
197
src/compiler.h
@ -24,10 +24,18 @@ class Compiler {
|
|||||||
std::unique_ptr<Lexer> lexer;
|
std::unique_ptr<Lexer> lexer;
|
||||||
stack<CodeEmitContext> contexts;
|
stack<CodeEmitContext> contexts;
|
||||||
std::map<TokenIndex, PrattRule> rules;
|
std::map<TokenIndex, PrattRule> rules;
|
||||||
bool used = false;
|
|
||||||
VM* vm;
|
VM* vm;
|
||||||
|
bool used;
|
||||||
|
// for parsing token stream
|
||||||
|
int i = 0;
|
||||||
|
std::vector<Token> tokens;
|
||||||
|
|
||||||
|
const Token& prev() { return tokens.at(i-1); }
|
||||||
|
const Token& curr() { return tokens.at(i); }
|
||||||
|
const Token& next() { return tokens.at(i+1); }
|
||||||
|
const Token& peek(int offset) { return tokens.at(i+offset); }
|
||||||
|
void advance() { i++; }
|
||||||
|
|
||||||
CodeObject* co() const{ return contexts.top().co.get(); }
|
|
||||||
CodeEmitContext* ctx() { return &contexts.top(); }
|
CodeEmitContext* ctx() { return &contexts.top(); }
|
||||||
CompileMode mode() const{ return lexer->src->mode; }
|
CompileMode mode() const{ return lexer->src->mode; }
|
||||||
NameScope name_scope() const { return contexts.size()>1 ? NAME_LOCAL : NAME_GLOBAL; }
|
NameScope name_scope() const { return contexts.size()>1 ? NAME_LOCAL : NAME_GLOBAL; }
|
||||||
@ -41,6 +49,7 @@ class Compiler {
|
|||||||
|
|
||||||
void pop_context(){
|
void pop_context(){
|
||||||
if(!ctx()->s_expr.empty()) UNREACHABLE();
|
if(!ctx()->s_expr.empty()) UNREACHABLE();
|
||||||
|
// if last instruction is not return, add a default return None
|
||||||
if(ctx()->co->codes.back().op != OP_RETURN_VALUE){
|
if(ctx()->co->codes.back().op != OP_RETURN_VALUE){
|
||||||
ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
|
||||||
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||||
@ -52,6 +61,7 @@ class Compiler {
|
|||||||
public:
|
public:
|
||||||
Compiler(VM* vm, const char* source, Str filename, CompileMode mode){
|
Compiler(VM* vm, const char* source, Str filename, CompileMode mode){
|
||||||
this->vm = vm;
|
this->vm = vm;
|
||||||
|
this->used = false;
|
||||||
this->lexer = std::make_unique<Lexer>(
|
this->lexer = std::make_unique<Lexer>(
|
||||||
make_sp<SourceData>(source, filename, mode)
|
make_sp<SourceData>(source, filename, mode)
|
||||||
);
|
);
|
||||||
@ -60,25 +70,32 @@ public:
|
|||||||
#define METHOD(name) &Compiler::name
|
#define METHOD(name) &Compiler::name
|
||||||
#define NO_INFIX nullptr, PREC_NONE
|
#define NO_INFIX nullptr, PREC_NONE
|
||||||
for(TokenIndex i=0; i<kTokenCount; i++) rules[i] = { nullptr, NO_INFIX };
|
for(TokenIndex i=0; i<kTokenCount; i++) rules[i] = { nullptr, NO_INFIX };
|
||||||
rules[TK(".")] = { nullptr, METHOD(exprAttrib), PREC_ATTRIB };
|
rules[TK(".")] = { nullptr, METHOD(exprAttrib), PREC_ATTRIB };
|
||||||
rules[TK("(")] = { METHOD(exprGroup), METHOD(exprCall), PREC_CALL };
|
rules[TK("(")] = { METHOD(exprGroup), METHOD(exprCall), PREC_CALL };
|
||||||
rules[TK("[")] = { METHOD(exprList), METHOD(exprSubscr), PREC_SUBSCRIPT };
|
rules[TK("[")] = { METHOD(exprList), METHOD(exprSubscr), PREC_SUBSCRIPT };
|
||||||
rules[TK("{")] = { METHOD(exprMap), NO_INFIX };
|
rules[TK("{")] = { METHOD(exprMap), NO_INFIX };
|
||||||
rules[TK("%")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
|
rules[TK("%")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
|
||||||
rules[TK("+")] = { nullptr, METHOD(exprBinaryOp), PREC_TERM };
|
rules[TK("+")] = { nullptr, METHOD(exprBinaryOp), PREC_TERM };
|
||||||
rules[TK("-")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_TERM };
|
rules[TK("-")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_TERM };
|
||||||
rules[TK("*")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_FACTOR };
|
rules[TK("*")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_FACTOR };
|
||||||
rules[TK("/")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
|
rules[TK("/")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
|
||||||
rules[TK("//")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
|
rules[TK("//")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
|
||||||
rules[TK("**")] = { nullptr, METHOD(exprBinaryOp), PREC_EXPONENT };
|
rules[TK("**")] = { nullptr, METHOD(exprBinaryOp), PREC_EXPONENT };
|
||||||
rules[TK(">")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
rules[TK(">")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
||||||
rules[TK("<")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
rules[TK("<")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
||||||
rules[TK("==")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY };
|
rules[TK("==")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY };
|
||||||
rules[TK("!=")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY };
|
rules[TK("!=")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY };
|
||||||
rules[TK(">=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
rules[TK(">=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
||||||
rules[TK("<=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
rules[TK("<=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
||||||
rules[TK("in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
|
rules[TK("in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
|
||||||
rules[TK("is")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
|
rules[TK("is")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
|
||||||
|
rules[TK("<<")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT };
|
||||||
|
rules[TK(">>")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT };
|
||||||
|
rules[TK("&")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_AND };
|
||||||
|
rules[TK("|")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_OR };
|
||||||
|
rules[TK("^")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_XOR };
|
||||||
|
rules[TK("?")] = { nullptr, METHOD(exprTernary), PREC_TERNARY };
|
||||||
|
rules[TK(",")] = { nullptr, METHOD(exprTuple), PREC_TUPLE };
|
||||||
rules[TK("not in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
|
rules[TK("not in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
|
||||||
rules[TK("is not")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
|
rules[TK("is not")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
|
||||||
rules[TK("and") ] = { nullptr, METHOD(exprAnd), PREC_LOGICAL_AND };
|
rules[TK("and") ] = { nullptr, METHOD(exprAnd), PREC_LOGICAL_AND };
|
||||||
@ -93,13 +110,6 @@ public:
|
|||||||
rules[TK("@num")] = { METHOD(exprLiteral), NO_INFIX };
|
rules[TK("@num")] = { METHOD(exprLiteral), NO_INFIX };
|
||||||
rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX };
|
rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX };
|
||||||
rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX };
|
rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX };
|
||||||
rules[TK("?")] = { nullptr, METHOD(exprTernary), PREC_TERNARY };
|
|
||||||
rules[TK(",")] = { nullptr, METHOD(exprTuple), PREC_TUPLE };
|
|
||||||
rules[TK("<<")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT };
|
|
||||||
rules[TK(">>")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT };
|
|
||||||
rules[TK("&")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_AND };
|
|
||||||
rules[TK("|")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_OR };
|
|
||||||
rules[TK("^")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_XOR };
|
|
||||||
#undef METHOD
|
#undef METHOD
|
||||||
#undef NO_INFIX
|
#undef NO_INFIX
|
||||||
|
|
||||||
@ -118,15 +128,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int i = 0;
|
|
||||||
std::vector<Token> tokens;
|
|
||||||
|
|
||||||
const Token& prev() { return tokens.at(i-1); }
|
|
||||||
const Token& curr() { return tokens.at(i); }
|
|
||||||
const Token& next() { return tokens.at(i+1); }
|
|
||||||
const Token& peek(int offset) { return tokens.at(i+offset); }
|
|
||||||
void advance() { i++; }
|
|
||||||
|
|
||||||
bool match(TokenIndex expected) {
|
bool match(TokenIndex expected) {
|
||||||
if (curr().type != expected) return false;
|
if (curr().type != expected) return false;
|
||||||
advance();
|
advance();
|
||||||
@ -164,12 +165,14 @@ private:
|
|||||||
if (!match_end_stmt()) SyntaxError("expected statement end");
|
if (!match_end_stmt()) SyntaxError("expected statement end");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXPR(ExprAction action=EXPR_PUSH_STACK) {
|
/*************************************************/
|
||||||
parse_expression(PREC_TUPLE + 1, action);
|
|
||||||
|
void EXPR(bool push_stack=true) {
|
||||||
|
parse_expression(PREC_TUPLE+1, push_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXPR_TUPLE(ExprAction action=EXPR_PUSH_STACK) {
|
void EXPR_TUPLE(bool push_stack=true) {
|
||||||
parse_expression(PREC_TUPLE, action);
|
parse_expression(PREC_TUPLE, push_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
@ -179,8 +182,6 @@ private:
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************/
|
|
||||||
|
|
||||||
// PASS
|
// PASS
|
||||||
void exprLiteral(){
|
void exprLiteral(){
|
||||||
ctx()->s_expr.push(make_expr<LiteralExpr>(prev().value));
|
ctx()->s_expr.push(make_expr<LiteralExpr>(prev().value));
|
||||||
@ -201,63 +202,12 @@ private:
|
|||||||
consume(TK(":"));
|
consume(TK(":"));
|
||||||
}
|
}
|
||||||
e->func.code = push_context(lexer->src, "<lambda>");
|
e->func.code = push_context(lexer->src, "<lambda>");
|
||||||
// https://github.com/blueloveTH/pocketpy/issues/37
|
EXPR(true); // https://github.com/blueloveTH/pocketpy/issues/37
|
||||||
EXPR(true);
|
|
||||||
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||||
pop_context();
|
pop_context();
|
||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
void exprAssign(){
|
|
||||||
// if(co()->codes.empty()) UNREACHABLE();
|
|
||||||
// bool is_load_name_ref = co()->codes.back().op == OP_LOAD_NAME_REF;
|
|
||||||
// int _name_arg = co()->codes.back().arg;
|
|
||||||
// // if the last op is OP_LOAD_NAME_REF, remove it
|
|
||||||
// // because we will emit OP_STORE_NAME or OP_STORE_CLASS_ATTR
|
|
||||||
// if(is_load_name_ref) co()->codes.pop_back();
|
|
||||||
|
|
||||||
// co()->_rvalue += 1;
|
|
||||||
// TokenIndex op = prev().type;
|
|
||||||
// if(op == TK("=")) { // a = (expr)
|
|
||||||
// EXPR_TUPLE();
|
|
||||||
// if(is_load_name_ref){
|
|
||||||
// auto op = ctx()->is_compiling_class ? OP_STORE_CLASS_ATTR : OP_STORE_NAME;
|
|
||||||
// emit(op, _name_arg);
|
|
||||||
// }else{
|
|
||||||
// if(ctx()->is_compiling_class) SyntaxError();
|
|
||||||
// emit(OP_STORE_REF);
|
|
||||||
// }
|
|
||||||
// }else{ // a += (expr) -> a = a + (expr)
|
|
||||||
// if(ctx()->is_compiling_class) SyntaxError();
|
|
||||||
// if(is_load_name_ref){
|
|
||||||
// emit(OP_LOAD_NAME, _name_arg);
|
|
||||||
// }else{
|
|
||||||
// emit(OP_DUP_TOP_VALUE);
|
|
||||||
// }
|
|
||||||
// EXPR();
|
|
||||||
// switch (op) {
|
|
||||||
// case TK("+="): emit(OP_BINARY_OP, 0); break;
|
|
||||||
// case TK("-="): emit(OP_BINARY_OP, 1); break;
|
|
||||||
// case TK("*="): emit(OP_BINARY_OP, 2); break;
|
|
||||||
// case TK("/="): emit(OP_BINARY_OP, 3); break;
|
|
||||||
// case TK("//="): emit(OP_BINARY_OP, 4); break;
|
|
||||||
// case TK("%="): emit(OP_BINARY_OP, 5); break;
|
|
||||||
// case TK("<<="): emit(OP_BITWISE_OP, 0); break;
|
|
||||||
// case TK(">>="): emit(OP_BITWISE_OP, 1); break;
|
|
||||||
// case TK("&="): emit(OP_BITWISE_OP, 2); break;
|
|
||||||
// case TK("|="): emit(OP_BITWISE_OP, 3); break;
|
|
||||||
// case TK("^="): emit(OP_BITWISE_OP, 4); break;
|
|
||||||
// default: UNREACHABLE();
|
|
||||||
// }
|
|
||||||
// if(is_load_name_ref){
|
|
||||||
// emit(OP_STORE_NAME, _name_arg);
|
|
||||||
// }else{
|
|
||||||
// emit(OP_STORE_REF);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// co()->_rvalue -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PASS
|
// PASS
|
||||||
void exprTuple(){
|
void exprTuple(){
|
||||||
auto e = make_expr<TupleExpr>();
|
auto e = make_expr<TupleExpr>();
|
||||||
@ -540,17 +490,17 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
ctx()->emit(OP_DUP_TOP_VALUE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
Str name = prev().str();
|
Str name = prev().str();
|
||||||
int index = ctx()->add_name(name, NAME_ATTR);
|
int index = ctx()->add_name(name);
|
||||||
ctx()->emit(OP_BUILD_ATTR, index, prev().line);
|
ctx()->emit(OP_LOAD_ATTR, index, prev().line);
|
||||||
if (match(TK("as"))) {
|
if (match(TK("as"))) {
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
name = prev().str();
|
name = prev().str();
|
||||||
}
|
}
|
||||||
index = ctx()->add_name(name, name_scope());
|
index = ctx()->add_name(name);
|
||||||
ctx()->emit(OP_STORE_NAME, index, prev().line);
|
ctx()->emit(OP_STORE_GLOBAL, index, prev().line);
|
||||||
} while (match(TK(",")));
|
} while (match(TK(",")));
|
||||||
ctx()->emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
@ -650,7 +600,20 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool try_compile_assignment(){
|
bool try_compile_assignment(){
|
||||||
|
// switch (op) {
|
||||||
|
// case TK("+="): emit(OP_BINARY_OP, 0); break;
|
||||||
|
// case TK("-="): emit(OP_BINARY_OP, 1); break;
|
||||||
|
// case TK("*="): emit(OP_BINARY_OP, 2); break;
|
||||||
|
// case TK("/="): emit(OP_BINARY_OP, 3); break;
|
||||||
|
// case TK("//="): emit(OP_BINARY_OP, 4); break;
|
||||||
|
// case TK("%="): emit(OP_BINARY_OP, 5); break;
|
||||||
|
// case TK("<<="): emit(OP_BITWISE_OP, 0); break;
|
||||||
|
// case TK(">>="): emit(OP_BITWISE_OP, 1); break;
|
||||||
|
// case TK("&="): emit(OP_BITWISE_OP, 2); break;
|
||||||
|
// case TK("|="): emit(OP_BITWISE_OP, 3); break;
|
||||||
|
// case TK("^="): emit(OP_BITWISE_OP, 4); break;
|
||||||
|
// default: UNREACHABLE();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile_stmt() {
|
void compile_stmt() {
|
||||||
@ -728,16 +691,18 @@ private:
|
|||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
} break;
|
} break;
|
||||||
case TK("with"): {
|
case TK("with"): {
|
||||||
EXPR(true);
|
// TODO: reimpl this
|
||||||
consume(TK("as"));
|
UNREACHABLE();
|
||||||
consume(TK("@id"));
|
// EXPR(true);
|
||||||
int index = ctx()->add_name(prev().str(), name_scope());
|
// consume(TK("as"));
|
||||||
emit(OP_STORE_NAME, index);
|
// consume(TK("@id"));
|
||||||
emit(OP_LOAD_NAME_REF, index);
|
// int index = ctx()->add_name(prev().str(), name_scope());
|
||||||
emit(OP_WITH_ENTER);
|
// emit(OP_STORE_NAME, index);
|
||||||
compile_block_body();
|
// emit(OP_LOAD_NAME_REF, index);
|
||||||
emit(OP_LOAD_NAME_REF, index);
|
// emit(OP_WITH_ENTER);
|
||||||
emit(OP_WITH_EXIT);
|
// compile_block_body();
|
||||||
|
// emit(OP_LOAD_NAME_REF, index);
|
||||||
|
// emit(OP_WITH_EXIT);
|
||||||
} break;
|
} break;
|
||||||
/*************************************************/
|
/*************************************************/
|
||||||
// TODO: refactor goto/label use special $ syntax
|
// TODO: refactor goto/label use special $ syntax
|
||||||
@ -749,21 +714,21 @@ private:
|
|||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK("goto"):
|
case TK("goto"):
|
||||||
if(mode() != EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE");
|
if(mode()!=EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE");
|
||||||
consume(TK(".")); consume(TK("@id"));
|
consume(TK(".")); consume(TK("@id"));
|
||||||
emit(OP_GOTO, co()->add_name(prev().str(), NAME_SPECIAL));
|
emit(OP_GOTO, co()->add_name(prev().str(), NAME_SPECIAL));
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
/*************************************************/
|
/*************************************************/
|
||||||
// dangling expression or assignment
|
// handle dangling expression or assignment
|
||||||
default: {
|
default: {
|
||||||
EXPR_TUPLE(true);
|
EXPR_TUPLE(true);
|
||||||
bool assigment = try_compile_assignment();
|
if(!try_compile_assignment()){
|
||||||
if(!assigment){
|
|
||||||
if(mode()==REPL_MODE && name_scope()==NAME_GLOBAL){
|
if(mode()==REPL_MODE && name_scope()==NAME_GLOBAL){
|
||||||
emit(OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE);
|
emit(OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE);
|
||||||
|
}else{
|
||||||
|
emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
|
||||||
}
|
}
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
}
|
}
|
||||||
|
42
src/expr.h
42
src/expr.h
@ -595,3 +595,45 @@ struct TernaryExpr: Expr{
|
|||||||
|
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|
||||||
|
|
||||||
|
// struct TupleRef : BaseRef {
|
||||||
|
// Tuple objs;
|
||||||
|
// TupleRef(Tuple&& objs) : objs(std::move(objs)) {}
|
||||||
|
|
||||||
|
// PyObject* get(VM* vm, Frame* frame) const{
|
||||||
|
// Tuple args(objs.size());
|
||||||
|
// for (int i = 0; i < objs.size(); i++) {
|
||||||
|
// args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame);
|
||||||
|
// }
|
||||||
|
// return VAR(std::move(args));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void set(VM* vm, Frame* frame, PyObject* val) const{
|
||||||
|
// val = vm->asIter(val);
|
||||||
|
// BaseIter* iter = vm->PyIter_AS_C(val);
|
||||||
|
// for(int i=0; i<objs.size(); i++){
|
||||||
|
// PyObject* x;
|
||||||
|
// if(is_type(objs[i], vm->tp_star_wrapper)){
|
||||||
|
// auto& star = _CAST(StarWrapper&, objs[i]);
|
||||||
|
// if(star.rvalue) vm->ValueError("can't use starred expression here");
|
||||||
|
// if(i != objs.size()-1) vm->ValueError("* can only be used at the end");
|
||||||
|
// auto ref = vm->PyRef_AS_C(star.obj);
|
||||||
|
// List list;
|
||||||
|
// while((x = iter->next()) != nullptr) list.push_back(x);
|
||||||
|
// ref->set(vm, frame, VAR(std::move(list)));
|
||||||
|
// return;
|
||||||
|
// }else{
|
||||||
|
// x = iter->next();
|
||||||
|
// if(x == nullptr) vm->ValueError("not enough values to unpack");
|
||||||
|
// vm->PyRef_AS_C(objs[i])->set(vm, frame, x);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// PyObject* x = iter->next();
|
||||||
|
// if(x != nullptr) vm->ValueError("too many values to unpack");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void del(VM* vm, Frame* frame) const{
|
||||||
|
// for(int i=0; i<objs.size(); i++) vm->PyRef_AS_C(objs[i])->del(vm, frame);
|
||||||
|
// }
|
||||||
|
// };
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
OPCODE(NO_OP)
|
OPCODE(NO_OP)
|
||||||
OPCODE(POP_TOP)
|
OPCODE(POP_TOP)
|
||||||
OPCODE(DUP_TOP_VALUE)
|
OPCODE(DUP_TOP)
|
||||||
OPCODE(CALL)
|
OPCODE(CALL)
|
||||||
OPCODE(CALL_UNPACK)
|
OPCODE(CALL_UNPACK)
|
||||||
OPCODE(CALL_KWARGS)
|
OPCODE(CALL_KWARGS)
|
||||||
@ -57,20 +57,13 @@ OPCODE(LOAD_FALSE)
|
|||||||
OPCODE(LOAD_EVAL_FN)
|
OPCODE(LOAD_EVAL_FN)
|
||||||
OPCODE(LOAD_FUNCTION)
|
OPCODE(LOAD_FUNCTION)
|
||||||
OPCODE(LOAD_ELLIPSIS)
|
OPCODE(LOAD_ELLIPSIS)
|
||||||
OPCODE(LOAD_NAME)
|
|
||||||
OPCODE(LOAD_NAME_REF)
|
|
||||||
|
|
||||||
OPCODE(ASSERT)
|
OPCODE(ASSERT)
|
||||||
OPCODE(EXCEPTION_MATCH)
|
OPCODE(EXCEPTION_MATCH)
|
||||||
OPCODE(RAISE)
|
OPCODE(RAISE)
|
||||||
OPCODE(RE_RAISE)
|
OPCODE(RE_RAISE)
|
||||||
|
|
||||||
OPCODE(BUILD_INDEX)
|
|
||||||
OPCODE(BUILD_ATTR)
|
|
||||||
OPCODE(BUILD_ATTR_REF)
|
|
||||||
OPCODE(STORE_NAME)
|
|
||||||
OPCODE(STORE_FUNCTION)
|
OPCODE(STORE_FUNCTION)
|
||||||
OPCODE(STORE_REF)
|
|
||||||
|
|
||||||
OPCODE(TRY_BLOCK_ENTER)
|
OPCODE(TRY_BLOCK_ENTER)
|
||||||
OPCODE(TRY_BLOCK_EXIT)
|
OPCODE(TRY_BLOCK_EXIT)
|
||||||
|
179
src/ref.h
179
src/ref.h
@ -1,179 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "obj.h"
|
|
||||||
#include "vm.h"
|
|
||||||
|
|
||||||
namespace pkpy {
|
|
||||||
|
|
||||||
struct BaseRef {
|
|
||||||
virtual PyObject* get(VM*, Frame*) const = 0;
|
|
||||||
virtual void set(VM*, Frame*, PyObject*) const = 0;
|
|
||||||
virtual void del(VM*, Frame*) const = 0;
|
|
||||||
virtual ~BaseRef() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NameRef : BaseRef {
|
|
||||||
const std::pair<StrName, NameScope> pair;
|
|
||||||
StrName name() const { return pair.first; }
|
|
||||||
NameScope scope() const { return pair.second; }
|
|
||||||
NameRef(const std::pair<StrName, NameScope>& pair) : pair(pair) {}
|
|
||||||
|
|
||||||
PyObject* get(VM* vm, Frame* frame) const{
|
|
||||||
PyObject* val;
|
|
||||||
val = frame->f_locals().try_get(name());
|
|
||||||
if(val != nullptr) return val;
|
|
||||||
val = frame->f_closure_try_get(name());
|
|
||||||
if(val != nullptr) return val;
|
|
||||||
val = frame->f_globals().try_get(name());
|
|
||||||
if(val != nullptr) return val;
|
|
||||||
val = vm->builtins->attr().try_get(name());
|
|
||||||
if(val != nullptr) return val;
|
|
||||||
vm->NameError(name());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(VM* vm, Frame* frame, PyObject* val) const{
|
|
||||||
switch(scope()) {
|
|
||||||
case NAME_LOCAL: frame->f_locals().set(name(), val); break;
|
|
||||||
case NAME_GLOBAL:
|
|
||||||
if(frame->f_locals().try_set(name(), val)) return;
|
|
||||||
frame->f_globals().set(name(), val);
|
|
||||||
break;
|
|
||||||
default: UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void del(VM* vm, Frame* frame) const{
|
|
||||||
switch(scope()) {
|
|
||||||
case NAME_LOCAL: {
|
|
||||||
if(frame->f_locals().contains(name())){
|
|
||||||
frame->f_locals().erase(name());
|
|
||||||
}else{
|
|
||||||
vm->NameError(name());
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case NAME_GLOBAL:
|
|
||||||
{
|
|
||||||
if(frame->f_locals().contains(name())){
|
|
||||||
frame->f_locals().erase(name());
|
|
||||||
}else{
|
|
||||||
if(frame->f_globals().contains(name())){
|
|
||||||
frame->f_globals().erase(name());
|
|
||||||
}else{
|
|
||||||
vm->NameError(name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
default: UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct AttrRef : BaseRef {
|
|
||||||
mutable PyObject* obj;
|
|
||||||
NameRef attr;
|
|
||||||
AttrRef(PyObject* obj, NameRef attr) : obj(obj), attr(attr) {}
|
|
||||||
|
|
||||||
PyObject* get(VM* vm, Frame* frame) const{
|
|
||||||
return vm->getattr(obj, attr.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(VM* vm, Frame* frame, PyObject* val) const{
|
|
||||||
vm->setattr(obj, attr.name(), std::move(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IndexRef : BaseRef {
|
|
||||||
mutable PyObject* obj;
|
|
||||||
PyObject* index;
|
|
||||||
IndexRef(PyObject* obj, PyObject* index) : obj(obj), index(index) {}
|
|
||||||
|
|
||||||
PyObject* get(VM* vm, Frame* frame) const{
|
|
||||||
return vm->fast_call(__getitem__, Args{obj, index});
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(VM* vm, Frame* frame, PyObject* val) const{
|
|
||||||
vm->fast_call(__setitem__, Args{obj, index, val});
|
|
||||||
}
|
|
||||||
|
|
||||||
void del(VM* vm, Frame* frame) const{
|
|
||||||
vm->fast_call(__delitem__, Args{obj, index});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TupleRef : BaseRef {
|
|
||||||
Tuple objs;
|
|
||||||
TupleRef(Tuple&& objs) : objs(std::move(objs)) {}
|
|
||||||
|
|
||||||
PyObject* get(VM* vm, Frame* frame) const{
|
|
||||||
Tuple args(objs.size());
|
|
||||||
for (int i = 0; i < objs.size(); i++) {
|
|
||||||
args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame);
|
|
||||||
}
|
|
||||||
return VAR(std::move(args));
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(VM* vm, Frame* frame, PyObject* val) const{
|
|
||||||
val = vm->asIter(val);
|
|
||||||
BaseIter* iter = vm->PyIter_AS_C(val);
|
|
||||||
for(int i=0; i<objs.size(); i++){
|
|
||||||
PyObject* x;
|
|
||||||
if(is_type(objs[i], vm->tp_star_wrapper)){
|
|
||||||
auto& star = _CAST(StarWrapper&, objs[i]);
|
|
||||||
if(star.rvalue) vm->ValueError("can't use starred expression here");
|
|
||||||
if(i != objs.size()-1) vm->ValueError("* can only be used at the end");
|
|
||||||
auto ref = vm->PyRef_AS_C(star.obj);
|
|
||||||
List list;
|
|
||||||
while((x = iter->next()) != nullptr) list.push_back(x);
|
|
||||||
ref->set(vm, frame, VAR(std::move(list)));
|
|
||||||
return;
|
|
||||||
}else{
|
|
||||||
x = iter->next();
|
|
||||||
if(x == nullptr) vm->ValueError("not enough values to unpack");
|
|
||||||
vm->PyRef_AS_C(objs[i])->set(vm, frame, x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PyObject* x = iter->next();
|
|
||||||
if(x != nullptr) vm->ValueError("too many values to unpack");
|
|
||||||
}
|
|
||||||
|
|
||||||
void del(VM* vm, Frame* frame) const{
|
|
||||||
for(int i=0; i<objs.size(); i++) vm->PyRef_AS_C(objs[i])->del(vm, frame);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template<typename P>
|
|
||||||
PyObject* VM::PyRef(P&& value) {
|
|
||||||
static_assert(std::is_base_of_v<BaseRef, std::decay_t<P>>);
|
|
||||||
return heap.gcnew<P>(tp_ref, std::forward<P>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const BaseRef* VM::PyRef_AS_C(PyObject* obj)
|
|
||||||
{
|
|
||||||
if(!is_type(obj, tp_ref)) TypeError("expected an l-value");
|
|
||||||
return static_cast<const BaseRef*>(obj->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
/***** Frame's Impl *****/
|
|
||||||
inline void Frame::try_deref(VM* vm, PyObject*& v){
|
|
||||||
if(is_type(v, vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***** GC's Impl *****/
|
|
||||||
template<> inline void _mark<AttrRef>(AttrRef& t){
|
|
||||||
OBJ_MARK(t.obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> inline void _mark<IndexRef>(IndexRef& t){
|
|
||||||
OBJ_MARK(t.obj);
|
|
||||||
OBJ_MARK(t.index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> inline void _mark<TupleRef>(TupleRef& t){
|
|
||||||
_mark<Tuple>(t.objs);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace pkpy
|
|
Loading…
x
Reference in New Issue
Block a user