reimpl break/continue

This commit is contained in:
blueloveTH 2023-01-05 19:41:51 +08:00
parent a4c2cc5605
commit 4bb967d426
5 changed files with 65 additions and 55 deletions

View File

@ -30,6 +30,7 @@ _Str pad(const _Str& s, const int n){
enum CodeBlockType { enum CodeBlockType {
NO_BLOCK, NO_BLOCK,
FOR_LOOP, FOR_LOOP,
WHILE_LOOP,
CONTEXT_MANAGER, CONTEXT_MANAGER,
TRY_EXCEPT, TRY_EXCEPT,
}; };
@ -39,6 +40,9 @@ struct CodeBlock {
std::vector<int> id; std::vector<int> id;
int parent; // parent index in co_blocks int parent; // parent index in co_blocks
int start; // start index of this block in co_code, inclusive
int end; // end index of this block in co_code, exclusive
std::string toString() const { std::string toString() const {
if(parent == -1) return ""; if(parent == -1) return "";
std::string s = "["; std::string s = "[";
@ -87,6 +91,9 @@ struct CodeObject {
// tmp variables // tmp variables
int _currBlockIndex = 0; int _currBlockIndex = 0;
bool __isCurrBlockLoop() const {
return co_blocks[_currBlockIndex].type == FOR_LOOP || co_blocks[_currBlockIndex].type == WHILE_LOOP;
}
void __enterBlock(CodeBlockType type){ void __enterBlock(CodeBlockType type){
const CodeBlock& currBlock = co_blocks[_currBlockIndex]; const CodeBlock& currBlock = co_blocks[_currBlockIndex];
@ -99,11 +106,12 @@ struct CodeObject {
if(it == co_blocks.end()) break; if(it == co_blocks.end()) break;
t++; t++;
} }
co_blocks.push_back(CodeBlock{type, copy, _currBlockIndex}); co_blocks.push_back(CodeBlock{type, copy, _currBlockIndex, (int)co_code.size()});
_currBlockIndex = co_blocks.size()-1; _currBlockIndex = co_blocks.size()-1;
} }
void __exitBlock(){ void __exitBlock(){
co_blocks[_currBlockIndex].end = co_code.size();
_currBlockIndex = co_blocks[_currBlockIndex].parent; _currBlockIndex = co_blocks[_currBlockIndex].parent;
if(_currBlockIndex < 0) UNREACHABLE(); if(_currBlockIndex < 0) UNREACHABLE();
} }

View File

@ -15,19 +15,12 @@ struct GrammarRule{
Precedence precedence; Precedence precedence;
}; };
struct Loop {
int start;
std::vector<int> breaks;
Loop(int start) : start(start) {}
};
enum StringType { NORMAL_STRING, RAW_STRING, F_STRING }; enum StringType { NORMAL_STRING, RAW_STRING, F_STRING };
class Compiler { class Compiler {
public: public:
pkpy::unique_ptr<Parser> parser; pkpy::unique_ptr<Parser> parser;
std::stack<_Code> codes; std::stack<_Code> codes;
std::stack<Loop> loops;
bool isCompilingClass = false; bool isCompilingClass = false;
int lexingCnt = 0; int lexingCnt = 0;
VM* vm; VM* vm;
@ -42,10 +35,6 @@ public:
return parser->src->mode; return parser->src->mode;
} }
Loop& getLoop() {
return loops.top();
}
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->parser = pkpy::make_unique<Parser>( this->parser = pkpy::make_unique<Parser>(
@ -575,8 +564,8 @@ __LISTCOMP:
patchJump(_skipPatch); patchJump(_skipPatch);
emitCode(OP_GET_ITER); emitCode(OP_GET_ITER);
Loop& loop = enterLoop(); getCode()->__enterBlock(FOR_LOOP); getCode()->__enterBlock(FOR_LOOP);
int patch = emitCode(OP_FOR_ITER); emitCode(OP_FOR_ITER);
if(_cond_end_return != -1) { // there is an if condition if(_cond_end_return != -1) { // there is an if condition
emitCode(OP_JUMP_ABSOLUTE, _cond_start); emitCode(OP_JUMP_ABSOLUTE, _cond_start);
@ -592,9 +581,8 @@ __LISTCOMP:
emitCode(OP_LIST_APPEND); emitCode(OP_LIST_APPEND);
} }
emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine(); emitCode(OP_LOOP_CONTINUE); keepOpcodeLine();
patchJump(patch); getCode()->__exitBlock();
exitLoop(); getCode()->__exitBlock();
matchNewLines(mode()==SINGLE_MODE); matchNewLines(mode()==SINGLE_MODE);
consume(TK("]")); consume(TK("]"));
} }
@ -817,26 +805,14 @@ __LISTCOMP:
} }
} }
Loop& enterLoop(){
Loop lp((int)getCode()->co_code.size());
loops.push(lp);
return loops.top();
}
void exitLoop(){
Loop& lp = loops.top();
for(int addr : lp.breaks) patchJump(addr);
loops.pop();
}
void compileWhileLoop() { void compileWhileLoop() {
Loop& loop = enterLoop(); getCode()->__enterBlock(WHILE_LOOP);
EXPR_TUPLE(); 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_LOOP_CONTINUE); keepOpcodeLine();
patchJump(patch); patchJump(patch);
exitLoop(); getCode()->__exitBlock();
} }
void EXPR_FOR_VARS(){ void EXPR_FOR_VARS(){
@ -851,24 +827,42 @@ __LISTCOMP:
void compileForLoop() { void compileForLoop() {
EXPR_FOR_VARS();consume(TK("in")); EXPR_TUPLE(); EXPR_FOR_VARS();consume(TK("in")); EXPR_TUPLE();
emitCode(OP_GET_ITER); emitCode(OP_GET_ITER);
Loop& loop = enterLoop(); getCode()->__enterBlock(FOR_LOOP); getCode()->__enterBlock(FOR_LOOP);
int patch = emitCode(OP_FOR_ITER); emitCode(OP_FOR_ITER);
compileBlockBody(); compileBlockBody();
emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine(); emitCode(OP_LOOP_CONTINUE); keepOpcodeLine();
getCode()->__exitBlock();
}
void compileTryExcept() {
getCode()->__enterBlock(TRY_EXCEPT);
compileBlockBody();
getCode()->__exitBlock();
int patch = emitCode(OP_JUMP_ABSOLUTE);
consume(TK("except"));
if(match(TK("@id"))){ // exception name
if(match(TK("as"))){ // exception name as alias
consume(TK("@id"));
exprName();
}
compileBlockBody();
}
if(match(TK("finally"))){
consume(TK(":"));
syntaxError("finally is not supported yet");
}
patchJump(patch); patchJump(patch);
exitLoop(); getCode()->__exitBlock();
} }
void compileStatement() { void compileStatement() {
if (match(TK("break"))) { if (match(TK("break"))) {
if (loops.empty()) syntaxError("'break' outside loop"); if (!getCode()->__isCurrBlockLoop()) syntaxError("'break' outside loop");
consumeEndStatement(); consumeEndStatement();
int patch = emitCode(OP_SAFE_JUMP_ABSOLUTE); emitCode(OP_LOOP_BREAK);
getLoop().breaks.push_back(patch);
} else if (match(TK("continue"))) { } else if (match(TK("continue"))) {
if (loops.empty()) syntaxError("'continue' not properly in loop"); if (!getCode()->__isCurrBlockLoop()) syntaxError("'continue' not properly in loop");
consumeEndStatement(); consumeEndStatement();
emitCode(OP_JUMP_ABSOLUTE, getLoop().start); emitCode(OP_LOOP_CONTINUE);
} else if (match(TK("return"))) { } else if (match(TK("return"))) {
if (codes.size() == 1) if (codes.size() == 1)
syntaxError("'return' outside function"); syntaxError("'return' outside function");
@ -885,7 +879,9 @@ __LISTCOMP:
compileWhileLoop(); compileWhileLoop();
} else if (match(TK("for"))) { } else if (match(TK("for"))) {
compileForLoop(); compileForLoop();
} else if(match(TK("assert"))){ } else if (match(TK("try"))) {
compileTryExcept();
}else if(match(TK("assert"))){
EXPR(); EXPR();
emitCode(OP_ASSERT); emitCode(OP_ASSERT);
consumeEndStatement(); consumeEndStatement();
@ -937,13 +933,10 @@ __LISTCOMP:
} else { } else {
EXPR_ANY(); EXPR_ANY();
consumeEndStatement(); consumeEndStatement();
// If last op is not an assignment, pop the result. // If last op is not an assignment, pop the result.
uint8_t lastOp = getCode()->co_code.back().op; uint8_t lastOp = getCode()->co_code.back().op;
if( lastOp != OP_STORE_NAME_REF && lastOp != OP_STORE_REF){ if( lastOp!=OP_STORE_NAME_REF && lastOp!=OP_STORE_REF){
if(mode()==SINGLE_MODE && parser->indents.top() == 0){ if(mode()==SINGLE_MODE && parser->indents.top()==0) emitCode(OP_PRINT_EXPR);
emitCode(OP_PRINT_EXPR);
}
emitCode(OP_POP_TOP); emitCode(OP_POP_TOP);
} }
} }
@ -962,7 +955,6 @@ __LISTCOMP:
isCompilingClass = true; isCompilingClass = true;
__compileBlockBody(&Compiler::compileFunction); __compileBlockBody(&Compiler::compileFunction);
isCompilingClass = false; isCompilingClass = false;
if(superClsNameIdx == -1) emitCode(OP_LOAD_NONE); if(superClsNameIdx == -1) emitCode(OP_LOAD_NONE);
else emitCode(OP_LOAD_NAME_REF, superClsNameIdx); else emitCode(OP_LOAD_NAME_REF, superClsNameIdx);
emitCode(OP_BUILD_CLASS, clsNameIdx); emitCode(OP_BUILD_CLASS, clsNameIdx);

View File

@ -76,4 +76,7 @@ OPCODE(JUMP_RELATIVE)
OPCODE(RAISE_VARARGS) OPCODE(RAISE_VARARGS)
OPCODE(LOOP_BREAK)
OPCODE(LOOP_CONTINUE)
#endif #endif

View File

@ -13,7 +13,7 @@ constexpr const char* __TOKENS[] = {
"+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=", "+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=",
/** KW_BEGIN **/ /** KW_BEGIN **/
"class", "import", "as", "def", "lambda", "pass", "del", "from", "with", "class", "import", "as", "def", "lambda", "pass", "del", "from", "with",
"None", "in", "is", "and", "or", "not", "True", "False", "global", "None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
"goto", "label", // extended keywords, not available in cpython "goto", "label", // extended keywords, not available in cpython
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise", "while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise",
/** KW_END **/ /** KW_END **/

View File

@ -279,9 +279,20 @@ protected:
PyRef_AS_C(it->var)->set(this, frame, it->next()); PyRef_AS_C(it->var)->set(this, frame, it->next());
} }
else{ else{
frame->jumpAbsoluteSafe(byte.arg); int blockEnd = frame->code->co_blocks[byte.block].end;
frame->jumpAbsoluteSafe(blockEnd);
} }
} break; } break;
case OP_LOOP_CONTINUE:
{
int blockStart = frame->code->co_blocks[byte.block].start;
frame->jumpAbsolute(blockStart);
} break;
case OP_LOOP_BREAK:
{
int blockEnd = frame->code->co_blocks[byte.block].end;
frame->jumpAbsoluteSafe(blockEnd);
} break;
case OP_JUMP_IF_FALSE_OR_POP: case OP_JUMP_IF_FALSE_OR_POP:
{ {
const PyVar expr = frame->topValue(this); const PyVar expr = frame->topValue(this);
@ -546,11 +557,7 @@ public:
if(_module == nullptr) _module = _main; if(_module == nullptr) _module = _main;
try { try {
_Code code = compile(source, filename, mode); _Code code = compile(source, filename, mode);
// if(filename != "<builtins>") std::cout << disassemble(code) << std::endl;
if(filename != "<builtins>"){
std::cout << disassemble(code) << std::endl;
}
return _exec(code, _module, {}); return _exec(code, _module, {});
}catch (const _Error& e){ }catch (const _Error& e){
*_stderr << e.what() << '\n'; *_stderr << e.what() << '\n';