impl unpack

This commit is contained in:
blueloveTH 2022-11-07 18:42:27 +08:00
parent c2fa538f44
commit b5aba376fe
6 changed files with 130 additions and 86 deletions

View File

@ -139,9 +139,15 @@ public:
this->ip = i; this->ip = i;
} }
inline PyVarList popNReversed(VM* vm, int n){ PyVarList popNValuesReversed(VM* vm, int n){
PyVarList v(n); PyVarList v(n);
for(int i=n-1; i>=0; i--) v[i] = popValue(vm); for(int i=n-1; i>=0; i--) v[i] = popValue(vm);
return v; return v;
} }
PyVarList __popNReversed(int n){
PyVarList v(n);
for(int i=n-1; i>=0; i--) v[i] = __pop();
return v;
}
}; };

View File

@ -26,19 +26,18 @@ struct Loop {
Loop(bool forLoop, int start) : forLoop(forLoop), start(start) {} Loop(bool forLoop, int start) : forLoop(forLoop), start(start) {}
}; };
#define ExprCommaSplitArgs(end) \ #define ExprCommaSplitArgs(end) \
int ARGC = 0; \ int ARGC = 0; \
do { \ do { \
matchNewLines(); \ matchNewLines(); \
if (peek() == TK(end)) break; \ if (peek() == TK(end)) break; \
compileExpression(); \ EXPR(); \
ARGC++; \ ARGC++; \
matchNewLines(); \ matchNewLines(); \
} while (match(TK(","))); \ } while (match(TK(","))); \
matchNewLines(); \ matchNewLines(); \
consume(TK(end)); consume(TK(end));
class Compiler { class Compiler {
public: public:
std::unique_ptr<Parser> parser; std::unique_ptr<Parser> parser;
@ -104,14 +103,19 @@ public:
rules[TK("@id")] = { METHOD(exprName), NO_INFIX }; rules[TK("@id")] = { METHOD(exprName), NO_INFIX };
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("=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST }; rules[TK("=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
rules[TK("+=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST }; rules[TK("+=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
rules[TK("-=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST }; rules[TK("-=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
rules[TK("*=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST }; rules[TK("*=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
rules[TK("/=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST }; rules[TK("/=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
rules[TK("//=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST }; rules[TK("//=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
rules[TK(",")] = { nullptr, METHOD(exprComma), PREC_COMMA };
#undef METHOD #undef METHOD
#undef NO_INFIX #undef NO_INFIX
#define EXPR() parsePrecedence(PREC_COMMA) // no '=' and ',' just a simple expression
#define EXPR_TUPLE() parsePrecedence(PREC_ASSIGNMENT) // no '=', but ',' is allowed
#define EXPR_ANY() parsePrecedence(PREC_NONE)
} }
void eatString(bool single_quote) { void eatString(bool single_quote) {
@ -297,15 +301,15 @@ public:
} }
void exprAssign(){ void exprAssign() {
_TokenType op = parser->previous.type; _TokenType op = parser->previous.type;
if(op == TK("=")) { // a = (expr) if(op == TK("=")) { // a = (expr)
compileExpressionTuple(); EXPR_TUPLE();
emitCode(OP_STORE_PTR); emitCode(OP_STORE_PTR);
}else{ // a += (expr) -> a = a + (expr) }else{ // a += (expr) -> a = a + (expr)
// TODO: optimization is needed for inplace operators // TODO: optimization is needed for inplace operators
emitCode(OP_DUP_TOP); emitCode(OP_DUP_TOP);
compileExpression(); EXPR();
switch (op) { switch (op) {
case TK("+="): emitCode(OP_BINARY_OP, 0); break; case TK("+="): emitCode(OP_BINARY_OP, 0); break;
case TK("-="): emitCode(OP_BINARY_OP, 1); break; case TK("-="): emitCode(OP_BINARY_OP, 1); break;
@ -318,6 +322,15 @@ public:
} }
} }
void exprComma() {
int size = 1; // an expr is in the stack now
do {
EXPR(); // NOTE: "1," will fail, "1,2" will be ok
size++;
} while(match(TK(",")));
emitCode(OP_BUILD_SMART_TUPLE, size);
}
void exprOr() { void exprOr() {
int patch = emitCode(OP_JUMP_IF_TRUE_OR_POP); int patch = emitCode(OP_JUMP_IF_TRUE_OR_POP);
parsePrecedence(PREC_LOGICAL_OR); parsePrecedence(PREC_LOGICAL_OR);
@ -371,7 +384,7 @@ public:
void exprGrouping() { void exprGrouping() {
matchNewLines(); matchNewLines();
compileExpressionTuple(); EXPR_TUPLE();
matchNewLines(); matchNewLines();
consume(TK(")")); consume(TK(")"));
} }
@ -386,8 +399,8 @@ public:
do { do {
matchNewLines(); matchNewLines();
if (peek() == TK("}")) break; if (peek() == TK("}")) break;
compileExpression();consume(TK(":"));compileExpression(); EXPR();consume(TK(":"));EXPR();
emitCode(OP_BUILD_TUPLE, 2); emitCode(OP_BUILD_SMART_TUPLE, 2);
size++; size++;
matchNewLines(); matchNewLines();
} while (match(TK(","))); } while (match(TK(",")));
@ -425,17 +438,17 @@ public:
if(match(TK("]"))){ if(match(TK("]"))){
emitCode(OP_LOAD_NONE); emitCode(OP_LOAD_NONE);
}else{ }else{
compileExpression(); EXPR();
consume(TK("]")); consume(TK("]"));
} }
emitCode(OP_BUILD_SLICE); emitCode(OP_BUILD_SLICE);
}else{ }else{
compileExpression(); EXPR();
if(match(TK(":"))){ if(match(TK(":"))){
if(match(TK("]"))){ if(match(TK("]"))){
emitCode(OP_LOAD_NONE); emitCode(OP_LOAD_NONE);
}else{ }else{
compileExpression(); EXPR();
consume(TK("]")); consume(TK("]"));
} }
emitCode(OP_BUILD_SLICE); emitCode(OP_BUILD_SLICE);
@ -457,23 +470,6 @@ public:
} }
} }
void parsePrecedence(Precedence precedence) {
lexToken();
GrammarFn prefix = rules[parser->previous.type].prefix;
if (prefix == nullptr) {
throw SyntaxError(path, parser->previous, "expected an expression");
}
(this->*prefix)();
while (rules[peek()].precedence >= precedence) {
lexToken();
_TokenType op = parser->previous.type;
GrammarFn infix = rules[op].infix;
(this->*infix)();
}
}
void keepOpcodeLine(){ void keepOpcodeLine(){
int i = getCode()->co_code.size() - 1; int i = getCode()->co_code.size() - 1;
getCode()->co_code[i].line = getCode()->co_code[i-1].line; getCode()->co_code[i].line = getCode()->co_code[i-1].line;
@ -527,29 +523,30 @@ public:
} }
int index = getCode()->addName(tkmodule.str(), NAME_GLOBAL); int index = getCode()->addName(tkmodule.str(), NAME_GLOBAL);
emitCode(OP_STORE_NAME_PTR, index); emitCode(OP_STORE_NAME_PTR, index);
} while (match(TK(",")) && (matchNewLines(), true)); } while (match(TK(",")));
consumeEndStatement(); consumeEndStatement();
} }
// Compiles an expression. An expression will result a value on top of the stack. void parsePrecedence(Precedence precedence) {
void compileExpression() { lexToken();
parsePrecedence(PREC_LOWEST); GrammarFn prefix = rules[parser->previous.type].prefix;
}
// Compiles an expression. Support tuple syntax. if (prefix == nullptr) {
void compileExpressionTuple() { throw SyntaxError(path, parser->previous, "expected an expression");
int size = 0; }
while (true) {
compileExpression(); (this->*prefix)();
size++; while (rules[peek()].precedence > precedence) {
if (!match(TK(","))) break; lexToken();
_TokenType op = parser->previous.type;
GrammarFn infix = rules[op].infix;
(this->*infix)();
} }
if(size > 1) emitCode(OP_BUILD_TUPLE, size);
} }
void compileIfStatement() { void compileIfStatement() {
matchNewLines(); matchNewLines();
compileExpression(); //< Condition. EXPR_TUPLE();
int ifpatch = emitCode(OP_POP_JUMP_IF_FALSE); int ifpatch = emitCode(OP_POP_JUMP_IF_FALSE);
compileBlockBody(); compileBlockBody();
@ -583,7 +580,7 @@ public:
void compileWhileStatement() { void compileWhileStatement() {
Loop& loop = enterLoop(false); Loop& loop = enterLoop(false);
compileExpression(); EXPR_TUPLE();
int patch = emitCode(OP_POP_JUMP_IF_FALSE); int patch = emitCode(OP_POP_JUMP_IF_FALSE);
compileBlockBody(); compileBlockBody();
emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine(); emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine();
@ -598,7 +595,7 @@ public:
codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL
); );
consume(TK("in")); consume(TK("in"));
compileExpressionTuple(); EXPR_TUPLE();
emitCode(OP_GET_ITER); emitCode(OP_GET_ITER);
Loop& loop = enterLoop(true); Loop& loop = enterLoop(true);
int patch = emitCode(OP_FOR_ITER); int patch = emitCode(OP_FOR_ITER);
@ -628,7 +625,7 @@ public:
if(matchEndStatement()){ if(matchEndStatement()){
emitCode(OP_LOAD_NONE); emitCode(OP_LOAD_NONE);
}else{ }else{
compileExpressionTuple(); EXPR_TUPLE();
consumeEndStatement(); consumeEndStatement();
} }
emitCode(OP_RETURN_VALUE); emitCode(OP_RETURN_VALUE);
@ -639,23 +636,23 @@ public:
} else if (match(TK("for"))) { } else if (match(TK("for"))) {
compileForStatement(); compileForStatement();
} else if(match(TK("assert"))){ } else if(match(TK("assert"))){
compileExpression(); EXPR();
emitCode(OP_ASSERT); emitCode(OP_ASSERT);
consumeEndStatement(); consumeEndStatement();
} else if(match(TK("raise"))){ } else if(match(TK("raise"))){
consume(TK("@id")); // dummy exception type consume(TK("@id")); // dummy exception type
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str()))); emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str())));
consume(TK("("));compileExpression();consume(TK(")")); consume(TK("("));EXPR();consume(TK(")"));
emitCode(OP_RAISE_ERROR); emitCode(OP_RAISE_ERROR);
consumeEndStatement(); consumeEndStatement();
} else if(match(TK("del"))){ } else if(match(TK("del"))){
compileExpression(); EXPR();
emitCode(OP_DELETE_PTR); emitCode(OP_DELETE_PTR);
consumeEndStatement(); consumeEndStatement();
} else if(match(TK("pass"))){ } else if(match(TK("pass"))){
consumeEndStatement(); consumeEndStatement();
} else { } else {
compileExpressionTuple(); EXPR_ANY();
consumeEndStatement(); consumeEndStatement();
// If last op is not an assignment, pop the result. // If last op is not an assignment, pop the result.

View File

@ -18,10 +18,8 @@ OPCODE(UNARY_NOT)
OPCODE(DUP_TOP) OPCODE(DUP_TOP)
OPCODE(BUILD_LIST) OPCODE(BUILD_LIST)
OPCODE(BUILD_TUPLE)
OPCODE(BUILD_MAP) OPCODE(BUILD_MAP)
OPCODE(BUILD_SLICE) OPCODE(BUILD_SLICE)
OPCODE(UNPACK_SEQUENCE)
OPCODE(GET_ITER) OPCODE(GET_ITER)
OPCODE(FOR_ITER) OPCODE(FOR_ITER)
@ -49,4 +47,6 @@ OPCODE(STORE_NAME_PTR) // arg for the name_ptr, [expr], directly store to t
OPCODE(STORE_PTR) // no arg, [ptr, expr] -> *ptr = expr OPCODE(STORE_PTR) // no arg, [ptr, expr] -> *ptr = expr
OPCODE(DELETE_PTR) // no arg, [ptr] -> [] -> delete ptr OPCODE(DELETE_PTR) // no arg, [ptr] -> [] -> delete ptr
OPCODE(BUILD_SMART_TUPLE) // if all elements are pointers, build a compound pointer, otherwise build a tuple
#endif #endif

View File

@ -65,7 +65,8 @@ struct Token{
enum Precedence { enum Precedence {
PREC_NONE, PREC_NONE,
PREC_LOWEST, PREC_ASSIGNMENT, // =
PREC_COMMA, // ,
PREC_LOGICAL_OR, // or PREC_LOGICAL_OR, // or
PREC_LOGICAL_AND, // and PREC_LOGICAL_AND, // and
PREC_EQUALITY, // == != PREC_EQUALITY, // == !=

View File

@ -49,3 +49,13 @@ struct IndexPointer : BasePointer {
void set(VM* vm, Frame* frame, PyVar val) const; void set(VM* vm, Frame* frame, PyVar val) const;
void del(VM* vm, Frame* frame) const; void del(VM* vm, Frame* frame) const;
}; };
struct CompoundPointer : BasePointer {
const std::vector<_Pointer> pointers;
CompoundPointer(std::vector<_Pointer> pointers) : pointers(pointers) {}
CompoundPointer(std::vector<_Pointer>&& pointers) : pointers(pointers) {}
PyVar get(VM* vm, Frame* frame) const;
void set(VM* vm, Frame* frame, PyVar val) const;
void del(VM* vm, Frame* frame) const;
};

View File

@ -163,6 +163,27 @@ public:
_Pointer p = PyPointer_AS_C(frame->__pop()); _Pointer p = PyPointer_AS_C(frame->__pop());
p->del(this, frame.get()); p->del(this, frame.get());
} break; } break;
case OP_BUILD_SMART_TUPLE:
{
PyVarList items = frame->__popNReversed(byte.arg);
bool done = false;
for(auto& item : items){
if(!item->isType(_tp_pointer)) {
done = true;
PyVarList values(items.size());
for(int i=0; i<items.size(); i++){
values[i] = frame->__deref_pointer(this, items[i]);
}
frame->push(PyTuple(values));
break;
}
}
if(done) break;
std::vector<_Pointer> pointers(items.size());
for(int i=0; i<items.size(); i++)
pointers[i] = PyPointer_AS_C(items[i]);
frame->push(PyPointer(std::make_shared<CompoundPointer>(pointers)));
} break;
case OP_STORE_FUNCTION: case OP_STORE_FUNCTION:
{ {
PyVar obj = frame->popValue(this); PyVar obj = frame->popValue(this);
@ -190,16 +211,6 @@ public:
callstack.pop(); callstack.pop();
return ret; return ret;
} break; } break;
case OP_UNPACK_SEQUENCE:
{
PyVar seq = frame->popValue(this);
bool iterable = (seq->isType(_tp_tuple) || seq->isType(_tp_list));
if(!iterable) _error("TypeError", "only tuple and list can be unpacked");
const PyVarList& objs = std::get<PyVarList>(seq->_native);
if(objs.size() > byte.arg) _error("ValueError", "too many values to unpack (expected " + std::to_string(byte.arg) + ")");
if(objs.size() < byte.arg) _error("ValueError", "not enough values to unpack (expected " + std::to_string(byte.arg) + ", got " + std::to_string(objs.size()) + ")");
for(auto it=objs.rbegin(); it!=objs.rend(); it++) frame->push(*it);
} break;
case OP_PRINT_EXPR: case OP_PRINT_EXPR:
{ {
const PyVar& expr = frame->topValue(this); const PyVar& expr = frame->topValue(this);
@ -254,24 +265,19 @@ public:
} break; } break;
case OP_BUILD_LIST: case OP_BUILD_LIST:
{ {
PyVarList items = frame->popNReversed(this, byte.arg); PyVarList items = frame->popNValuesReversed(this, byte.arg);
frame->push(PyList(items)); frame->push(PyList(items));
} break; } break;
case OP_BUILD_MAP: case OP_BUILD_MAP:
{ {
PyVarList items = frame->popNReversed(this, byte.arg); PyVarList items = frame->popNValuesReversed(this, byte.arg);
PyVar obj = call(builtins->attribs["dict"], {PyList(items)}); PyVar obj = call(builtins->attribs["dict"], {PyList(items)});
frame->push(obj); frame->push(obj);
} break; } break;
case OP_BUILD_TUPLE:
{
PyVarList items = frame->popNReversed(this, byte.arg);
frame->push(PyTuple(items));
} break;
case OP_DUP_TOP: frame->push(frame->topValue(this)); break; case OP_DUP_TOP: frame->push(frame->topValue(this)); break;
case OP_CALL: case OP_CALL:
{ {
PyVarList args = frame->popNReversed(this, byte.arg); PyVarList args = frame->popNValuesReversed(this, byte.arg);
PyVar callable = frame->popValue(this); PyVar callable = frame->popValue(this);
frame->push(call(callable, args)); frame->push(call(callable, args));
} break; } break;
@ -640,6 +646,30 @@ void IndexPointer::del(VM* vm, Frame* frame) const{
vm->call(obj, __delitem__, {index}); vm->call(obj, __delitem__, {index});
} }
PyVar CompoundPointer::get(VM* vm, Frame* frame) const{
PyVarList args(pointers.size());
for (int i = 0; i < pointers.size(); i++) {
args[i] = pointers[i]->get(vm, frame);
}
return vm->PyTuple(args);
}
void CompoundPointer::set(VM* vm, Frame* frame, PyVar val) const{
if(!val->isType(vm->_tp_tuple) && !val->isType(vm->_tp_list)){
vm->_error("TypeError", "only tuple or list can be unpacked");
}
const PyVarList& args = std::get<PyVarList>(val->_native);
if(args.size() > pointers.size()) vm->_error("ValueError", "too many values to unpack");
if(args.size() < pointers.size()) vm->_error("ValueError", "not enough values to unpack");
for (int i = 0; i < pointers.size(); i++) {
pointers[i]->set(vm, frame, args[i]);
}
}
void CompoundPointer::del(VM* vm, Frame* frame) const{
for (auto& ptr : pointers) ptr->del(vm, frame);
}
/**************** Frame ****************/ /**************** Frame ****************/
inline PyVar Frame::__deref_pointer(VM* vm, PyVar v){ inline PyVar Frame::__deref_pointer(VM* vm, PyVar v){
if(v->isType(vm->_tp_pointer)) v = vm->PyPointer_AS_C(v)->get(vm, this); if(v->isType(vm->_tp_pointer)) v = vm->PyPointer_AS_C(v)->get(vm, this);