Now you can break, continue and return in try statements

This commit is contained in:
2025-05-17 19:26:49 -05:00
parent bb19d2444c
commit 4beb22cef4
5 changed files with 150 additions and 8 deletions

View File

@ -115,8 +115,6 @@ do(conditionLikeIf)
#### Try statement #### Try statement
Note: you can't yield, return, break or continue from inside a try statement (also applys to catch and finally due to these being internally closures)
```js ```js
try { try {
Console.WriteLine("God is good."); Console.WriteLine("God is good.");

View File

@ -659,7 +659,11 @@ typedef enum {
YIELD, YIELD,
PUSHROOTPATH, PUSHROOTPATH,
PUSHRELATIVEPATH, PUSHRELATIVEPATH,
BREAKPOINT BREAKPOINT,
PUSHBREAK,
PUSHCONTINUE,
JMPIFBREAK,
JMPIFCONTINUE
} Instruction; } Instruction;
/** /**
* @brief Base type for bytecode instruction * @brief Base type for bytecode instruction
@ -1344,6 +1348,9 @@ class Parser {
} }
}; };
//this is a dummy type with //this is a dummy type with
class MethodInvoker { class MethodInvoker {
@ -1358,11 +1365,19 @@ class Parser {
Tesses::Framework::Date::DateTime& GetDate(); Tesses::Framework::Date::DateTime& GetDate();
~TDateTime(); ~TDateTime();
}; };
class TBreak {
};
class TContinue {
};
/** /**
* @brief A script object * @brief A script object
* *
*/ */
using TObject = std::variant<int64_t,double,char,bool,std::string,std::regex,Tesses::Framework::Filesystem::VFSPath,std::nullptr_t,Undefined,MethodInvoker,THeapObjectHolder,TVMVersion,TDateTime>;
using TObject = std::variant<int64_t,double,char,bool,std::string,std::regex,Tesses::Framework::Filesystem::VFSPath,std::nullptr_t,Undefined,MethodInvoker,THeapObjectHolder,TVMVersion,TDateTime,TBreak,TContinue>;
class TRootEnvironment; class TRootEnvironment;
class GC; class GC;
class GC { class GC {
@ -2072,6 +2087,10 @@ class GC {
bool Dup(GC* gc); bool Dup(GC* gc);
bool Nop(GC* gc); bool Nop(GC* gc);
bool Breakpoint(GC* gc); bool Breakpoint(GC* gc);
bool PushBreak(GC* gc);
bool PushContinue(GC* gc);
bool JumpIfBreak(GC* gc);
bool JumpIfContinue(GC* gc);
public: public:
static InterperterThread* Create(GCList* ls); static InterperterThread* Create(GCList* ls);
static InterperterThread* Create(GCList& ls); static InterperterThread* Create(GCList& ls);

View File

@ -991,6 +991,11 @@ namespace Tesses::CrossLang
{ {
std::cout << "WARN: continue does nothing here\n"; std::cout << "WARN: continue does nothing here\n";
} }
else if(contscope == -2)
{
instructions.push_back(new SimpleInstruction(PUSHCONTINUE));
instructions.push_back(new SimpleInstruction(RET));
}
else else
{ {
auto cont = scope-contscope; auto cont = scope-contscope;
@ -1009,6 +1014,11 @@ namespace Tesses::CrossLang
{ {
std::cout << "WARN: break does nothing here\n"; std::cout << "WARN: break does nothing here\n";
} }
else if(brkscope == -2)
{
instructions.push_back(new SimpleInstruction(PUSHBREAK));
instructions.push_back(new SimpleInstruction(RET));
}
else else
{ {
auto _brk = scope-brkscope; auto _brk = scope-brkscope;
@ -1223,17 +1233,63 @@ namespace Tesses::CrossLang
} }
if(std::holds_alternative<AdvancedSyntaxNode>(adv.nodes[0]) && std::holds_alternative<AdvancedSyntaxNode>(adv.nodes[1]) && std::holds_alternative<AdvancedSyntaxNode>(adv.nodes[2])) if(std::holds_alternative<AdvancedSyntaxNode>(adv.nodes[0]) && std::holds_alternative<AdvancedSyntaxNode>(adv.nodes[1]) && std::holds_alternative<AdvancedSyntaxNode>(adv.nodes[2]))
{ {
GenNode(instructions,AdvancedSyntaxNode::Create(ScopelessClosureExpression,true,{AdvancedSyntaxNode::Create(ParenthesesExpression,true,{}),adv.nodes[0]}),scope,contscope,brkscope,contI,brkI); GenNode(instructions,AdvancedSyntaxNode::Create(ScopelessClosureExpression,true,{AdvancedSyntaxNode::Create(ParenthesesExpression,true,{}),adv.nodes[0]}),scope,contscope == -1 ? -1 : -2,brkscope == -1 ? -1 : -2,contI,brkI);
GenNode(instructions,AdvancedSyntaxNode::Create(ScopelessClosureExpression,true,{ GenNode(instructions,AdvancedSyntaxNode::Create(ScopelessClosureExpression,true,{
AdvancedSyntaxNode::Create(ParenthesesExpression,true,{adv.nodes[2]}), AdvancedSyntaxNode::Create(ParenthesesExpression,true,{adv.nodes[2]}),
adv.nodes[1] adv.nodes[1]
}),scope,contscope,brkscope,contI,brkI); }),scope,contscope == -1 ? -1 : -2,brkscope == -1 ? -1 : -2,contI,brkI);
instructions.push_back(new SimpleInstruction(TRYCATCH)); instructions.push_back(new SimpleInstruction(TRYCATCH));
uint32_t compGenId = NewId(); uint32_t compGenId = NewId();
std::string compGenIttr = "__compGenRetThing"; std::string compGenIttr = "__compGenRetThing";
compGenIttr.append(std::to_string(compGenId)); compGenIttr.append(std::to_string(compGenId));
if(contscope != -1)
{
instructions.push_back(new JumpStyleInstruction(JMPIFCONTINUE,compGenIttr+"_cont"));
}
if(brkscope != -1)
{
instructions.push_back(new JumpStyleInstruction(JMPIFBREAK,compGenIttr+"_brk"));
}
instructions.push_back(new JumpStyleInstruction(JMPUNDEFINED, compGenIttr)); instructions.push_back(new JumpStyleInstruction(JMPUNDEFINED, compGenIttr));
instructions.push_back(new SimpleInstruction(RET)); instructions.push_back(new SimpleInstruction(RET));
if(contscope == -2)
{
instructions.push_back(new LabelInstruction(compGenIttr+"_cont"));
instructions.push_back(new SimpleInstruction(PUSHCONTINUE));
instructions.push_back(new SimpleInstruction(RET));
}
else if(contscope != -1)
{
instructions.push_back(new LabelInstruction(compGenIttr+"_cont"));
auto cont = scope-contscope;
if(cont > 0)
instructions.push_back(new ScopeEndTimesInstruction((uint32_t)cont));
std::string myJmp = "__compGenCont";
myJmp.append(std::to_string(contI));
instructions.push_back(new JumpStyleInstruction(JMP,myJmp));
}
if(brkscope == -2)
{
instructions.push_back(new LabelInstruction(compGenIttr+"_brk"));
instructions.push_back(new SimpleInstruction(PUSHBREAK));
instructions.push_back(new SimpleInstruction(RET));
}
else if(brkscope != -1)
{
instructions.push_back(new LabelInstruction(compGenIttr+"_brk"));
auto _brk = scope-brkscope;
if(_brk > 0)
instructions.push_back(new ScopeEndTimesInstruction((uint32_t)_brk));
std::string myJmp = "__compGenBrk";
myJmp.append(std::to_string(brkI));
instructions.push_back(new JumpStyleInstruction(JMP,myJmp));
}
instructions.push_back(new LabelInstruction(compGenIttr)); instructions.push_back(new LabelInstruction(compGenIttr));
} }
@ -1264,7 +1320,7 @@ namespace Tesses::CrossLang
} }
GenNode(fnInstructions,body,0,-1,-1,-1,-1); GenNode(fnInstructions,body,0,contscope == -2 ? -2 : -1,brkscope == -2 ? -2 : -1,-1,-1);
this->chunks[fnindex] = std::pair<std::vector<uint32_t>,std::vector<ByteCodeInstruction*>>(args, fnInstructions); this->chunks[fnindex] = std::pair<std::vector<uint32_t>,std::vector<ByteCodeInstruction*>>(args, fnInstructions);
instructions.push_back(new ClosureInstruction((uint32_t)fnindex,false)); instructions.push_back(new ClosureInstruction((uint32_t)fnindex,false));

View File

@ -5153,6 +5153,57 @@ namespace Tesses::CrossLang {
} }
return false; return false;
} }
bool InterperterThread::JumpIfBreak(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
auto stk = cse.back();
if(stk->ip + 4 <= stk->callable->closure->code.size())
{
uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]);
GCList ls(gc);
auto _res2 = stk->Pop(ls);
stk->ip = stk->ip + 4;
if(std::holds_alternative<TBreak>(_res2))
stk->ip = n;
else
stk->Push(gc,_res2);
}
else
throw VMException("Can't read jmpifbreak pc.");
return false;
}
bool InterperterThread::JumpIfContinue(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
auto stk = cse.back();
if(stk->ip + 4 <= stk->callable->closure->code.size())
{
uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]);
GCList ls(gc);
auto _res2 = stk->Pop(ls);
stk->ip = stk->ip + 4;
if(std::holds_alternative<TContinue>(_res2))
stk->ip = n;
else
stk->Push(gc,_res2);
}
else
throw VMException("Can't read jmpifcontinue pc.");
return false;
}
bool InterperterThread::JumpUndefined(GC* gc) bool InterperterThread::JumpUndefined(GC* gc)
{ {
@ -5201,6 +5252,24 @@ namespace Tesses::CrossLang {
stk->Push(gc,nullptr); stk->Push(gc,nullptr);
return false; return false;
}
bool InterperterThread::PushBreak(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
auto stk = cse.back();
stk->Push(gc,TBreak());
return false;
}
bool InterperterThread::PushContinue(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
auto stk = cse.back();
stk->Push(gc,TContinue());
return false;
} }
bool InterperterThread::PushUndefined(GC* gc) bool InterperterThread::PushUndefined(GC* gc)
{ {

File diff suppressed because one or more lines are too long