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 {
NO_BLOCK,
FOR_LOOP,
WHILE_LOOP,
CONTEXT_MANAGER,
TRY_EXCEPT,
};
@ -39,6 +40,9 @@ struct CodeBlock {
std::vector<int> id;
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 {
if(parent == -1) return "";
std::string s = "[";
@ -87,6 +91,9 @@ struct CodeObject {
// tmp variables
int _currBlockIndex = 0;
bool __isCurrBlockLoop() const {
return co_blocks[_currBlockIndex].type == FOR_LOOP || co_blocks[_currBlockIndex].type == WHILE_LOOP;
}
void __enterBlock(CodeBlockType type){
const CodeBlock& currBlock = co_blocks[_currBlockIndex];
@ -99,11 +106,12 @@ struct CodeObject {
if(it == co_blocks.end()) break;
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;
}
void __exitBlock(){
co_blocks[_currBlockIndex].end = co_code.size();
_currBlockIndex = co_blocks[_currBlockIndex].parent;
if(_currBlockIndex < 0) UNREACHABLE();
}

View File

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

View File

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

View File

@ -13,7 +13,7 @@ constexpr const char* __TOKENS[] = {
"+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=",
/** KW_BEGIN **/
"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
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise",
/** KW_END **/

View File

@ -279,9 +279,20 @@ protected:
PyRef_AS_C(it->var)->set(this, frame, it->next());
}
else{
frame->jumpAbsoluteSafe(byte.arg);
int blockEnd = frame->code->co_blocks[byte.block].end;
frame->jumpAbsoluteSafe(blockEnd);
}
} 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:
{
const PyVar expr = frame->topValue(this);
@ -546,11 +557,7 @@ public:
if(_module == nullptr) _module = _main;
try {
_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, {});
}catch (const _Error& e){
*_stderr << e.what() << '\n';