mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-23 04:50:17 +00:00
reimpl break/continue
This commit is contained in:
parent
a4c2cc5605
commit
4bb967d426
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -76,4 +76,7 @@ OPCODE(JUMP_RELATIVE)
|
|||||||
|
|
||||||
OPCODE(RAISE_VARARGS)
|
OPCODE(RAISE_VARARGS)
|
||||||
|
|
||||||
|
OPCODE(LOOP_BREAK)
|
||||||
|
OPCODE(LOOP_CONTINUE)
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -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 **/
|
||||||
|
19
src/vm.h
19
src/vm.h
@ -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';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user