impl listcomp(with if)

This commit is contained in:
blueloveTH 2022-11-08 21:22:59 +08:00
parent bb651906c3
commit f2e589a5a3
2 changed files with 39 additions and 15 deletions

View File

@ -55,10 +55,11 @@ struct CodeObject {
return co_consts.size() - 1; return co_consts.size() - 1;
} }
void __copyToEnd(int start, int end){ void __moveToEnd(int start, int end){
auto _start = co_code.begin() + start; auto _start = co_code.begin() + start;
auto _end = co_code.begin() + end; auto _end = co_code.begin() + end;
co_code.insert(co_code.end(), _start, _end); co_code.insert(co_code.end(), _start, _end);
for(int i=start; i<end; i++) co_code[i].op = OP_NO_OP;
} }
_Str toString(){ _Str toString(){

View File

@ -11,7 +11,7 @@
class Compiler; class Compiler;
typedef void (Compiler::*GrammarFn)(); typedef void (Compiler::*GrammarFn)();
typedef std::function<void(Compiler*)> CompilerAction; typedef void (Compiler::*CompilerAction)();
struct GrammarRule{ struct GrammarRule{
GrammarFn prefix; GrammarFn prefix;
@ -450,12 +450,33 @@ __LISTCOMP:
getCode()->co_code[_patch].op = OP_JUMP_ABSOLUTE; getCode()->co_code[_patch].op = OP_JUMP_ABSOLUTE;
getCode()->co_code[_patch].arg = _body_end; getCode()->co_code[_patch].arg = _body_end;
emitCode(OP_BUILD_LIST, 0); emitCode(OP_BUILD_LIST, 0);
__compileForLoop([=](Compiler* compiler){ EXPR_FOR_VARS();consume(TK("in"));EXPR_TUPLE();
// [list, iter] matchNewLines();
getCode()->__copyToEnd(_body_start, _body_end);
// [list, iter, value] int _skipPatch = emitCode(OP_JUMP_ABSOLUTE);
int _cond_start = getCode()->co_code.size();
if(match(TK("if"))) EXPR_TUPLE();
int _cond_end = getCode()->co_code.size();
patchJump(_skipPatch);
emitCode(OP_GET_ITER);
Loop& loop = enterLoop(true);
int patch = emitCode(OP_FOR_ITER);
if(_cond_end != _cond_start) { // there is an if condition
getCode()->__moveToEnd(_cond_start, _cond_end);
int ifpatch = emitCode(OP_POP_JUMP_IF_FALSE);
getCode()->__moveToEnd(_body_start, _body_end);
emitCode(OP_LIST_APPEND); emitCode(OP_LIST_APPEND);
}); patchJump(ifpatch);
}else{
getCode()->__moveToEnd(_body_start, _body_end);
emitCode(OP_LIST_APPEND);
}
emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine();
patchJump(patch);
exitLoop();
consume(TK("]")); consume(TK("]"));
} }
@ -547,7 +568,7 @@ __LISTCOMP:
return getCode()->co_code.size() - 1; return getCode()->co_code.size() - 1;
} }
void patchJump(int addr_index) { inline void patchJump(int addr_index) {
int target = getCode()->co_code.size(); int target = getCode()->co_code.size();
getCode()->co_code[addr_index].arg = target; getCode()->co_code[addr_index].arg = target;
} }
@ -563,7 +584,7 @@ __LISTCOMP:
} }
consume(TK("@indent")); consume(TK("@indent"));
while (peek() != TK("@dedent")) { while (peek() != TK("@dedent")) {
action(this); (this->*action)();
matchNewLines(); matchNewLines();
} }
consume(TK("@dedent")); consume(TK("@dedent"));
@ -652,19 +673,21 @@ __LISTCOMP:
exitLoop(); exitLoop();
} }
void __compileForLoop(CompilerAction action) { void EXPR_FOR_VARS(){
int size = 0; int size = 0;
do { do {
consume(TK("@id")); consume(TK("@id"));
exprName(); size++; exprName(); size++;
} while (match(TK(","))); } while (match(TK(",")));
if(size > 1) emitCode(OP_BUILD_SMART_TUPLE, size); if(size > 1) emitCode(OP_BUILD_SMART_TUPLE, size);
consume(TK("in")); }
EXPR_TUPLE();
emitCode(OP_GET_ITER); // [ptr, list] -> iter void compileForLoop() {
EXPR_FOR_VARS();consume(TK("in"));EXPR_TUPLE();
emitCode(OP_GET_ITER);
Loop& loop = enterLoop(true); Loop& loop = enterLoop(true);
int patch = emitCode(OP_FOR_ITER); int patch = emitCode(OP_FOR_ITER);
action(this); compileBlockBody();
emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine(); emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine();
patchJump(patch); patchJump(patch);
exitLoop(); exitLoop();
@ -698,7 +721,7 @@ __LISTCOMP:
} else if (match(TK("while"))) { } else if (match(TK("while"))) {
compileWhileLoop(); compileWhileLoop();
} else if (match(TK("for"))) { } else if (match(TK("for"))) {
__compileForLoop(&Compiler::compileBlockBody); compileForLoop();
} else if(match(TK("assert"))){ } else if(match(TK("assert"))){
EXPR(); EXPR();
emitCode(OP_ASSERT); emitCode(OP_ASSERT);