Implements parsing function declarations
This commit is contained in:
parent
6fad5a0a7d
commit
c407ba2f50
|
@ -56,6 +56,8 @@ IToken* Lexer::LexNext(char c){
|
|||
return new SimpleToken(TokenKind::OpenParenthesis, this -> Position - 1, 1);
|
||||
case ')':
|
||||
return new SimpleToken(TokenKind::CloseParenthesis, this -> Position - 1, 1);
|
||||
case ',':
|
||||
return new SimpleToken(TokenKind::CommaToken, this -> Position - 1, 1);
|
||||
case '=':
|
||||
if (Lexer::Peek() == '='){
|
||||
Lexer::Next();
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
#include <utility>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
|
||||
#ifndef PORYGONLANG_PARSEDSTATEMENT_HPP
|
||||
#define PORYGONLANG_PARSEDSTATEMENT_HPP
|
||||
|
||||
|
@ -13,13 +7,15 @@
|
|||
|
||||
#include "../ParsedExpressions/ParsedExpression.hpp"
|
||||
#include "../../Utilities/HashedString.hpp"
|
||||
#include "../TypedVariableIdentifier.hpp"
|
||||
|
||||
enum class ParsedStatementKind{
|
||||
Bad,
|
||||
Script,
|
||||
Block,
|
||||
Expression,
|
||||
Assignment
|
||||
Assignment,
|
||||
FunctionDeclaration
|
||||
};
|
||||
|
||||
class ParsedStatement {
|
||||
|
@ -105,6 +101,39 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class ParsedFunctionDeclarationStatement : public ParsedStatement{
|
||||
HashedString _identifier;
|
||||
vector<TypedVariableIdentifier*> _parameters;
|
||||
ParsedBlockStatement* _block;
|
||||
public:
|
||||
ParsedFunctionDeclarationStatement(HashedString identifier, vector<TypedVariableIdentifier*> parameters, ParsedBlockStatement* block,
|
||||
unsigned int start, unsigned int length)
|
||||
: ParsedStatement(start, length), _identifier(identifier), _parameters(std::move(parameters)), _block(block){};
|
||||
|
||||
~ParsedFunctionDeclarationStatement() override {
|
||||
for (auto v : _parameters){
|
||||
delete v;
|
||||
}
|
||||
delete _block;
|
||||
}
|
||||
|
||||
ParsedStatementKind GetKind() final{
|
||||
return ParsedStatementKind ::FunctionDeclaration;
|
||||
}
|
||||
|
||||
HashedString GetIdentifier(){
|
||||
return _identifier;
|
||||
}
|
||||
|
||||
vector<TypedVariableIdentifier*> GetParameters(){
|
||||
return _parameters;
|
||||
}
|
||||
|
||||
ParsedBlockStatement* GetBlock(){
|
||||
return _block;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedAssignmentStatement : public ParsedStatement{
|
||||
bool _local;
|
||||
HashedString _identifier;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "Parser.hpp"
|
||||
#include "UnaryOperatorKind.hpp"
|
||||
#include "BinaryOperatorKind.hpp"
|
||||
#include "TypedVariableIdentifier.hpp"
|
||||
|
||||
|
||||
ParsedScriptStatement* Parser::Parse() {
|
||||
|
@ -11,9 +12,6 @@ ParsedScriptStatement* Parser::Parse() {
|
|||
if (next->GetKind() == TokenKind::EndOfFile){
|
||||
break;
|
||||
}
|
||||
if (next->GetKind() == TokenKind::WhiteSpace){
|
||||
continue;
|
||||
}
|
||||
statements.push_back(this -> ParseStatement(next));
|
||||
}
|
||||
return new ParsedScriptStatement(statements);
|
||||
|
@ -29,9 +27,13 @@ IToken *Parser::Next() {
|
|||
}
|
||||
|
||||
ParsedStatement* Parser::ParseStatement(IToken* current){
|
||||
if (current->GetKind() == TokenKind::LocalKeyword){
|
||||
return ParseAssignment(current);
|
||||
} else if (this->Peek()->GetKind() == TokenKind::AssignmentToken){
|
||||
auto currentKind = current->GetKind();
|
||||
switch (currentKind){
|
||||
case TokenKind ::LocalKeyword: return this -> ParseAssignment(current);
|
||||
case TokenKind ::FunctionKeyword: return this -> ParseFunctionDeclaration(current);
|
||||
default: break;
|
||||
}
|
||||
if (this->Peek()->GetKind() == TokenKind::AssignmentToken){
|
||||
return ParseAssignment(current);
|
||||
}
|
||||
return new ParsedExpressionStatement(this -> ParseExpression(current));
|
||||
|
@ -62,8 +64,83 @@ ParsedStatement *Parser::ParseAssignment(IToken *current) {
|
|||
return new ParsedAssignmentStatement(isLocal, ((IdentifierToken*)identifier) -> Value, expression, start, expression->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
ParsedStatement *Parser::ParseBlock(vector<TokenKind> endTokens) {
|
||||
vector<ParsedStatement*> statements;
|
||||
while (true){
|
||||
auto next = this -> Next();
|
||||
auto nextKind = next->GetKind();
|
||||
if (std::find(endTokens.begin(), endTokens.end(), nextKind) != endTokens.end()){
|
||||
break;
|
||||
}
|
||||
if (nextKind == TokenKind::EndOfFile){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(), next->GetLength());
|
||||
break;
|
||||
}
|
||||
statements.push_back(this -> ParseStatement(next));
|
||||
}
|
||||
return new ParsedBlockStatement(statements);
|
||||
}
|
||||
|
||||
ParsedStatement *Parser::ParseFunctionDeclaration(IToken *current) {
|
||||
auto functionIdentifierToken = this->Next();
|
||||
auto openParenthesis = this->Next();
|
||||
vector<TypedVariableIdentifier*> parameters;
|
||||
bool hasErrors = false;
|
||||
if (functionIdentifierToken->GetKind() != TokenKind::Identifier){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, functionIdentifierToken->GetStartPosition(), functionIdentifierToken->GetLength());
|
||||
hasErrors = true;
|
||||
}
|
||||
if (openParenthesis->GetKind() != TokenKind::OpenParenthesis && !hasErrors){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, openParenthesis->GetStartPosition(), openParenthesis->GetLength());
|
||||
hasErrors = true;
|
||||
}
|
||||
|
||||
while (true){
|
||||
auto type = this->Next();
|
||||
auto identifier = this->Next();
|
||||
auto next = this->Next();
|
||||
if (type->GetKind() != TokenKind::Identifier &&!hasErrors){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, type->GetStartPosition(), type->GetLength());
|
||||
hasErrors = true;
|
||||
continue;
|
||||
}
|
||||
if (identifier->GetKind() != TokenKind::Identifier &&!hasErrors){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength());
|
||||
hasErrors = true;
|
||||
continue;
|
||||
}
|
||||
auto typeToken = (IdentifierToken*)type;
|
||||
auto identifierToken = (IdentifierToken*)identifier;
|
||||
parameters.push_back(new TypedVariableIdentifier(HashedString(typeToken->Value), HashedString(identifierToken->Value)));
|
||||
|
||||
auto nextKind = next->GetKind();
|
||||
if (nextKind == TokenKind::CloseParenthesis || nextKind == TokenKind::EndOfFile){
|
||||
break;
|
||||
} else if (nextKind != TokenKind::CommaToken && !hasErrors){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(), next->GetLength());
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
auto block = this -> ParseBlock({TokenKind ::EndKeyword});
|
||||
|
||||
auto start = current->GetStartPosition();
|
||||
if (hasErrors){
|
||||
return new ParsedBadStatement(start, block->GetEndPosition() - start);
|
||||
}
|
||||
if (block->GetKind() == ParsedStatementKind::Bad){
|
||||
return new ParsedBadStatement(start, block->GetEndPosition() - start);
|
||||
}
|
||||
auto functionIdentifier = ((IdentifierToken*) functionIdentifierToken)->Value;
|
||||
return new ParsedFunctionDeclarationStatement(HashedString(functionIdentifier), parameters, (ParsedBlockStatement*)block, start, block->GetEndPosition() - start);
|
||||
|
||||
}
|
||||
|
||||
ParsedExpression* Parser::ParseExpression(IToken* current){
|
||||
return this -> ParseBinaryExpression(current, OperatorPrecedence::No);
|
||||
auto expression = this -> ParseBinaryExpression(current, OperatorPrecedence::No);
|
||||
if (this -> Peek() -> GetKind() == TokenKind::OpenParenthesis){
|
||||
//TODO: Function Evaluation
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
OperatorPrecedence GetUnaryPrecedence(TokenKind kind){
|
||||
|
@ -175,3 +252,5 @@ ParsedExpression *Parser::ParseParenthesizedExpression(IToken *current) {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,9 @@ class Parser {
|
|||
IToken* Next();
|
||||
|
||||
ParsedStatement* ParseStatement(IToken* current);
|
||||
ParsedStatement* ParseAssignment(IToken *current);
|
||||
ParsedStatement* ParseAssignment(IToken* current);
|
||||
ParsedStatement *ParseBlock(vector<TokenKind> endTokens);
|
||||
ParsedStatement* ParseFunctionDeclaration(IToken* current);
|
||||
|
||||
ParsedExpression* ParseExpression(IToken* current);
|
||||
ParsedExpression* ParseBinaryExpression(IToken* current, OperatorPrecedence parentPrecedence);
|
||||
|
|
|
@ -15,6 +15,7 @@ enum class TokenKind{
|
|||
InequalityToken,
|
||||
OpenParenthesis,
|
||||
CloseParenthesis,
|
||||
CommaToken,
|
||||
|
||||
Identifier,
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
#ifndef PORYGONLANG_TYPEDVARIABLEIDENTIFIER_HPP
|
||||
#define PORYGONLANG_TYPEDVARIABLEIDENTIFIER_HPP
|
||||
|
||||
#include "../Utilities/HashedString.hpp"
|
||||
|
||||
class TypedVariableIdentifier{
|
||||
HashedString _type;
|
||||
HashedString _identifier;
|
||||
public:
|
||||
TypedVariableIdentifier(HashedString type, HashedString identifier)
|
||||
: _type(type), _identifier(identifier)
|
||||
{
|
||||
}
|
||||
|
||||
HashedString GetType(){
|
||||
return _type;
|
||||
}
|
||||
|
||||
HashedString GetIdentifier(){
|
||||
return _identifier;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //PORYGONLANG_TYPEDVARIABLEIDENTIFIER_HPP
|
|
@ -19,6 +19,13 @@ public:
|
|||
const int GetHash(){
|
||||
return _hash;
|
||||
}
|
||||
|
||||
bool operator==(const HashedString& b) const{
|
||||
return _hash == b._hash;
|
||||
}
|
||||
bool operator!=(const HashedString& b) const{
|
||||
return _hash != b._hash;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //PORYGONLANG_HASHEDSTRING_HPP
|
||||
|
|
|
@ -191,5 +191,36 @@ TEST_CASE( "Parse local Assignment", "[parser]" ) {
|
|||
REQUIRE(((LiteralBoolExpression*)assignment->GetExpression()) -> GetValue());
|
||||
}
|
||||
|
||||
TEST_CASE( "Parse function declaration", "[parser]" ){
|
||||
vector<IToken*> v {
|
||||
new SimpleToken(TokenKind::FunctionKeyword,0,0),
|
||||
new IdentifierToken("foo",0,0),
|
||||
new SimpleToken(TokenKind::OpenParenthesis,0,0),
|
||||
new IdentifierToken("number",0,0),
|
||||
new IdentifierToken("bar",0,0),
|
||||
new SimpleToken(TokenKind::CommaToken,0,0),
|
||||
new IdentifierToken("number",0,0),
|
||||
new IdentifierToken("par",0,0),
|
||||
new SimpleToken(TokenKind::CloseParenthesis,0,0),
|
||||
new IdentifierToken("bar",0,0),
|
||||
new SimpleToken(TokenKind::PlusToken,0,0),
|
||||
new IdentifierToken("par",0,0),
|
||||
new SimpleToken(TokenKind::EndKeyword,0,0),
|
||||
new SimpleToken(TokenKind::EndOfFile,0,0),
|
||||
};
|
||||
Parser parser = Parser(v, nullptr);
|
||||
auto parsedStatements = parser.Parse() -> GetStatements();
|
||||
REQUIRE(parsedStatements.size() == 1);
|
||||
auto firstStatement = parsedStatements[0];
|
||||
REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::FunctionDeclaration);
|
||||
auto functionDeclaration = (ParsedFunctionDeclarationStatement*)firstStatement;
|
||||
REQUIRE(functionDeclaration->GetIdentifier() == HashedString("foo"));
|
||||
auto parameters = functionDeclaration->GetParameters();
|
||||
CHECK(parameters[0]->GetType() == HashedString("number"));
|
||||
CHECK(parameters[0]->GetIdentifier() == HashedString("bar"));
|
||||
CHECK(parameters[1]->GetType() == HashedString("number"));
|
||||
CHECK(parameters[1]->GetIdentifier() == HashedString("par"));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue