Implements numeric for loops
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
694b0ac0c0
commit
e472dcec1c
|
@ -44,7 +44,8 @@ namespace Porygon::Binder {
|
||||||
return this->BindReturnStatement(statement);
|
return this->BindReturnStatement(statement);
|
||||||
case ParsedStatementKind::Conditional:
|
case ParsedStatementKind::Conditional:
|
||||||
return this->BindConditionalStatement(statement);
|
return this->BindConditionalStatement(statement);
|
||||||
|
case ParsedStatementKind::NumericalFor:
|
||||||
|
return this->BindNumericalForStatement(statement);
|
||||||
case ParsedStatementKind::Bad:
|
case ParsedStatementKind::Bad:
|
||||||
return new BoundBadStatement();
|
return new BoundBadStatement();
|
||||||
}
|
}
|
||||||
|
@ -214,6 +215,48 @@ namespace Porygon::Binder {
|
||||||
return new BoundConditionalStatement(boundCondition, boundBlock, elseStatement);
|
return new BoundConditionalStatement(boundCondition, boundBlock, elseStatement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BoundStatement *Binder::BindNumericalForStatement(const ParsedStatement *statement) {
|
||||||
|
auto forStatement = (ParsedNumericalForStatement*) statement;
|
||||||
|
auto identifier = forStatement->GetIdentifier();
|
||||||
|
auto start = this -> BindExpression(forStatement->GetStart());
|
||||||
|
auto end = this -> BindExpression(forStatement->GetEnd());
|
||||||
|
auto parsedStep = forStatement -> GetStep();
|
||||||
|
BoundExpression* step = nullptr;
|
||||||
|
if (parsedStep != nullptr){
|
||||||
|
step = this -> BindExpression(parsedStep);
|
||||||
|
}
|
||||||
|
if (start -> GetType()->GetClass() != TypeClass::Number){
|
||||||
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber, start->GetStartPosition(),
|
||||||
|
start->GetLength());
|
||||||
|
return new BoundBadStatement();
|
||||||
|
}
|
||||||
|
if (end -> GetType()->GetClass() != TypeClass::Number){
|
||||||
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber, end->GetStartPosition(),
|
||||||
|
end->GetLength());
|
||||||
|
return new BoundBadStatement();
|
||||||
|
}
|
||||||
|
if (step != nullptr && step -> GetType()->GetClass() != TypeClass::Number){
|
||||||
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber, step->GetStartPosition(),
|
||||||
|
step->GetLength());
|
||||||
|
return new BoundBadStatement();
|
||||||
|
}
|
||||||
|
|
||||||
|
this -> _scope ->GoInnerScope();
|
||||||
|
auto variableKey = this -> _scope ->CreateExplicitLocal(identifier.GetHash(), make_shared<NumericScriptType>(true, false));
|
||||||
|
if (variableKey.GetResult() != VariableAssignmentResult::Ok){
|
||||||
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(),
|
||||||
|
statement->GetLength());
|
||||||
|
return new BoundBadStatement();
|
||||||
|
}
|
||||||
|
auto block = this -> BindBlockStatement(forStatement->GetBlock());
|
||||||
|
this -> _scope ->GoOuterScope();
|
||||||
|
return new BoundNumericalForStatement(variableKey.GetKey(), start, end, step, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
// Expressions //
|
||||||
|
/////////////////
|
||||||
|
|
||||||
BoundExpression *Binder::BindExpression(const ParsedExpression *expression) {
|
BoundExpression *Binder::BindExpression(const ParsedExpression *expression) {
|
||||||
switch (expression->GetKind()) {
|
switch (expression->GetKind()) {
|
||||||
case ParsedExpressionKind::LiteralInteger:
|
case ParsedExpressionKind::LiteralInteger:
|
||||||
|
@ -586,4 +629,5 @@ namespace Porygon::Binder {
|
||||||
return new BoundTableExpression((BoundBlockStatement *) block, tableType, expression->GetStartPosition(),
|
return new BoundTableExpression((BoundBlockStatement *) block, tableType, expression->GetStartPosition(),
|
||||||
expression->GetLength());
|
expression->GetLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,21 +18,19 @@ namespace Porygon::Binder {
|
||||||
|
|
||||||
~Binder();
|
~Binder();
|
||||||
|
|
||||||
|
// Statements
|
||||||
|
|
||||||
BoundStatement *BindStatement(const ParsedStatement *statement);
|
BoundStatement *BindStatement(const ParsedStatement *statement);
|
||||||
|
|
||||||
BoundStatement *BindBlockStatement(const ParsedStatement *statement);
|
BoundStatement *BindBlockStatement(const ParsedStatement *statement);
|
||||||
|
|
||||||
BoundStatement *BindExpressionStatement(const ParsedStatement *statement);
|
BoundStatement *BindExpressionStatement(const ParsedStatement *statement);
|
||||||
|
|
||||||
BoundStatement *BindAssignmentStatement(const ParsedStatement *statement);
|
BoundStatement *BindAssignmentStatement(const ParsedStatement *statement);
|
||||||
|
|
||||||
BoundStatement *BindIndexAssignmentStatement(const ParsedStatement *statement);
|
BoundStatement *BindIndexAssignmentStatement(const ParsedStatement *statement);
|
||||||
|
|
||||||
BoundStatement *BindFunctionDeclarationStatement(const ParsedStatement *statement);
|
BoundStatement *BindFunctionDeclarationStatement(const ParsedStatement *statement);
|
||||||
|
|
||||||
BoundStatement *BindReturnStatement(const ParsedStatement *statement);
|
BoundStatement *BindReturnStatement(const ParsedStatement *statement);
|
||||||
|
|
||||||
BoundStatement *BindConditionalStatement(const ParsedStatement *statement);
|
BoundStatement *BindConditionalStatement(const ParsedStatement *statement);
|
||||||
|
BoundStatement *BindNumericalForStatement(const ParsedStatement *statement);
|
||||||
|
|
||||||
|
// Expressions
|
||||||
|
|
||||||
BoundExpression *BindExpression(const ParsedExpression *expression);
|
BoundExpression *BindExpression(const ParsedExpression *expression);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef PORYGONLANG_BOUNDSTATEMENT_HPP
|
#ifndef PORYGONLANG_BOUNDSTATEMENT_HPP
|
||||||
#define PORYGONLANG_BOUNDSTATEMENT_HPP
|
#define PORYGONLANG_BOUNDSTATEMENT_HPP
|
||||||
|
@ -23,6 +20,7 @@ namespace Porygon::Binder {
|
||||||
FunctionDeclaration,
|
FunctionDeclaration,
|
||||||
Return,
|
Return,
|
||||||
Conditional,
|
Conditional,
|
||||||
|
NumericalFor,
|
||||||
};
|
};
|
||||||
|
|
||||||
class BoundStatement {
|
class BoundStatement {
|
||||||
|
@ -202,6 +200,53 @@ namespace Porygon::Binder {
|
||||||
return _elseStatement;
|
return _elseStatement;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BoundNumericalForStatement : public BoundStatement {
|
||||||
|
const BoundVariableKey* _identifier;
|
||||||
|
const BoundExpression *_start;
|
||||||
|
const BoundExpression *_end;
|
||||||
|
const BoundExpression *_step;
|
||||||
|
|
||||||
|
const BoundStatement *_block;
|
||||||
|
public:
|
||||||
|
explicit BoundNumericalForStatement(const BoundVariableKey* identifier, const BoundExpression *start,
|
||||||
|
const BoundExpression *end, const BoundExpression *step,
|
||||||
|
const BoundStatement *block)
|
||||||
|
: _identifier(identifier), _start(start), _end(end), _step(step), _block(block) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~BoundNumericalForStatement() final {
|
||||||
|
delete _identifier;
|
||||||
|
delete _start;
|
||||||
|
delete _end;
|
||||||
|
delete _step;
|
||||||
|
delete _block;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BoundStatementKind GetKind() const final {
|
||||||
|
return BoundStatementKind::NumericalFor;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BoundVariableKey* GetIdentifier() const{
|
||||||
|
return _identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BoundExpression* GetStart() const{
|
||||||
|
return _start;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BoundExpression* GetEnd() const{
|
||||||
|
return _end;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BoundExpression* GetStep() const{
|
||||||
|
return _step;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BoundStatement* GetBlock() const{
|
||||||
|
return _block;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,8 @@ namespace Porygon::Diagnostics {
|
||||||
InvalidTableValueType,
|
InvalidTableValueType,
|
||||||
InvalidTypeName,
|
InvalidTypeName,
|
||||||
UserDataFieldNoGetter,
|
UserDataFieldNoGetter,
|
||||||
UserDataFieldNoSetter
|
UserDataFieldNoSetter,
|
||||||
|
NumericalForArgumentNotANumber
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif //PORYGONLANG_DIAGNOSTICCODE_HPP
|
#endif //PORYGONLANG_DIAGNOSTICCODE_HPP
|
||||||
|
|
|
@ -42,6 +42,8 @@ namespace Porygon::Evaluation {
|
||||||
return this->EvaluateReturnStatement((BoundReturnStatement *) statement);
|
return this->EvaluateReturnStatement((BoundReturnStatement *) statement);
|
||||||
case BoundStatementKind::Conditional:
|
case BoundStatementKind::Conditional:
|
||||||
return this->EvaluateConditionalStatement((BoundConditionalStatement *) statement);
|
return this->EvaluateConditionalStatement((BoundConditionalStatement *) statement);
|
||||||
|
case BoundStatementKind::NumericalFor:
|
||||||
|
return this->EvaluateNumericalForStatement((BoundNumericalForStatement*)statement);
|
||||||
|
|
||||||
case BoundStatementKind::Bad:
|
case BoundStatementKind::Bad:
|
||||||
throw;
|
throw;
|
||||||
|
@ -116,6 +118,38 @@ namespace Porygon::Evaluation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Evaluator::EvaluateNumericalForStatement(const BoundNumericalForStatement *statement) {
|
||||||
|
long start = this->EvaluateIntegerExpression(statement -> GetStart()) -> EvaluateInteger();
|
||||||
|
long end = this->EvaluateIntegerExpression(statement -> GetEnd()) -> EvaluateInteger();
|
||||||
|
long step = 1;
|
||||||
|
auto stepExp = statement -> GetStep();
|
||||||
|
if (stepExp != nullptr){
|
||||||
|
step = this -> EvaluateIntegerExpression(stepExp) -> EvaluateInteger();
|
||||||
|
}
|
||||||
|
auto identifier = statement -> GetIdentifier();
|
||||||
|
this -> _evaluationScope -> CreateVariable(identifier, nullptr);
|
||||||
|
auto block = (BoundBlockStatement*)statement -> GetBlock();
|
||||||
|
if (step > 0){
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const shared_ptr<EvalValue> Evaluator::EvaluateExpression(const BoundExpression *expression) {
|
const shared_ptr<EvalValue> Evaluator::EvaluateExpression(const BoundExpression *expression) {
|
||||||
auto type = expression->GetType();
|
auto type = expression->GetType();
|
||||||
switch (type->GetClass()) {
|
switch (type->GetClass()) {
|
||||||
|
@ -389,4 +423,5 @@ namespace Porygon::Evaluation {
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -31,6 +31,7 @@ namespace Porygon::Evaluation{
|
||||||
void EvaluateFunctionDeclarationStatement(const BoundFunctionDeclarationStatement *statement);
|
void EvaluateFunctionDeclarationStatement(const BoundFunctionDeclarationStatement *statement);
|
||||||
void EvaluateReturnStatement(const BoundReturnStatement *statement);
|
void EvaluateReturnStatement(const BoundReturnStatement *statement);
|
||||||
void EvaluateConditionalStatement(const BoundConditionalStatement *statement);
|
void EvaluateConditionalStatement(const BoundConditionalStatement *statement);
|
||||||
|
void EvaluateNumericalForStatement(const BoundNumericalForStatement *statement);
|
||||||
|
|
||||||
const shared_ptr<EvalValue> EvaluateExpression(const BoundExpression *expression);
|
const shared_ptr<EvalValue> EvaluateExpression(const BoundExpression *expression);
|
||||||
const shared_ptr<NumericEvalValue> EvaluateIntegerExpression(const BoundExpression *expression);
|
const shared_ptr<NumericEvalValue> EvaluateIntegerExpression(const BoundExpression *expression);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#ifndef PORYGONLANG_PARSEDEXPRESSION_HPP
|
#ifndef PORYGONLANG_PARSEDEXPRESSION_HPP
|
||||||
#define PORYGONLANG_PARSEDEXPRESSION_HPP
|
#define PORYGONLANG_PARSEDEXPRESSION_HPP
|
||||||
|
@ -12,7 +11,7 @@
|
||||||
#include "../../Utilities/HashedString.hpp"
|
#include "../../Utilities/HashedString.hpp"
|
||||||
|
|
||||||
namespace Porygon::Parser {
|
namespace Porygon::Parser {
|
||||||
enum class ParsedExpressionKind {
|
enum class ParsedExpressionKind : uint8_t {
|
||||||
Bad,
|
Bad,
|
||||||
|
|
||||||
LiteralInteger,
|
LiteralInteger,
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#ifndef PORYGONLANG_PARSEDSTATEMENT_HPP
|
#ifndef PORYGONLANG_PARSEDSTATEMENT_HPP
|
||||||
#define PORYGONLANG_PARSEDSTATEMENT_HPP
|
#define PORYGONLANG_PARSEDSTATEMENT_HPP
|
||||||
|
@ -14,7 +11,7 @@
|
||||||
#include "../TypedVariableIdentifier.hpp"
|
#include "../TypedVariableIdentifier.hpp"
|
||||||
|
|
||||||
namespace Porygon::Parser {
|
namespace Porygon::Parser {
|
||||||
enum class ParsedStatementKind {
|
enum class ParsedStatementKind : uint8_t {
|
||||||
Bad,
|
Bad,
|
||||||
Script,
|
Script,
|
||||||
Block,
|
Block,
|
||||||
|
@ -23,7 +20,8 @@ namespace Porygon::Parser {
|
||||||
IndexAssignment,
|
IndexAssignment,
|
||||||
FunctionDeclaration,
|
FunctionDeclaration,
|
||||||
Return,
|
Return,
|
||||||
Conditional
|
Conditional,
|
||||||
|
NumericalFor
|
||||||
};
|
};
|
||||||
|
|
||||||
class ParsedStatement {
|
class ParsedStatement {
|
||||||
|
@ -278,5 +276,51 @@ namespace Porygon::Parser {
|
||||||
return _elseStatement;
|
return _elseStatement;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ParsedNumericalForStatement : public ParsedStatement {
|
||||||
|
const HashedString _identifier;
|
||||||
|
const ParsedExpression *_start;
|
||||||
|
const ParsedExpression *_end;
|
||||||
|
const ParsedExpression *_step;
|
||||||
|
const ParsedStatement *_block;
|
||||||
|
public:
|
||||||
|
ParsedNumericalForStatement(const HashedString identifier, const ParsedExpression *start,
|
||||||
|
const ParsedExpression *end, const ParsedExpression *step, const ParsedStatement *block,
|
||||||
|
unsigned int startPos, unsigned int length)
|
||||||
|
: ParsedStatement(startPos, length), _identifier(identifier), _start(start), _end(end), _step(step), _block(block) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~ParsedNumericalForStatement() final {
|
||||||
|
delete _start;
|
||||||
|
delete _end;
|
||||||
|
delete _step;
|
||||||
|
delete _block;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ParsedStatementKind GetKind() const final {
|
||||||
|
return ParsedStatementKind::NumericalFor;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HashedString GetIdentifier() const{
|
||||||
|
return _identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ParsedExpression *GetStart() const{
|
||||||
|
return _start;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ParsedExpression *GetEnd() const{
|
||||||
|
return _end;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ParsedExpression *GetStep() const{
|
||||||
|
return _step;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ParsedStatement *GetBlock() const{
|
||||||
|
return _block;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif //PORYGONLANG_PARSEDSTATEMENT_HPP
|
#endif //PORYGONLANG_PARSEDSTATEMENT_HPP
|
||||||
|
|
|
@ -44,6 +44,8 @@ namespace Porygon::Parser {
|
||||||
return this->ParseReturnStatement(current);
|
return this->ParseReturnStatement(current);
|
||||||
case TokenKind::IfKeyword:
|
case TokenKind::IfKeyword:
|
||||||
return this->ParseIfStatement(current);
|
return this->ParseIfStatement(current);
|
||||||
|
case TokenKind ::ForKeyword:
|
||||||
|
return this->ParseForStatement(current);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -191,7 +193,6 @@ namespace Porygon::Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedStatement *Parser::ParseReturnStatement(const IToken *current) {
|
ParsedStatement *Parser::ParseReturnStatement(const IToken *current) {
|
||||||
//TODO: if next token is on a different line, don't parse it as return expression.
|
|
||||||
auto start = current->GetStartPosition();
|
auto start = current->GetStartPosition();
|
||||||
auto startLine = this -> ScriptData -> Diagnostics ->GetLineFromPosition(start);
|
auto startLine = this -> ScriptData -> Diagnostics ->GetLineFromPosition(start);
|
||||||
if (startLine != this -> ScriptData -> Diagnostics -> GetLineFromPosition(this -> Peek() -> GetStartPosition())){
|
if (startLine != this -> ScriptData -> Diagnostics -> GetLineFromPosition(this -> Peek() -> GetStartPosition())){
|
||||||
|
@ -224,6 +225,55 @@ 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) {
|
||||||
|
auto identifier = this -> Next();
|
||||||
|
if (this -> Peek()->GetKind() == TokenKind::AssignmentToken){
|
||||||
|
return ParseNumericForStatement(identifier);
|
||||||
|
} else {
|
||||||
|
return ParseGenericForStatement(identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedStatement *Parser::ParseNumericForStatement(const IToken *current) {
|
||||||
|
auto identifier = (IdentifierToken*)current;
|
||||||
|
this->Next(); // consume assignment token
|
||||||
|
bool hasErrors = false;
|
||||||
|
auto start = this ->ParseExpression(this ->Next());
|
||||||
|
auto comma = this -> Next(); // consume comma token
|
||||||
|
if (comma->GetKind() != TokenKind::CommaToken){
|
||||||
|
hasErrors = true;
|
||||||
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, comma->GetStartPosition(),
|
||||||
|
comma->GetLength());
|
||||||
|
}
|
||||||
|
auto end = this -> ParseExpression(this -> Next());
|
||||||
|
ParsedExpression *step = nullptr;
|
||||||
|
if (this -> Peek()->GetKind() == TokenKind::CommaToken){
|
||||||
|
this -> Next();
|
||||||
|
step = this -> ParseExpression(this -> Next());
|
||||||
|
}
|
||||||
|
auto doToken = this ->Next();
|
||||||
|
if (doToken->GetKind() != TokenKind::DoKeyword && !hasErrors){
|
||||||
|
hasErrors = true;
|
||||||
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, doToken->GetStartPosition(),
|
||||||
|
doToken->GetLength());
|
||||||
|
}
|
||||||
|
auto block = this -> ParseBlock({TokenKind ::EndKeyword});
|
||||||
|
auto startPos = current->GetStartPosition();
|
||||||
|
if (hasErrors){
|
||||||
|
return new ParsedBadStatement(startPos, block -> GetEndPosition() - startPos);
|
||||||
|
}
|
||||||
|
return new ParsedNumericalForStatement(identifier->GetValue(), start, end, step, block, startPos, block->GetEndPosition() - startPos);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedStatement *Parser::ParseGenericForStatement(const IToken *current) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
// Expressions //
|
||||||
|
/////////////////
|
||||||
|
|
||||||
ParsedExpression *Parser::ParseExpression(const IToken *current) {
|
ParsedExpression *Parser::ParseExpression(const IToken *current) {
|
||||||
auto expression = this->ParseBinaryExpression(current, OperatorPrecedence::No);
|
auto expression = this->ParseBinaryExpression(current, OperatorPrecedence::No);
|
||||||
auto peekKind = this->Peek()->GetKind();
|
auto peekKind = this->Peek()->GetKind();
|
||||||
|
|
|
@ -29,14 +29,15 @@ namespace Porygon::Parser {
|
||||||
|
|
||||||
const IToken *Next();
|
const IToken *Next();
|
||||||
|
|
||||||
|
// Statements
|
||||||
|
|
||||||
ParsedStatement *ParseStatement(const IToken *current);
|
ParsedStatement *ParseStatement(const IToken *current);
|
||||||
|
|
||||||
ParsedStatement *ParseVariableAssignment(const IToken *current);
|
ParsedStatement *ParseVariableAssignment(const IToken *current);
|
||||||
|
|
||||||
ParsedStatement *ParseIndexAssignment(ParsedExpression *indexer);
|
ParsedStatement *ParseIndexAssignment(ParsedExpression *indexer);
|
||||||
|
|
||||||
ParsedStatement *
|
ParsedStatement *ParseBlock(const vector<TokenKind> &endTokens, const vector<const ParsedStatement *> &openStatements = {});
|
||||||
ParseBlock(const vector<TokenKind> &endTokens, const vector<const ParsedStatement *> &openStatements = {});
|
|
||||||
|
|
||||||
ParsedStatement *ParseFunctionDeclaration(const IToken *current);
|
ParsedStatement *ParseFunctionDeclaration(const IToken *current);
|
||||||
|
|
||||||
|
@ -44,6 +45,12 @@ namespace Porygon::Parser {
|
||||||
|
|
||||||
ParsedStatement *ParseIfStatement(const IToken *current);
|
ParsedStatement *ParseIfStatement(const IToken *current);
|
||||||
|
|
||||||
|
ParsedStatement *ParseForStatement(const IToken *current);
|
||||||
|
ParsedStatement *ParseNumericForStatement(const IToken *current);
|
||||||
|
ParsedStatement *ParseGenericForStatement(const IToken *current);
|
||||||
|
|
||||||
|
// Expressions
|
||||||
|
|
||||||
ParsedExpression *ParseExpression(const IToken *current);
|
ParsedExpression *ParseExpression(const IToken *current);
|
||||||
|
|
||||||
ParsedExpression *ParseBinaryExpression(const IToken *current, OperatorPrecedence parentPrecedence);
|
ParsedExpression *ParseBinaryExpression(const IToken *current, OperatorPrecedence parentPrecedence);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define PORYGONLANG_TOKENKIND_HPP
|
#define PORYGONLANG_TOKENKIND_HPP
|
||||||
|
|
||||||
namespace Porygon::Parser {
|
namespace Porygon::Parser {
|
||||||
enum class TokenKind {
|
enum class TokenKind : uint8_t {
|
||||||
EndOfFile,
|
EndOfFile,
|
||||||
BadToken,
|
BadToken,
|
||||||
WhiteSpace,
|
WhiteSpace,
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
#ifdef TESTS_BUILD
|
||||||
|
#include <catch.hpp>
|
||||||
|
#include "../src/Script.hpp"
|
||||||
|
using namespace Porygon;
|
||||||
|
|
||||||
|
TEST_CASE( "Numerical for loop without step", "[integration]" ) {
|
||||||
|
auto script = Script::Create(uR"(
|
||||||
|
result = 0
|
||||||
|
for i = 0,10 do
|
||||||
|
result = result + 3
|
||||||
|
end
|
||||||
|
)");
|
||||||
|
REQUIRE(!script->Diagnostics -> HasErrors());
|
||||||
|
script->Evaluate();
|
||||||
|
auto var = script->GetVariable(u"result");
|
||||||
|
REQUIRE(var->EvaluateInteger() == 33);
|
||||||
|
delete script;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "Numerical for loop with step", "[integration]" ) {
|
||||||
|
auto script = Script::Create(uR"(
|
||||||
|
result = 0
|
||||||
|
for i = 0,10,3 do
|
||||||
|
result = result + 3
|
||||||
|
end
|
||||||
|
)");
|
||||||
|
REQUIRE(!script->Diagnostics -> HasErrors());
|
||||||
|
script->Evaluate();
|
||||||
|
auto var = script->GetVariable(u"result");
|
||||||
|
REQUIRE(var->EvaluateInteger() == 12);
|
||||||
|
delete script;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "Numerical for loop with negative step", "[integration]" ) {
|
||||||
|
auto script = Script::Create(uR"(
|
||||||
|
result = 0
|
||||||
|
for i = 10,0,-1 do
|
||||||
|
result = result + 3
|
||||||
|
end
|
||||||
|
)");
|
||||||
|
REQUIRE(!script->Diagnostics -> HasErrors());
|
||||||
|
script->Evaluate();
|
||||||
|
auto var = script->GetVariable(u"result");
|
||||||
|
REQUIRE(var->EvaluateInteger() == 33);
|
||||||
|
delete script;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE( "Numerical for loop creates variable", "[integration]" ) {
|
||||||
|
auto script = Script::Create(uR"(
|
||||||
|
result = 0
|
||||||
|
for i = 0,5 do
|
||||||
|
result = result + i
|
||||||
|
end
|
||||||
|
)");
|
||||||
|
REQUIRE(!script->Diagnostics -> HasErrors());
|
||||||
|
script->Evaluate();
|
||||||
|
auto var = script->GetVariable(u"result");
|
||||||
|
REQUIRE(var->EvaluateInteger() == 15);
|
||||||
|
delete script;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue