Better error handling of expressions
This commit is contained in:
@@ -72,25 +72,26 @@ shared_ptr<Statement> Parser::nextStatement() {
|
|||||||
|
|
||||||
shared_ptr<Statement> Parser::nextInBlockStatement() {
|
shared_ptr<Statement> Parser::nextInBlockStatement() {
|
||||||
shared_ptr<Statement> statement;
|
shared_ptr<Statement> statement;
|
||||||
|
int errorsCount = errors.size();
|
||||||
|
|
||||||
statement = matchStatementVariable();
|
statement = matchStatementVariable();
|
||||||
if (statement != nullptr)
|
if (statement != nullptr || errors.size() > errorsCount)
|
||||||
return statement;
|
return statement;
|
||||||
|
|
||||||
statement = matchStatementAssignment();
|
statement = matchStatementAssignment();
|
||||||
if (statement != nullptr)
|
if (statement != nullptr || errors.size() > errorsCount)
|
||||||
return statement;
|
return statement;
|
||||||
|
|
||||||
statement = matchStatementReturn();
|
statement = matchStatementReturn();
|
||||||
if (statement != nullptr)
|
if (statement != nullptr || errors.size() > errorsCount)
|
||||||
return statement;
|
return statement;
|
||||||
|
|
||||||
statement = matchStatementRepeat();
|
statement = matchStatementRepeat();
|
||||||
if (statement != nullptr)
|
if (statement != nullptr || errors.size() > errorsCount)
|
||||||
return statement;
|
return statement;
|
||||||
|
|
||||||
statement = matchStatementExpression();
|
statement = matchStatementExpression();
|
||||||
if (statement != nullptr)
|
if (statement != nullptr || errors.size() > errorsCount)
|
||||||
return statement;
|
return statement;
|
||||||
|
|
||||||
markError({}, {});
|
markError({}, {});
|
||||||
@@ -374,19 +375,21 @@ shared_ptr<Statement> Parser::matchStatementExpression() {
|
|||||||
//
|
//
|
||||||
shared_ptr<Expression> Parser::nextExpression() {
|
shared_ptr<Expression> Parser::nextExpression() {
|
||||||
shared_ptr<Expression> expression;
|
shared_ptr<Expression> expression;
|
||||||
|
int errorsCount = errors.size();
|
||||||
|
|
||||||
expression = matchEquality();
|
expression = matchEquality();
|
||||||
if (expression != nullptr)
|
if (expression != nullptr || errors.size() > errorsCount)
|
||||||
return expression;
|
return expression;
|
||||||
|
|
||||||
expression = matchExpressionIfElse();
|
expression = matchExpressionIfElse();
|
||||||
if (expression != nullptr)
|
if (expression != nullptr || errors.size() > errorsCount)
|
||||||
return expression;
|
return expression;
|
||||||
|
|
||||||
expression = matchExpressionVariable();
|
expression = matchExpressionVariable();
|
||||||
if (expression != nullptr)
|
if (expression != nullptr || errors.size() > errorsCount)
|
||||||
return expression;
|
return expression;
|
||||||
|
|
||||||
|
markError({}, {});
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,12 +464,12 @@ shared_ptr<Expression> Parser::matchExpressionGrouping() {
|
|||||||
if (tryMatchingTokenKinds({TokenKind::LEFT_PAREN}, true, true)) {
|
if (tryMatchingTokenKinds({TokenKind::LEFT_PAREN}, true, true)) {
|
||||||
shared_ptr<Expression> expression = matchTerm();
|
shared_ptr<Expression> expression = matchTerm();
|
||||||
// has grouped expression failed?
|
// has grouped expression failed?
|
||||||
if (expression == nullptr || !expression->isValid()) {
|
if (expression == nullptr) {
|
||||||
return expression ?: matchExpressionInvalid("Expected expression");
|
return nullptr;
|
||||||
} else if (tryMatchingTokenKinds({TokenKind::RIGHT_PAREN}, true, true)) {
|
} else if (tryMatchingTokenKinds({TokenKind::RIGHT_PAREN}, true, true)) {
|
||||||
return make_shared<ExpressionGrouping>(expression);
|
return make_shared<ExpressionGrouping>(expression);
|
||||||
} else {
|
} else {
|
||||||
return matchExpressionInvalid("Unexpected token");
|
markError(TokenKind::RIGHT_PAREN, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,8 +513,10 @@ shared_ptr<Expression> Parser::matchExpressionCall() {
|
|||||||
} while (tryMatchingTokenKinds({TokenKind::COMMA}, true, true));
|
} while (tryMatchingTokenKinds({TokenKind::COMMA}, true, true));
|
||||||
|
|
||||||
tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // optional new line
|
tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // optional new line
|
||||||
if (!tryMatchingTokenKinds({TokenKind::RIGHT_PAREN}, true, true))
|
if (!tryMatchingTokenKinds({TokenKind::RIGHT_PAREN}, true, true)) {
|
||||||
return matchExpressionInvalid("Expected \")\"");
|
markError(TokenKind::RIGHT_PAREN, {});
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return make_shared<ExpressionCall>(identifierToken->getLexme(), argumentExpressions);
|
return make_shared<ExpressionCall>(identifierToken->getLexme(), argumentExpressions);
|
||||||
}
|
}
|
||||||
@@ -526,30 +531,29 @@ shared_ptr<Expression> Parser::matchExpressionIfElse() {
|
|||||||
|
|
||||||
// condition expression
|
// condition expression
|
||||||
condition = nextExpression();
|
condition = nextExpression();
|
||||||
if (condition == nullptr || !condition->isValid())
|
if (condition == nullptr)
|
||||||
return condition ?: matchExpressionInvalid("Expected condition expression");
|
return nullptr;
|
||||||
|
|
||||||
if (!tryMatchingTokenKinds({TokenKind::COLON}, true, true))
|
if (!tryMatchingTokenKinds({TokenKind::COLON}, true, true)) {
|
||||||
return matchExpressionInvalid("Expected \":\"");
|
markError(TokenKind::COLON, {});
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// then
|
// then
|
||||||
bool isMultiLine = false;
|
bool isMultiLine = tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true);
|
||||||
|
|
||||||
if (tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true))
|
|
||||||
isMultiLine = true;
|
|
||||||
|
|
||||||
// then block
|
// then block
|
||||||
if (isMultiLine)
|
if (isMultiLine)
|
||||||
thenBlock = matchExpressionBlock({TokenKind::ELSE, TokenKind::SEMICOLON});
|
thenBlock = matchExpressionBlock({TokenKind::ELSE, TokenKind::SEMICOLON});
|
||||||
else
|
else
|
||||||
thenBlock = matchExpressionBlock({TokenKind::ELSE, TokenKind::NEW_LINE});
|
thenBlock = matchExpressionBlock({TokenKind::ELSE, TokenKind::NEW_LINE});
|
||||||
if (thenBlock == nullptr || !thenBlock->isValid())
|
|
||||||
return thenBlock ?: matchExpressionInvalid("Expected then block");
|
if (thenBlock == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
// else
|
// else
|
||||||
if (tryMatchingTokenKinds({TokenKind::ELSE}, true, true)) {
|
if (tryMatchingTokenKinds({TokenKind::ELSE}, true, true)) {
|
||||||
if (tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true))
|
isMultiLine = (tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true));
|
||||||
isMultiLine = true;
|
|
||||||
|
|
||||||
// else block
|
// else block
|
||||||
if (isMultiLine)
|
if (isMultiLine)
|
||||||
@@ -557,8 +561,8 @@ shared_ptr<Expression> Parser::matchExpressionIfElse() {
|
|||||||
else
|
else
|
||||||
elseBlock = matchExpressionBlock({TokenKind::NEW_LINE});
|
elseBlock = matchExpressionBlock({TokenKind::NEW_LINE});
|
||||||
|
|
||||||
if (elseBlock == nullptr || !elseBlock->isValid())
|
if (elseBlock == nullptr)
|
||||||
return elseBlock ?: matchExpressionInvalid("Expected else block");
|
return nullptr;
|
||||||
}
|
}
|
||||||
tryMatchingTokenKinds({TokenKind::SEMICOLON}, false, true);
|
tryMatchingTokenKinds({TokenKind::SEMICOLON}, false, true);
|
||||||
|
|
||||||
@@ -580,7 +584,7 @@ shared_ptr<Expression> Parser::matchExpressionBinary(shared_ptr<Expression> left
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (right == nullptr) {
|
if (right == nullptr) {
|
||||||
return matchExpressionInvalid("Expected right-side expression");
|
return nullptr;
|
||||||
} else if (!right->isValid()) {
|
} else if (!right->isValid()) {
|
||||||
return right;
|
return right;
|
||||||
} else {
|
} else {
|
||||||
@@ -595,27 +599,23 @@ shared_ptr<Expression> Parser::matchExpressionBlock(vector<TokenKind> terminalTo
|
|||||||
|
|
||||||
while (!tryMatchingTokenKinds(terminalTokenKinds, false, false)) {
|
while (!tryMatchingTokenKinds(terminalTokenKinds, false, false)) {
|
||||||
shared_ptr<Statement> statement = nextInBlockStatement();
|
shared_ptr<Statement> statement = nextInBlockStatement();
|
||||||
if (statement == nullptr) {
|
|
||||||
markError({}, "Expected statement");
|
if (statement != nullptr)
|
||||||
return nullptr;
|
statements.push_back(statement);
|
||||||
}
|
|
||||||
statements.push_back(statement);
|
|
||||||
|
|
||||||
if (tryMatchingTokenKinds(terminalTokenKinds, false, false))
|
if (tryMatchingTokenKinds(terminalTokenKinds, false, false))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// except new line
|
// except new line
|
||||||
if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true))
|
if (statement != nullptr && !tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) {
|
||||||
return matchExpressionInvalid("Expected new line");
|
markError(TokenKind::NEW_LINE, {});
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return make_shared<ExpressionBlock>(statements);
|
return make_shared<ExpressionBlock>(statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<ExpressionInvalid> Parser::matchExpressionInvalid(string message) {
|
|
||||||
return make_shared<ExpressionInvalid>(tokens.at(currentIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Parser::tryMatchingTokenKinds(vector<TokenKind> kinds, bool shouldMatchAll, bool shouldAdvance) {
|
bool Parser::tryMatchingTokenKinds(vector<TokenKind> kinds, bool shouldMatchAll, bool shouldAdvance) {
|
||||||
int requiredCount = shouldMatchAll ? kinds.size() : 1;
|
int requiredCount = shouldMatchAll ? kinds.size() : 1;
|
||||||
if (currentIndex + requiredCount > tokens.size())
|
if (currentIndex + requiredCount > tokens.size())
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ private:
|
|||||||
shared_ptr<Expression> matchExpressionIfElse();
|
shared_ptr<Expression> matchExpressionIfElse();
|
||||||
shared_ptr<Expression> matchExpressionBinary(shared_ptr<Expression> left);
|
shared_ptr<Expression> matchExpressionBinary(shared_ptr<Expression> left);
|
||||||
shared_ptr<Expression> matchExpressionBlock(vector<TokenKind> terminalTokenKinds);
|
shared_ptr<Expression> matchExpressionBlock(vector<TokenKind> terminalTokenKinds);
|
||||||
shared_ptr<ExpressionInvalid> matchExpressionInvalid(string message);
|
|
||||||
|
|
||||||
bool tryMatchingTokenKinds(vector<TokenKind> kinds, bool shouldMatchAll, bool shouldAdvance);
|
bool tryMatchingTokenKinds(vector<TokenKind> kinds, bool shouldMatchAll, bool shouldAdvance);
|
||||||
optional<ValueType> valueTypeForToken(shared_ptr<Token> token);
|
optional<ValueType> valueTypeForToken(shared_ptr<Token> token);
|
||||||
|
|||||||
Reference in New Issue
Block a user