implement break/continue in bytecode

master
Daniel Kolesa 2016-09-15 02:12:22 +02:00
parent b05bc51b14
commit 38c17d1911
4 changed files with 39 additions and 17 deletions

View File

@ -1587,6 +1587,12 @@ compilecomv:
}
}
break;
case CsIdBreak:
gs.code.push(CsCodeBreak | CsCodeFlagFalse);
break;
case CsIdContinue:
gs.code.push(CsCodeBreak | CsCodeFlagTrue);
break;
case CsIdResult:
if (more) {
more = compilearg(gs, CsValAny, prevargs);

View File

@ -734,6 +734,20 @@ static ostd::Uint32 *runcode(CsState &cs, ostd::Uint32 *code, CsValue &result) {
}
continue;
}
case CsCodeBreak | CsCodeFlagFalse:
if (cs.is_in_loop()) {
throw CsBreakException();
} else {
throw CsErrorException(cs, "no loop to break");
}
break;
case CsCodeBreak | CsCodeFlagTrue:
if (cs.is_in_loop()) {
throw CsContinueException();
} else {
throw CsErrorException(cs, "no loop to continue");
}
break;
case CsCodeMacro: {
ostd::Uint32 len = op >> 8;

View File

@ -21,7 +21,8 @@ static constexpr int DbgaliasIdx = MaxArguments + 2;
enum {
CsIdUnknown = -1, CsIdIvar, CsIdFvar, CsIdSvar, CsIdCommand, CsIdAlias,
CsIdLocal, CsIdDo, CsIdDoArgs, CsIdIf, CsIdResult, CsIdNot, CsIdAnd, CsIdOr
CsIdLocal, CsIdDo, CsIdDoArgs, CsIdIf, CsIdBreak, CsIdContinue, CsIdResult,
CsIdNot, CsIdAnd, CsIdOr
};
struct CsIdentLink {
@ -76,6 +77,7 @@ enum {
CsCodeLocal,
CsCodeDo, CsCodeDoArgs,
CsCodeJump, CsCodeJumpB, CsCodeJumpResult,
CsCodeBreak,
CsCodeOpMask = 0x3F,
CsCodeRet = 6,

View File

@ -332,6 +332,22 @@ CsState::CsState(CsAllocCb func, void *data):
new_command("local", nullptr, nullptr)->p_type = CsIdLocal;
new_command("break", "", [](auto &cs, auto, auto &) {
if (cs.is_in_loop()) {
throw CsBreakException();
} else {
throw CsErrorException(cs, "no loop to break");
}
})->p_type = CsIdBreak;
new_command("continue", "", [](auto &cs, auto, auto &) {
if (cs.is_in_loop()) {
throw CsContinueException();
} else {
throw CsErrorException(cs, "no loop to continue");
}
})->p_type = CsIdContinue;
cs_init_lib_base(*this);
}
@ -1113,22 +1129,6 @@ void cs_init_lib_base(CsState &gcs) {
}
});
gcs.new_command("break", "", [](auto &cs, auto, auto &) {
if (cs.is_in_loop()) {
throw CsBreakException();
} else {
throw CsErrorException(cs, "no loop to break");
}
});
gcs.new_command("continue", "", [](auto &cs, auto, auto &) {
if (cs.is_in_loop()) {
throw CsContinueException();
} else {
throw CsErrorException(cs, "no loop to continue");
}
});
gcs.new_command("?", "tTT", [](auto &, auto args, auto &res) {
if (args[0].get_bool()) {
res = ostd::move(args[1]);