Implements numeric for loops
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2019-06-22 17:35:33 +02:00
parent 694b0ac0c0
commit e472dcec1c
16 changed files with 311 additions and 23 deletions

View File

@@ -1,4 +1,3 @@
#include <utility>
#ifndef PORYGONLANG_PARSEDEXPRESSION_HPP
#define PORYGONLANG_PARSEDEXPRESSION_HPP
@@ -12,7 +11,7 @@
#include "../../Utilities/HashedString.hpp"
namespace Porygon::Parser {
enum class ParsedExpressionKind {
enum class ParsedExpressionKind : uint8_t {
Bad,
LiteralInteger,

View File

@@ -1,6 +1,3 @@
#include <utility>
#include <utility>
#ifndef PORYGONLANG_PARSEDSTATEMENT_HPP
#define PORYGONLANG_PARSEDSTATEMENT_HPP
@@ -14,7 +11,7 @@
#include "../TypedVariableIdentifier.hpp"
namespace Porygon::Parser {
enum class ParsedStatementKind {
enum class ParsedStatementKind : uint8_t {
Bad,
Script,
Block,
@@ -23,7 +20,8 @@ namespace Porygon::Parser {
IndexAssignment,
FunctionDeclaration,
Return,
Conditional
Conditional,
NumericalFor
};
class ParsedStatement {
@@ -278,5 +276,51 @@ namespace Porygon::Parser {
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

View File

@@ -44,6 +44,8 @@ namespace Porygon::Parser {
return this->ParseReturnStatement(current);
case TokenKind::IfKeyword:
return this->ParseIfStatement(current);
case TokenKind ::ForKeyword:
return this->ParseForStatement(current);
default:
break;
}
@@ -191,7 +193,6 @@ namespace Porygon::Parser {
}
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 startLine = this -> ScriptData -> Diagnostics ->GetLineFromPosition(start);
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);
}
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) {
auto expression = this->ParseBinaryExpression(current, OperatorPrecedence::No);
auto peekKind = this->Peek()->GetKind();

View File

@@ -29,14 +29,15 @@ namespace Porygon::Parser {
const IToken *Next();
// Statements
ParsedStatement *ParseStatement(const IToken *current);
ParsedStatement *ParseVariableAssignment(const IToken *current);
ParsedStatement *ParseIndexAssignment(ParsedExpression *indexer);
ParsedStatement *
ParseBlock(const vector<TokenKind> &endTokens, const vector<const ParsedStatement *> &openStatements = {});
ParsedStatement *ParseBlock(const vector<TokenKind> &endTokens, const vector<const ParsedStatement *> &openStatements = {});
ParsedStatement *ParseFunctionDeclaration(const IToken *current);
@@ -44,6 +45,12 @@ namespace Porygon::Parser {
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 *ParseBinaryExpression(const IToken *current, OperatorPrecedence parentPrecedence);

View File

@@ -2,7 +2,7 @@
#define PORYGONLANG_TOKENKIND_HPP
namespace Porygon::Parser {
enum class TokenKind {
enum class TokenKind : uint8_t {
EndOfFile,
BadToken,
WhiteSpace,