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