Support break statements
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
46197e0a6e
commit
3367e60ae5
|
@ -48,6 +48,9 @@ namespace Porygon::Binder {
|
|||
return this->BindNumericalForStatement(statement);
|
||||
case ParsedStatementKind::GenericFor:
|
||||
return this -> BindGenericForStatement(statement);
|
||||
case ParsedStatementKind::Break:
|
||||
//TODO: Validate we're in a loop
|
||||
return new BoundBreakStatement();
|
||||
case ParsedStatementKind::Bad:
|
||||
return new BoundBadStatement();
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace Porygon::Binder {
|
|||
Conditional,
|
||||
NumericalFor,
|
||||
GenericFor,
|
||||
Break,
|
||||
};
|
||||
|
||||
class BoundStatement {
|
||||
|
@ -38,6 +39,13 @@ namespace Porygon::Binder {
|
|||
}
|
||||
};
|
||||
|
||||
class BoundBreakStatement : public BoundStatement {
|
||||
public:
|
||||
const BoundStatementKind GetKind() const final {
|
||||
return BoundStatementKind::Break;
|
||||
}
|
||||
};
|
||||
|
||||
class BoundBlockStatement : public BoundStatement {
|
||||
const vector<BoundStatement *> _statements;
|
||||
public:
|
||||
|
|
|
@ -48,7 +48,9 @@ namespace Porygon::Evaluation {
|
|||
return this->EvaluateNumericalForStatement((BoundNumericalForStatement*)statement);
|
||||
case BoundStatementKind::GenericFor:
|
||||
return this-> EvaluateGenericForStatement((BoundGenericForStatement*)statement);
|
||||
|
||||
case BoundStatementKind::Break:
|
||||
this -> _hasBroken = true;
|
||||
return;
|
||||
case BoundStatementKind::Bad:
|
||||
throw;
|
||||
}
|
||||
|
@ -138,20 +140,25 @@ namespace Porygon::Evaluation {
|
|||
this -> _evaluationScope -> SetVariable(identifier, make_shared<IntegerEvalValue>(i));
|
||||
for (auto s: *block->GetStatements()) {
|
||||
this->EvaluateStatement(s);
|
||||
if (this->_hasReturned)
|
||||
if (this->_hasReturned || this -> _hasBroken)
|
||||
break;
|
||||
}
|
||||
if (this->_hasReturned || this -> _hasBroken)
|
||||
break;
|
||||
}
|
||||
} else{
|
||||
for (long i = start; i >= end; i += step){
|
||||
this -> _evaluationScope -> SetVariable(identifier, make_shared<IntegerEvalValue>(i));
|
||||
for (auto s: *block->GetStatements()) {
|
||||
this->EvaluateStatement(s);
|
||||
if (this->_hasReturned)
|
||||
if (this->_hasReturned || this -> _hasBroken)
|
||||
break;
|
||||
}
|
||||
if (this->_hasReturned || this -> _hasBroken)
|
||||
break;
|
||||
}
|
||||
}
|
||||
this -> _hasBroken = false;
|
||||
}
|
||||
|
||||
void Evaluator::EvaluateGenericForStatement(const BoundGenericForStatement *statement) {
|
||||
|
@ -172,8 +179,15 @@ namespace Porygon::Evaluation {
|
|||
auto currentValue = iteratorVal -> IndexValue(currentKey.get());
|
||||
this -> _evaluationScope -> SetVariable(valueVariable, currentValue);
|
||||
}
|
||||
this -> EvaluateBlockStatement(block);
|
||||
for (auto s: *block->GetStatements()) {
|
||||
this->EvaluateStatement(s);
|
||||
if (this->_hasReturned || this -> _hasBroken)
|
||||
break;
|
||||
}
|
||||
if (this->_hasReturned || this -> _hasBroken)
|
||||
break;
|
||||
}
|
||||
this -> _hasBroken = false;
|
||||
delete iterator;
|
||||
}
|
||||
|
||||
|
@ -433,7 +447,7 @@ namespace Porygon::Evaluation {
|
|||
auto type = dynamic_pointer_cast<TableScriptType>(tableExpression->GetType());
|
||||
auto declaredVars = type->GetValues();
|
||||
auto variables = make_shared<map<Utilities::HashedString, shared_ptr<EvalValue>>>();
|
||||
for (auto i : *declaredVars) {
|
||||
for (const auto& i : *declaredVars) {
|
||||
variables->insert({i.first, nullptr});
|
||||
}
|
||||
auto evaluator = make_shared<EvaluationScope>(variables.get(), type->GetLocalVariableCount());
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace Porygon::Evaluation{
|
|||
shared_ptr<EvalValue> _returnValue;
|
||||
map<Utilities::HashedString, shared_ptr<EvalValue>>* _scriptVariables;
|
||||
bool _hasReturned;
|
||||
bool _hasBroken;
|
||||
shared_ptr<EvalValue> _lastValue;
|
||||
|
||||
//Porygon::Script* _scriptData;
|
||||
|
@ -60,6 +61,7 @@ namespace Porygon::Evaluation{
|
|||
explicit Evaluator(map<Utilities::HashedString, shared_ptr<EvalValue>>* scriptVariables){
|
||||
_scriptVariables = scriptVariables;
|
||||
_hasReturned = false;
|
||||
_hasBroken = false;
|
||||
_returnValue = nullptr;
|
||||
_evaluationScope = nullptr;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@ namespace Porygon::Parser {
|
|||
Return,
|
||||
Conditional,
|
||||
NumericalFor,
|
||||
GenericFor
|
||||
GenericFor,
|
||||
Break
|
||||
};
|
||||
|
||||
class ParsedStatement {
|
||||
|
@ -59,6 +60,15 @@ namespace Porygon::Parser {
|
|||
}
|
||||
};
|
||||
|
||||
class ParsedBreakStatement : public ParsedStatement{
|
||||
public:
|
||||
ParsedBreakStatement(unsigned int start, unsigned int length) : ParsedStatement(start, length) {};
|
||||
|
||||
const ParsedStatementKind GetKind() const final {
|
||||
return ParsedStatementKind::Break;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedBlockStatement : public ParsedStatement {
|
||||
const std::vector<const ParsedStatement *> _statements;
|
||||
public:
|
||||
|
|
|
@ -45,7 +45,9 @@ namespace Porygon::Parser {
|
|||
case TokenKind::IfKeyword:
|
||||
return this->ParseIfStatement(current);
|
||||
case TokenKind ::ForKeyword:
|
||||
return this->ParseForStatement(current);
|
||||
return this->ParseForStatement();
|
||||
case TokenKind ::BreakKeyword:
|
||||
return new ParsedBreakStatement(current->GetStartPosition(), current -> GetLength());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -225,7 +227,7 @@ namespace Porygon::Parser {
|
|||
return new ParsedConditionalStatement(condition, block, start, block->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
ParsedStatement *Parser::ParseForStatement(const IToken *current) {
|
||||
ParsedStatement *Parser::ParseForStatement() {
|
||||
auto identifier = this -> Next();
|
||||
if (this -> Peek()->GetKind() == TokenKind::AssignmentToken){
|
||||
return ParseNumericForStatement(identifier);
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace Porygon::Parser {
|
|||
|
||||
ParsedStatement *ParseIfStatement(const IToken *current);
|
||||
|
||||
ParsedStatement *ParseForStatement(const IToken *current);
|
||||
ParsedStatement *ParseForStatement();
|
||||
ParsedStatement *ParseNumericForStatement(const IToken *current);
|
||||
ParsedStatement *ParseGenericForStatement(const IToken *current);
|
||||
|
||||
|
|
|
@ -60,6 +60,22 @@ end
|
|||
delete script;
|
||||
}
|
||||
|
||||
TEST_CASE( "Numerical for loop, break", "[integration]" ) {
|
||||
auto script = Script::Create(uR"(
|
||||
result = 0
|
||||
for i = 0,5 do
|
||||
if i > 3 then break end
|
||||
result = result + i
|
||||
end
|
||||
)");
|
||||
REQUIRE(!script->Diagnostics -> HasErrors());
|
||||
script->Evaluate();
|
||||
auto var = script->GetVariable(u"result");
|
||||
REQUIRE(var->EvaluateInteger() == 6);
|
||||
delete script;
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "Generic for loop over simple numerical table, get keys", "[integration]" ) {
|
||||
auto script = Script::Create(uR"(
|
||||
local table = {1, 3, 5, 7, 9}
|
||||
|
@ -90,5 +106,21 @@ end
|
|||
delete script;
|
||||
}
|
||||
|
||||
TEST_CASE( "Generic for loop over simple numerical table, break", "[integration]" ) {
|
||||
auto script = Script::Create(uR"(
|
||||
local table = {1, 3, 5, 7, 9}
|
||||
result = 0
|
||||
for i,v in table do
|
||||
if i > 3 then break end
|
||||
result = result + v
|
||||
end
|
||||
)");
|
||||
REQUIRE(!script->Diagnostics -> HasErrors());
|
||||
script->Evaluate();
|
||||
auto var = script->GetVariable(u"result");
|
||||
REQUIRE(var->EvaluateInteger() == 9);
|
||||
delete script;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue