Implements parsing switch case statements.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2021-01-02 12:38:50 +01:00
parent 85e3a6db43
commit de15173b0b
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
4 changed files with 124 additions and 3 deletions

View File

@ -575,6 +575,7 @@ namespace MalachScript::Parser {
case LexTokenKind::ContinueKeyword: return ParseContinue(out, currentToken, log);
case LexTokenKind::DoKeyword: return ParseDoWhileStatement(out, currentToken, log);
case LexTokenKind::TryKeyword: return ParseTryStatement(out, currentToken, log);
case LexTokenKind::SwitchKeyword: return ParseSwitchStatement(out, currentToken, log);
default: return ParseStatBlock(out, currentToken, log) || ParseExprStat(out, currentToken, log);
}
return false;
@ -1030,4 +1031,90 @@ namespace MalachScript::Parser {
currentToken = current;
return true;
}
bool Parser::ParseSwitchStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
const Parser::log_func& log) {
const auto* current = currentToken;
if (current->GetKind() != LexTokenKind::SwitchKeyword) {
return false;
}
PROGRESS_TOKEN(current);
EXPECT_TOKEN(currentToken, OpenParenthesisSymbol);
ScopedPtr<const ParsedStatement> expression = nullptr;
if (!ParseExpr(expression, current, log)) {
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
return false;
}
EXPECT_TOKEN(currentToken, CloseParenthesisSymbol);
EXPECT_TOKEN(currentToken, OpenCurlyParenthesisSymbol);
std::vector<const ParsedStatement*> caseStatements;
while (true) {
if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) {
break;
}
if (current->GetKind() == LexTokenKind::CaseKeyword ||
currentToken->GetKind() == LexTokenKind::DefaultKeyword) {
ScopedPtr<const ParsedStatement> stat = nullptr;
if (!ParseCaseStatement(stat, current, log)) {
for (const auto* s : caseStatements) {
delete s;
}
return false;
}
caseStatements.push_back(stat.TakeOwnership());
} else {
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
return false;
}
}
// Consume }
PROGRESS_TOKEN(current);
out = new ParsedSwitchStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()),
expression.TakeOwnership(), caseStatements);
currentToken = current;
return true;
}
bool Parser::ParseCaseStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
const Parser::log_func& log) {
const auto* current = currentToken;
if (current->GetKind() != LexTokenKind::CaseKeyword && current->GetKind() != LexTokenKind::DefaultKeyword) {
return false;
}
bool isDefault = current->GetKind() == LexTokenKind::DefaultKeyword;
PROGRESS_TOKEN(current);
ScopedPtr<const ParsedStatement> expression = nullptr;
if (!isDefault) {
if (!ParseExpr(expression, current, log)) {
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
return false;
}
}
EXPECT_TOKEN(current, ColonSymbol);
std::vector<const ParsedStatement*> statements;
while (true) {
// Minor optimization, if we encounter a case/default keyword we know the upcoming statement is another case
// so not part of the current case. Similarly, if we find a close curly parenthesis we know we're at the end
// of the current switch statement, so we don't need to continue parsing.
if (current->GetKind() == LexTokenKind::CaseKeyword || current->GetKind() == LexTokenKind::DefaultKeyword ||
current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) {
break;
}
ScopedPtr<const ParsedStatement> stat = nullptr;
if (ParseStatement(stat, current, log)) {
statements.push_back(stat.TakeOwnership());
} else {
break;
}
}
out = new ParsedCaseStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()),
expression.TakeOwnership(), statements);
currentToken = current;
return true;
}
}

View File

@ -160,8 +160,10 @@ namespace MalachScript::Parser {
const log_func&);
static bool ParseTryStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
const log_func&);
// Case
// Switch
static bool ParseCaseStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
const log_func&);
static bool ParseSwitchStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
const log_func&);
static bool ParseStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
const log_func&);

View File

@ -429,6 +429,36 @@ namespace MalachScript::Parser {
std::unique_ptr<const ParsedStatement> _catchStatement;
};
class ParsedSwitchStatement : public ParsedStatementImpl<ParsedStatementKind::Switch> {
public:
ParsedSwitchStatement(const TextSpan& span, const ParsedStatement* expression,
const std::vector<const ParsedStatement*>& cases)
: ParsedStatementImpl(span), _expression(expression), _cases(cases.size()) {
for (size_t i = 0; i < cases.size(); i++) {
_cases[i] = std::unique_ptr<const ParsedStatement>(cases[i]);
}
}
private:
std::unique_ptr<const ParsedStatement> _expression;
std::vector<std::unique_ptr<const ParsedStatement>> _cases;
};
class ParsedCaseStatement : public ParsedStatementImpl<ParsedStatementKind::Case> {
public:
ParsedCaseStatement(const TextSpan& span, const ParsedStatement* expression,
const std::vector<const ParsedStatement*>& statements)
: ParsedStatementImpl(span), _expression(expression), _statements(statements.size()) {
for (size_t i = 0; i < statements.size(); i++) {
_statements[i] = std::unique_ptr<const ParsedStatement>(statements[i]);
}
}
private:
std::unique_ptr<const ParsedStatement> _expression;
std::vector<std::unique_ptr<const ParsedStatement>> _statements;
};
}
#endif // MALACHSCRIPT_PARSEDSTATEMENT_HPP

View File

@ -27,7 +27,9 @@ namespace MalachScript::Parser {
For,
While,
DoWhile,
Try
Try,
Switch,
Case,
};
}