Support break statements
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2019-06-27 15:55:46 +02:00
parent 46197e0a6e
commit 3367e60ae5
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
8 changed files with 80 additions and 9 deletions

View File

@ -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();
}

View File

@ -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:

View File

@ -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());

View File

@ -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;
}

View File

@ -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:

View File

@ -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);

View File

@ -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);

View File

@ -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