1955 lines
55 KiB
C++
1955 lines
55 KiB
C++
|
|
// TODO check for memory leaks everywhere a nullptr is returned
|
|
|
|
#include <tuple>
|
|
#include <vector>
|
|
|
|
#include "bolt/Common.hpp"
|
|
#include "bolt/CST.hpp"
|
|
#include "bolt/Scanner.hpp"
|
|
#include "bolt/Parser.hpp"
|
|
#include "bolt/Diagnostics.hpp"
|
|
#include "bolt/DiagnosticEngine.hpp"
|
|
|
|
// ## Some rules
|
|
//
|
|
// 1. Only Tokens.get() if you are certain the token is valid. If not, you
|
|
// should first Tokens.peek() and only call Tokens.get() if all checks
|
|
// succeeded.
|
|
//
|
|
// 2. Do not consume a token when emitting an error. It is up to
|
|
// skipToLineFoldEnd() to skip the actual tokens. Because that function skips
|
|
// over blocks, it is important it knows when a block started.
|
|
//
|
|
// 3. Always unref() whatever CST node that has been allocated on error. That
|
|
// includes tokens. This avoids memory leaks. And yes, they matter when the
|
|
// compiler is permanently on such as in a language server.
|
|
//
|
|
// 5. Always unref() a LineFoldEnd or BlockEnd obtained via Tokens.get(), since
|
|
// it will never be stored somewhere
|
|
//
|
|
// 6. Maintain the invariant that a wrong parse will never advance the input stream.
|
|
|
|
namespace bolt {
|
|
|
|
bool isOperator(Token* T) {
|
|
switch (T->getKind()) {
|
|
case NodeKind::VBar:
|
|
case NodeKind::CustomOperator:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::optional<OperatorInfo> OperatorTable::getInfix(Token* T) {
|
|
auto Match = Mapping.find(T->getText());
|
|
if (Match == Mapping.end() || !Match->second.isInfix()) {
|
|
return {};
|
|
}
|
|
return Match->second;
|
|
}
|
|
|
|
bool OperatorTable::isInfix(Token* T) {
|
|
auto Match = Mapping.find(T->getText());
|
|
return Match != Mapping.end() && Match->second.isInfix();
|
|
}
|
|
|
|
bool OperatorTable::isPrefix(Token* T) {
|
|
auto Match = Mapping.find(T->getText());
|
|
return Match != Mapping.end() && Match->second.isPrefix();
|
|
}
|
|
|
|
bool OperatorTable::isSuffix(Token* T) {
|
|
auto Match = Mapping.find(T->getText());
|
|
return Match != Mapping.end() && Match->second.isSuffix();
|
|
}
|
|
|
|
void OperatorTable::add(std::string Name, unsigned Flags, int Precedence) {
|
|
Mapping.emplace(Name, OperatorInfo { Precedence, Flags });
|
|
}
|
|
|
|
Parser::Parser(TextFile& File, Stream<Token*>& S, DiagnosticEngine& DE):
|
|
File(File), Tokens(S), DE(DE) {
|
|
ExprOperators.add("**", OperatorFlags_InfixR, 10);
|
|
ExprOperators.add("*", OperatorFlags_InfixL, 5);
|
|
ExprOperators.add("/", OperatorFlags_InfixL, 5);
|
|
ExprOperators.add("+", OperatorFlags_InfixL, 4);
|
|
ExprOperators.add("-", OperatorFlags_InfixL, 4);
|
|
ExprOperators.add("<", OperatorFlags_InfixL, 3);
|
|
ExprOperators.add(">", OperatorFlags_InfixL, 3);
|
|
ExprOperators.add("<=", OperatorFlags_InfixL, 3);
|
|
ExprOperators.add(">=", OperatorFlags_InfixL, 3);
|
|
ExprOperators.add("==", OperatorFlags_InfixL, 3);
|
|
ExprOperators.add("!=", OperatorFlags_InfixL, 3);
|
|
ExprOperators.add(":", OperatorFlags_InfixL, 2);
|
|
ExprOperators.add("<|>", OperatorFlags_InfixL, 1);
|
|
ExprOperators.add("$", OperatorFlags_InfixR, 0);
|
|
}
|
|
|
|
Token* Parser::peekFirstTokenAfterAnnotationsAndModifiers() {
|
|
std::size_t I = 0;
|
|
for (;;) {
|
|
auto T0 = Tokens.peek(I++);
|
|
switch (T0->getKind()) {
|
|
case NodeKind::PubKeyword:
|
|
case NodeKind::MutKeyword:
|
|
continue;
|
|
case NodeKind::At:
|
|
for (;;) {
|
|
auto T1 = Tokens.peek(I++);
|
|
if (T1->getKind() == NodeKind::LineFoldEnd) {
|
|
break;
|
|
}
|
|
}
|
|
continue;
|
|
default:
|
|
return T0;
|
|
}
|
|
}
|
|
}
|
|
|
|
Token* Parser::expectToken(NodeKind Kind) {
|
|
auto T = Tokens.peek();
|
|
if (T->getKind() != Kind) {
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T, std::vector<NodeKind> { Kind });
|
|
return nullptr;
|
|
}
|
|
Tokens.get();
|
|
return T;
|
|
}
|
|
|
|
ListPattern* Parser::parseListPattern() {
|
|
auto LBracket = expectToken<class LBracket>();
|
|
if (!LBracket) {
|
|
return nullptr;
|
|
}
|
|
std::vector<std::tuple<Pattern*, Comma*>> Elements;
|
|
RBracket* RBracket;
|
|
auto T0 = Tokens.peek();
|
|
if (T0->getKind() == NodeKind::RBracket) {
|
|
Tokens.get();
|
|
RBracket = static_cast<class RBracket*>(T0);
|
|
goto finish;
|
|
}
|
|
for (;;) {
|
|
auto P = parseWidePattern();
|
|
if (!P) {
|
|
LBracket->unref();
|
|
for (auto [Element, Separator]: Elements) {
|
|
Element->unref();
|
|
Separator->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
auto T1 = Tokens.peek();
|
|
switch (T1->getKind()) {
|
|
case NodeKind::Comma:
|
|
Tokens.get();
|
|
Elements.push_back(std::make_tuple(P, static_cast<Comma*>(T1)));
|
|
break;
|
|
case NodeKind::RBracket:
|
|
Tokens.get();
|
|
Elements.push_back(std::make_tuple(P, nullptr));
|
|
RBracket = static_cast<class RBracket*>(T1);
|
|
goto finish;
|
|
default:
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T1, std::vector { NodeKind::Comma, NodeKind::RBracket });
|
|
}
|
|
}
|
|
finish:
|
|
return new ListPattern { LBracket, Elements, RBracket };
|
|
}
|
|
|
|
std::optional<std::vector<std::tuple<RecordPatternField*, Comma*>>> Parser::parseRecordPatternFields() {
|
|
std::vector<std::tuple<RecordPatternField*, Comma*>> Fields;
|
|
for (;;) {
|
|
auto T0 = Tokens.peek();
|
|
if (T0->getKind() == NodeKind::RBrace) {
|
|
break;
|
|
}
|
|
if (T0->getKind() == NodeKind::DotDot) {
|
|
Tokens.get();
|
|
auto DotDot = static_cast<class DotDot*>(T0);
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::RBrace) {
|
|
Fields.push_back(std::make_tuple(new RecordPatternField(DotDot), nullptr));
|
|
break;
|
|
}
|
|
auto P = parseWidePattern();
|
|
auto T2 = Tokens.peek();
|
|
if (T2->getKind() != NodeKind::RBrace) {
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T2, std::vector { NodeKind::RBrace, NodeKind::Comma });
|
|
return {};
|
|
}
|
|
Fields.push_back(std::make_tuple(new RecordPatternField(DotDot, P), nullptr));
|
|
break;
|
|
}
|
|
auto Name = expectToken<Identifier>();
|
|
Equals* Equals = nullptr;
|
|
Pattern* Pattern = nullptr;
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::Equals) {
|
|
Tokens.get();
|
|
Equals = static_cast<class Equals*>(T1);
|
|
Pattern = parseWidePattern();
|
|
}
|
|
auto Field = new RecordPatternField(Name, Equals, Pattern);
|
|
auto T2 = Tokens.peek();
|
|
if (T2->getKind() == NodeKind::RBrace) {
|
|
Fields.push_back(std::make_tuple(Field, nullptr));
|
|
break;
|
|
}
|
|
if (T2->getKind() != NodeKind::Comma) {
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T2, std::vector { NodeKind::RBrace, NodeKind::Comma });
|
|
return {};
|
|
}
|
|
Tokens.get();
|
|
auto Comma = static_cast<class Comma*>(T2);
|
|
Fields.push_back(std::make_tuple(Field, Comma));
|
|
}
|
|
return Fields;
|
|
}
|
|
|
|
Pattern* Parser::parsePrimitivePattern(bool IsNarrow) {
|
|
auto T0 = Tokens.peek();
|
|
switch (T0->getKind()) {
|
|
case NodeKind::StringLiteral:
|
|
case NodeKind::IntegerLiteral:
|
|
Tokens.get();
|
|
return new LiteralPattern(static_cast<Literal*>(T0));
|
|
case NodeKind::Identifier:
|
|
Tokens.get();
|
|
return new BindPattern(static_cast<Identifier*>(T0));
|
|
case NodeKind::LBrace:
|
|
{
|
|
Tokens.get();
|
|
auto LBrace = static_cast<class LBrace*>(T0);
|
|
auto Fields = parseRecordPatternFields();
|
|
if (!Fields) {
|
|
LBrace->unref();
|
|
skipToRBrace();
|
|
return nullptr;
|
|
}
|
|
auto RBrace = static_cast<class RBrace*>(Tokens.get());
|
|
return new RecordPattern(LBrace, *Fields, RBrace);
|
|
}
|
|
case NodeKind::IdentifierAlt:
|
|
{
|
|
Tokens.get();
|
|
auto Name = static_cast<IdentifierAlt*>(T0);
|
|
if (IsNarrow) {
|
|
return new NamedTuplePattern(Name, {});
|
|
}
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::LBrace) {
|
|
auto LBrace = static_cast<class LBrace*>(T1);
|
|
Tokens.get();
|
|
auto Fields = parseRecordPatternFields();
|
|
if (!Fields) {
|
|
LBrace->unref();
|
|
skipToRBrace();
|
|
return nullptr;
|
|
}
|
|
auto RBrace = static_cast<class RBrace*>(Tokens.get());
|
|
return new NamedRecordPattern({}, Name, LBrace, *Fields, RBrace);
|
|
}
|
|
std::vector<Pattern*> Patterns;
|
|
for (;;) {
|
|
auto T2 = Tokens.peek();
|
|
if (T2->getKind() == NodeKind::RParen
|
|
|| T2->getKind() == NodeKind::RBracket
|
|
|| T2->getKind() == NodeKind::RBrace
|
|
|| T2->getKind() == NodeKind::Comma
|
|
|| T2->getKind() == NodeKind::Colon
|
|
|| T2->getKind() == NodeKind::Equals
|
|
|| T2->getKind() == NodeKind::BlockStart
|
|
|| T2->getKind() == NodeKind::RArrowAlt) {
|
|
break;
|
|
}
|
|
auto P = parseNarrowPattern();
|
|
if (!P) {
|
|
Name->unref();
|
|
for (auto P: Patterns) {
|
|
P->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
Patterns.push_back(P);
|
|
}
|
|
return new NamedTuplePattern { Name, Patterns };
|
|
}
|
|
case NodeKind::LBracket:
|
|
return parseListPattern();
|
|
case NodeKind::LParen:
|
|
{
|
|
Tokens.get();
|
|
auto LParen = static_cast<class LParen*>(T0);
|
|
std::vector<std::tuple<Pattern*, Comma*>> Elements;
|
|
RParen* RParen;
|
|
for (;;) {
|
|
auto P = parseWidePattern();
|
|
if (!P) {
|
|
LParen->unref();
|
|
for (auto [P, Comma]: Elements) {
|
|
P->unref();
|
|
Comma->unref();
|
|
}
|
|
// TODO maybe skip to next comma?
|
|
return nullptr;
|
|
}
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::Comma) {
|
|
Tokens.get();
|
|
Elements.push_back(std::make_tuple(P, static_cast<Comma*>(T1)));
|
|
} else if (T1->getKind() == NodeKind::RParen) {
|
|
Tokens.get();
|
|
RParen = static_cast<class RParen*>(T1);
|
|
Elements.push_back(std::make_tuple(P, nullptr));
|
|
break;
|
|
} else {
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T1, std::vector { NodeKind::Comma, NodeKind::RParen });
|
|
LParen->unref();
|
|
for (auto [P, Comma]: Elements) {
|
|
P->unref();
|
|
Comma->unref();
|
|
}
|
|
// TODO maybe skip to next comma?
|
|
return nullptr;
|
|
|
|
}
|
|
}
|
|
if (Elements.size() == 1) {
|
|
return new NestedPattern { LParen, std::get<0>(Elements.front()), RParen };
|
|
}
|
|
return new TuplePattern(LParen, Elements, RParen);
|
|
}
|
|
default:
|
|
// Tokens.get();
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T0, std::vector {
|
|
NodeKind::Identifier,
|
|
NodeKind::IdentifierAlt,
|
|
NodeKind::StringLiteral,
|
|
NodeKind::IntegerLiteral,
|
|
NodeKind::LParen,
|
|
NodeKind::LBracket
|
|
});
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
Pattern* Parser::parseWidePattern() {
|
|
return parsePrimitivePattern(false);
|
|
}
|
|
|
|
Pattern* Parser::parseNarrowPattern() {
|
|
return parsePrimitivePattern(true);
|
|
}
|
|
|
|
TypeExpression* Parser::parseTypeExpression() {
|
|
return parseQualifiedTypeExpression();
|
|
}
|
|
|
|
TypeExpression* Parser::parseQualifiedTypeExpression() {
|
|
bool HasConstraints = false;
|
|
auto T0 = Tokens.peek();
|
|
if (isa<LParen>(T0)) {
|
|
std::size_t I = 1;
|
|
for (;;) {
|
|
auto T0 = Tokens.peek(I++);
|
|
switch (T0->getKind()) {
|
|
case NodeKind::RArrowAlt:
|
|
HasConstraints = true;
|
|
goto after_lookahead;
|
|
case NodeKind::Equals:
|
|
case NodeKind::BlockStart:
|
|
case NodeKind::LineFoldEnd:
|
|
case NodeKind::EndOfFile:
|
|
goto after_lookahead;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
after_lookahead:
|
|
if (!HasConstraints) {
|
|
return parseArrowTypeExpression();
|
|
}
|
|
Tokens.get();
|
|
LParen* LParen = static_cast<class LParen*>(T0);
|
|
std::vector<std::tuple<ConstraintExpression*, Comma*>> Constraints;
|
|
RParen* RParen;
|
|
RArrowAlt* RArrowAlt;
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::RParen) {
|
|
Tokens.get();
|
|
RParen = static_cast<class RParen*>(T1);
|
|
goto after_constraints;
|
|
}
|
|
for (;;) {
|
|
auto C = parseConstraintExpression();
|
|
Comma* Comma = nullptr;
|
|
auto T2 = Tokens.get();
|
|
switch (T2->getKind()) {
|
|
case NodeKind::Comma:
|
|
{
|
|
auto Comma = static_cast<class Comma*>(T2);
|
|
if (C) {
|
|
Constraints.push_back(std::make_tuple(C, Comma));
|
|
} else {
|
|
Comma->unref();
|
|
}
|
|
continue;
|
|
}
|
|
case NodeKind::RParen:
|
|
RParen = static_cast<class RParen*>(T2);
|
|
if (C) {
|
|
Constraints.push_back(std::make_tuple(C, nullptr));
|
|
}
|
|
goto after_constraints;
|
|
default:
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T2, std::vector { NodeKind::Comma, NodeKind::RArrowAlt });
|
|
return nullptr;
|
|
}
|
|
}
|
|
after_constraints:
|
|
RArrowAlt = expectToken<class RArrowAlt>();
|
|
if (!RArrowAlt) {
|
|
LParen->unref();
|
|
for (auto [CE, Comma]: Constraints) {
|
|
CE->unref();
|
|
}
|
|
RParen->unref();
|
|
return nullptr;
|
|
}
|
|
auto TE = parseArrowTypeExpression();
|
|
if (!TE) {
|
|
LParen->unref();
|
|
for (auto [CE, Comma]: Constraints) {
|
|
CE->unref();
|
|
if (Comma) {
|
|
Comma->unref();
|
|
}
|
|
}
|
|
RParen->unref();
|
|
RArrowAlt->unref();
|
|
return nullptr;
|
|
}
|
|
return new QualifiedTypeExpression(Constraints, RArrowAlt, TE);
|
|
}
|
|
|
|
TypeExpression* Parser::parsePrimitiveTypeExpression() {
|
|
auto T0 = Tokens.peek();
|
|
switch (T0->getKind()) {
|
|
case NodeKind::Identifier:
|
|
return parseVarTypeExpression();
|
|
case NodeKind::LBrace:
|
|
{
|
|
Tokens.get();
|
|
auto LBrace = static_cast<class LBrace*>(T0);
|
|
std::vector<std::tuple<RecordTypeExpressionField*, Comma*>> Fields;
|
|
VBar* VBar = nullptr;
|
|
TypeExpression* Rest = nullptr;
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::RBrace) {
|
|
break;
|
|
}
|
|
auto Name = expectToken<Identifier>();
|
|
if (Name == nullptr) {
|
|
for (auto [Field, Comma]: Fields) {
|
|
Field->unref();
|
|
Comma->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
auto Colon = expectToken<class Colon>();
|
|
if (Colon == nullptr) {
|
|
for (auto [Field, Comma]: Fields) {
|
|
Field->unref();
|
|
Comma->unref();
|
|
}
|
|
Name->unref();
|
|
return nullptr;
|
|
}
|
|
auto TE = parseTypeExpression();
|
|
if (TE == nullptr) {
|
|
for (auto [Field, Comma]: Fields) {
|
|
Field->unref();
|
|
Comma->unref();
|
|
}
|
|
Name->unref();
|
|
Colon->unref();
|
|
return nullptr;
|
|
}
|
|
auto Field = new RecordTypeExpressionField(Name, Colon, TE);
|
|
auto T3 = Tokens.peek();
|
|
if (T3->getKind() == NodeKind::RBrace) {
|
|
Fields.push_back(std::make_tuple(Field, nullptr));
|
|
break;
|
|
}
|
|
if (T3->getKind() == NodeKind::VBar) {
|
|
Tokens.get();
|
|
Fields.push_back(std::make_tuple(Field, nullptr));
|
|
VBar = static_cast<class VBar*>(T3);
|
|
Rest = parseTypeExpression();
|
|
if (!Rest) {
|
|
for (auto [Field, Comma]: Fields) {
|
|
Field->unref();
|
|
Comma->unref();
|
|
}
|
|
Field->unref();
|
|
return nullptr;
|
|
}
|
|
auto T4 = Tokens.peek();
|
|
if (T4->getKind() != NodeKind::RBrace) {
|
|
for (auto [Field, Comma]: Fields) {
|
|
Field->unref();
|
|
Comma->unref();
|
|
}
|
|
Field->unref();
|
|
Rest->unref();
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T4, std::vector { NodeKind::RBrace });
|
|
return nullptr;
|
|
}
|
|
break;
|
|
}
|
|
if (T3->getKind() == NodeKind::Comma) {
|
|
Tokens.get();
|
|
auto Comma = static_cast<class Comma*>(T3);
|
|
Fields.push_back(std::make_tuple(Field, Comma));
|
|
continue;
|
|
}
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T3, std::vector { NodeKind::RBrace, NodeKind::Comma, NodeKind::VBar });
|
|
for (auto [Field, Comma]: Fields) {
|
|
Field->unref();
|
|
Comma->unref();
|
|
}
|
|
Field->unref();
|
|
return nullptr;
|
|
}
|
|
auto RBrace = static_cast<class RBrace*>(Tokens.get());
|
|
return new RecordTypeExpression(LBrace, Fields, VBar, Rest, RBrace);
|
|
}
|
|
case NodeKind::LParen:
|
|
{
|
|
Tokens.get();
|
|
auto LParen = static_cast<class LParen*>(T0);
|
|
std::vector<std::tuple<TypeExpression*, Comma*>> Elements;
|
|
RParen* RParen;
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
if (isa<class RParen>(T1)) {
|
|
Tokens.get();
|
|
RParen = static_cast<class RParen*>(T1);
|
|
break;
|
|
}
|
|
auto TE = parseTypeExpression();
|
|
if (!TE) {
|
|
LParen->unref();
|
|
for (auto [TE, Comma]: Elements) {
|
|
TE->unref();
|
|
Comma->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
auto T2 = Tokens.get();
|
|
switch (T2->getKind()) {
|
|
case NodeKind::RParen:
|
|
RParen = static_cast<class RParen*>(T1);
|
|
Elements.push_back({ TE, nullptr });
|
|
goto after_tuple_element;
|
|
case NodeKind::Comma:
|
|
Elements.push_back({ TE, static_cast<Comma*>(T2) });
|
|
continue;
|
|
default:
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T2, std::vector { NodeKind::Comma, NodeKind::RParen });
|
|
LParen->unref();
|
|
for (auto [TE, Comma]: Elements) {
|
|
TE->unref();
|
|
Comma->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
}
|
|
after_tuple_element:
|
|
if (Elements.size() == 1) {
|
|
return new NestedTypeExpression { LParen, std::get<0>(Elements.front()), RParen };
|
|
}
|
|
return new TupleTypeExpression { LParen, Elements, RParen };
|
|
}
|
|
case NodeKind::IdentifierAlt:
|
|
return parseReferenceTypeExpression();
|
|
default:
|
|
// Tokens.get();
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T0, std::vector { NodeKind::Identifier, NodeKind::IdentifierAlt, NodeKind::LParen });
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
ReferenceTypeExpression* Parser::parseReferenceTypeExpression() {
|
|
std::vector<std::tuple<IdentifierAlt*, Dot*>> ModulePath;
|
|
auto Name = expectToken<IdentifierAlt>();
|
|
if (!Name) {
|
|
return nullptr;
|
|
}
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() != NodeKind::Dot) {
|
|
break;
|
|
}
|
|
Tokens.get();
|
|
ModulePath.push_back(std::make_tuple(static_cast<IdentifierAlt*>(Name), static_cast<Dot*>(T1)));
|
|
Name = expectToken<IdentifierAlt>();
|
|
if (!Name) {
|
|
for (auto [Name, Dot]: ModulePath) {
|
|
Name->unref();
|
|
Dot->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
}
|
|
return new ReferenceTypeExpression(ModulePath, static_cast<IdentifierAlt*>(Name));
|
|
}
|
|
|
|
TypeExpression* Parser::parseAppTypeExpression() {
|
|
auto OpTy = parsePrimitiveTypeExpression();
|
|
if (!OpTy) {
|
|
return nullptr;
|
|
}
|
|
std::vector<TypeExpression*> ArgTys;
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
auto Kind = T1->getKind();
|
|
if (Kind == NodeKind::Comma
|
|
|| Kind == NodeKind::RArrow
|
|
|| Kind == NodeKind::Equals
|
|
|| Kind == NodeKind::BlockStart
|
|
|| Kind == NodeKind::LineFoldEnd
|
|
|| Kind == NodeKind::EndOfFile
|
|
|| Kind == NodeKind::RParen
|
|
|| Kind == NodeKind::RBracket
|
|
|| Kind == NodeKind::RBrace
|
|
|| Kind == NodeKind::VBar) {
|
|
break;
|
|
}
|
|
auto TE = parsePrimitiveTypeExpression();
|
|
if (!TE) {
|
|
OpTy->unref();
|
|
for (auto Arg: ArgTys) {
|
|
Arg->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
ArgTys.push_back(TE);
|
|
}
|
|
if (ArgTys.empty()) {
|
|
return OpTy;
|
|
}
|
|
return new AppTypeExpression { OpTy, ArgTys };
|
|
}
|
|
|
|
TypeExpression* Parser::parseArrowTypeExpression() {
|
|
auto RetType = parseAppTypeExpression();
|
|
if (RetType == nullptr) {
|
|
return nullptr;
|
|
}
|
|
std::vector<TypeExpression*> ParamTypes;
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() != NodeKind::RArrow) {
|
|
break;
|
|
}
|
|
Tokens.get();
|
|
ParamTypes.push_back(RetType);
|
|
RetType = parseAppTypeExpression();
|
|
if (!RetType) {
|
|
for (auto ParamType: ParamTypes) {
|
|
ParamType->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
}
|
|
if (!ParamTypes.empty()) {
|
|
return new ArrowTypeExpression(ParamTypes, RetType);
|
|
}
|
|
return RetType;
|
|
}
|
|
|
|
MatchExpression* Parser::parseMatchExpression() {
|
|
auto T0 = expectToken<MatchKeyword>();
|
|
if (!T0) {
|
|
return nullptr;
|
|
}
|
|
auto T1 = Tokens.peek();
|
|
Expression* Value;
|
|
BlockStart* BlockStart;
|
|
if (isa<class BlockStart>(T1)) {
|
|
Value = nullptr;
|
|
BlockStart = static_cast<class BlockStart*>(T1);
|
|
Tokens.get();
|
|
} else {
|
|
Value = parseExpression();
|
|
if (!Value) {
|
|
T0->unref();
|
|
return nullptr;
|
|
}
|
|
BlockStart = expectToken<class BlockStart>();
|
|
if (!BlockStart) {
|
|
T0->unref();
|
|
Value->unref();
|
|
return nullptr;
|
|
}
|
|
}
|
|
std::vector<MatchCase*> Cases;
|
|
for (;;) {
|
|
auto T2 = Tokens.peek();
|
|
if (isa<BlockEnd>(T2)) {
|
|
Tokens.get()->unref();
|
|
break;
|
|
}
|
|
auto Pattern = parseWidePattern();
|
|
if (!Pattern) {
|
|
skipPastLineFoldEnd();
|
|
continue;
|
|
}
|
|
auto RArrowAlt = expectToken<class RArrowAlt>();
|
|
if (!RArrowAlt) {
|
|
Pattern->unref();
|
|
skipPastLineFoldEnd();
|
|
continue;
|
|
}
|
|
auto Expression = parseExpression();
|
|
if (!Expression) {
|
|
Pattern->unref();
|
|
RArrowAlt->unref();
|
|
skipPastLineFoldEnd();
|
|
continue;
|
|
}
|
|
checkLineFoldEnd();
|
|
Cases.push_back(new MatchCase { Pattern, RArrowAlt, Expression });
|
|
}
|
|
return new MatchExpression(static_cast<MatchKeyword*>(T0), Value, BlockStart, Cases);
|
|
}
|
|
|
|
RecordExpression* Parser::parseRecordExpression() {
|
|
auto LBrace = expectToken<class LBrace>();
|
|
if (!LBrace) {
|
|
return nullptr;
|
|
}
|
|
RBrace* RBrace;
|
|
auto T1 = Tokens.peek();
|
|
std::vector<std::tuple<RecordExpressionField*, Comma*>> Fields;
|
|
if (T1->getKind() == NodeKind::RBrace) {
|
|
Tokens.get();
|
|
RBrace = static_cast<class RBrace*>(T1);
|
|
} else {
|
|
for (;;) {
|
|
auto Name = expectToken<Identifier>();
|
|
if (!Name) {
|
|
LBrace->unref();
|
|
for (auto [Field, Comma]: Fields) {
|
|
Field->unref();
|
|
Comma->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
auto Equals = expectToken<class Equals>();
|
|
if (!Equals) {
|
|
LBrace->unref();
|
|
for (auto [Field, Comma]: Fields) {
|
|
Field->unref();
|
|
Comma->unref();
|
|
}
|
|
Name->unref();
|
|
return nullptr;
|
|
}
|
|
auto E = parseExpression();
|
|
if (!E) {
|
|
LBrace->unref();
|
|
for (auto [Field, Comma]: Fields) {
|
|
Field->unref();
|
|
Comma->unref();
|
|
}
|
|
Name->unref();
|
|
Equals->unref();
|
|
return nullptr;
|
|
}
|
|
auto T2 = Tokens.peek();
|
|
if (T2->getKind() == NodeKind::Comma) {
|
|
Tokens.get();
|
|
Fields.push_back(std::make_tuple(new RecordExpressionField { Name, Equals, E }, static_cast<Comma*>(T2)));
|
|
} else if (T2->getKind() == NodeKind::RBrace) {
|
|
Tokens.get();
|
|
RBrace = static_cast<class RBrace*>(T2);
|
|
Fields.push_back(std::make_tuple(new RecordExpressionField { Name, Equals, E }, nullptr));
|
|
break;
|
|
} else {
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T2, std::vector { NodeKind::Comma, NodeKind::RBrace });
|
|
LBrace->unref();
|
|
for (auto [Field, Comma]: Fields) {
|
|
Field->unref();
|
|
Comma->unref();
|
|
}
|
|
Name->unref();
|
|
Equals->unref();
|
|
E->unref();
|
|
return nullptr;
|
|
}
|
|
}
|
|
}
|
|
return new RecordExpression { LBrace, Fields, RBrace };
|
|
}
|
|
|
|
Expression* Parser::parsePrimitiveExpression() {
|
|
auto Annotations = parseAnnotations();
|
|
auto T0 = Tokens.peek();
|
|
switch (T0->getKind()) {
|
|
case NodeKind::Identifier:
|
|
case NodeKind::IdentifierAlt:
|
|
{
|
|
std::vector<std::tuple<IdentifierAlt*, Dot*>> ModulePath;
|
|
for (;;) {
|
|
auto T1 = Tokens.peek(0);
|
|
auto T2 = Tokens.peek(1);
|
|
if (!isa<IdentifierAlt>(T1) || !isa<Dot>(T2)) {
|
|
break;
|
|
}
|
|
Tokens.get();
|
|
Tokens.get();
|
|
ModulePath.push_back(std::make_tuple(static_cast<IdentifierAlt*>(T1), static_cast<class Dot*>(T2)));
|
|
}
|
|
auto T3 = Tokens.get();
|
|
if (!T3->is<Identifier>() && !T3->is<IdentifierAlt>()) {
|
|
for (auto [Name, Dot]: ModulePath) {
|
|
Name->unref();
|
|
Dot->unref();
|
|
}
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T3, std::vector { NodeKind::Identifier, NodeKind::IdentifierAlt });
|
|
return nullptr;
|
|
}
|
|
return new ReferenceExpression(Annotations, ModulePath, static_cast<Symbol*>(T3));
|
|
}
|
|
case NodeKind::LParen:
|
|
{
|
|
Tokens.get();
|
|
std::vector<std::tuple<Expression*, Comma*>> Elements;
|
|
auto LParen = static_cast<class LParen*>(T0);
|
|
RParen* RParen;
|
|
auto T1 = Tokens.peek();
|
|
if (isa<class RParen>(T1)) {
|
|
Tokens.get();
|
|
RParen = static_cast<class RParen*>(T1);
|
|
goto after_tuple_elements;
|
|
}
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
auto E = parseExpression();
|
|
if (!E) {
|
|
LParen->unref();
|
|
for (auto [E, Comma]: Elements) {
|
|
E->unref();
|
|
Comma->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
auto T2 = Tokens.get();
|
|
switch (T2->getKind()) {
|
|
case NodeKind::RParen:
|
|
RParen = static_cast<class RParen*>(T2);
|
|
Elements.push_back({ E, nullptr });
|
|
goto after_tuple_elements;
|
|
case NodeKind::Comma:
|
|
Elements.push_back({ E, static_cast<class Comma*>(T2) });
|
|
break;
|
|
default:
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T2, std::vector { NodeKind::RParen, NodeKind::Comma });
|
|
LParen->unref();
|
|
for (auto [E, Comma]: Elements) {
|
|
E->unref();
|
|
Comma->unref();
|
|
}
|
|
return nullptr;
|
|
case NodeKind::LineFoldEnd:
|
|
case NodeKind::BlockStart:
|
|
case NodeKind::EndOfFile:
|
|
// Can recover from this one
|
|
RParen = nullptr;
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T2, std::vector { NodeKind::RParen, NodeKind::Comma });
|
|
goto after_tuple_elements;
|
|
}
|
|
}
|
|
after_tuple_elements:
|
|
if (Elements.size() == 1 && !std::get<1>(Elements.front())) {
|
|
return new NestedExpression(Annotations, LParen, std::get<0>(Elements.front()), RParen);
|
|
}
|
|
return new TupleExpression { Annotations, LParen, Elements, RParen };
|
|
}
|
|
case NodeKind::MatchKeyword:
|
|
return parseMatchExpression();
|
|
case NodeKind::IntegerLiteral:
|
|
case NodeKind::StringLiteral:
|
|
Tokens.get();
|
|
return new LiteralExpression(Annotations, static_cast<Literal*>(T0));
|
|
case NodeKind::LBrace:
|
|
return parseRecordExpression();
|
|
default:
|
|
// Tokens.get();
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T0, std::vector {
|
|
NodeKind::MatchKeyword,
|
|
NodeKind::Identifier,
|
|
NodeKind::IdentifierAlt,
|
|
NodeKind::LParen,
|
|
NodeKind::LBrace,
|
|
NodeKind::IntegerLiteral,
|
|
NodeKind::StringLiteral
|
|
});
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
Expression* Parser::parseMemberExpression() {
|
|
auto E = parsePrimitiveExpression();
|
|
if (!E) {
|
|
return nullptr;
|
|
}
|
|
for (;;) {
|
|
auto T1 = Tokens.peek(0);
|
|
auto T2 = Tokens.peek(1);
|
|
if (!isa<Dot>(T1)) {
|
|
break;
|
|
}
|
|
switch (T2->getKind()) {
|
|
case NodeKind::IntegerLiteral:
|
|
case NodeKind::Identifier:
|
|
{
|
|
Tokens.get();
|
|
Tokens.get();
|
|
auto Annotations = E->Annotations;
|
|
E->Annotations = {};
|
|
E = new MemberExpression { Annotations, E, static_cast<Dot*>(T1), T2 };
|
|
break;
|
|
}
|
|
default:
|
|
goto finish;
|
|
}
|
|
}
|
|
finish:
|
|
return E;
|
|
}
|
|
|
|
Expression* Parser::parseCallExpression() {
|
|
auto Operator = parseMemberExpression();
|
|
if (!Operator) {
|
|
return nullptr;
|
|
}
|
|
std::vector<Expression*> Args;
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::LineFoldEnd
|
|
|| T1->getKind() == NodeKind::RParen
|
|
|| T1->getKind() == NodeKind::RBracket
|
|
|| T1->getKind() == NodeKind::RBrace
|
|
|| T1->getKind() == NodeKind::BlockStart
|
|
|| T1->getKind() == NodeKind::Comma
|
|
|| ExprOperators.isInfix(T1)) {
|
|
break;
|
|
}
|
|
auto Arg = parseMemberExpression();
|
|
if (!Arg) {
|
|
Operator->unref();
|
|
for (auto Arg: Args) {
|
|
Arg->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
Args.push_back(Arg);
|
|
}
|
|
if (Args.empty()) {
|
|
return Operator;
|
|
}
|
|
auto Annotations = Operator->Annotations;
|
|
Operator->Annotations = {};
|
|
return new CallExpression(Annotations, Operator, Args);
|
|
}
|
|
|
|
Expression* Parser::parseUnaryExpression() {
|
|
std::vector<Token*> Prefix;
|
|
for (;;) {
|
|
auto T0 = Tokens.peek();
|
|
if (!ExprOperators.isPrefix(T0)) {
|
|
break;
|
|
}
|
|
Tokens.get();
|
|
Prefix.push_back(T0);
|
|
}
|
|
auto E = parseCallExpression();
|
|
if (!E) {
|
|
for (auto Tok: Prefix) {
|
|
Tok->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
for (auto Iter = Prefix.rbegin(); Iter != Prefix.rend(); Iter++) {
|
|
E = new PrefixExpression(*Iter, E);
|
|
}
|
|
return E;
|
|
}
|
|
|
|
Expression* Parser::parseInfixOperatorAfterExpression(Expression* Left, int MinPrecedence) {
|
|
for (;;) {
|
|
auto T0 = Tokens.peek();
|
|
auto Info0 = ExprOperators.getInfix(T0);
|
|
if (!Info0 || Info0->Precedence < MinPrecedence) {
|
|
break;
|
|
}
|
|
Tokens.get();
|
|
auto Right = parseUnaryExpression();
|
|
if (!Right) {
|
|
Left->unref();
|
|
T0->unref();
|
|
return nullptr;
|
|
}
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
auto Info1 = ExprOperators.getInfix(T1);
|
|
if (!Info1 || Info1->Precedence < Info0->Precedence && (Info1->Precedence > Info0->Precedence || Info1->isRightAssoc())) {
|
|
break;
|
|
}
|
|
auto NewRight = parseInfixOperatorAfterExpression(Right, Info1->Precedence);
|
|
if (!NewRight) {
|
|
Left->unref();
|
|
T0->unref();
|
|
Right->unref();
|
|
return nullptr;
|
|
}
|
|
Right = NewRight;
|
|
}
|
|
Left = new InfixExpression(Left, T0, Right);
|
|
}
|
|
return Left;
|
|
}
|
|
|
|
Expression* Parser::parseExpression() {
|
|
auto Left = parseUnaryExpression();
|
|
if (!Left) {
|
|
return nullptr;
|
|
}
|
|
return parseInfixOperatorAfterExpression(Left, 0);
|
|
}
|
|
|
|
ExpressionStatement* Parser::parseExpressionStatement() {
|
|
auto E = parseExpression();
|
|
if (!E) {
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
checkLineFoldEnd();
|
|
return new ExpressionStatement(E);
|
|
}
|
|
|
|
ReturnStatement* Parser::parseReturnStatement() {
|
|
auto Annotations = parseAnnotations();
|
|
auto ReturnKeyword = expectToken<class ReturnKeyword>();
|
|
if (!ReturnKeyword) {
|
|
return nullptr;
|
|
}
|
|
Expression* Expression;
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::LineFoldEnd) {
|
|
Tokens.get()->unref();
|
|
Expression = nullptr;
|
|
} else {
|
|
Expression = parseExpression();
|
|
if (!Expression) {
|
|
ReturnKeyword->unref();
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
checkLineFoldEnd();
|
|
}
|
|
return new ReturnStatement(Annotations, ReturnKeyword, Expression);
|
|
}
|
|
|
|
IfStatement* Parser::parseIfStatement() {
|
|
std::vector<IfStatementPart*> Parts;
|
|
auto Annotations = parseAnnotations();
|
|
auto IfKeyword = expectToken<class IfKeyword>();
|
|
auto Test = parseExpression();
|
|
if (!Test) {
|
|
IfKeyword->unref();
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
auto T1 = expectToken<BlockStart>();
|
|
if (!T1) {
|
|
IfKeyword->unref();
|
|
Test->unref();
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
std::vector<Node*> Then;
|
|
for (;;) {
|
|
auto T2 = Tokens.peek();
|
|
if (T2->getKind() == NodeKind::BlockEnd) {
|
|
Tokens.get()->unref();
|
|
break;
|
|
}
|
|
auto Element = parseLetBodyElement();
|
|
if (Element) {
|
|
Then.push_back(Element);
|
|
}
|
|
}
|
|
Tokens.get()->unref(); // Always a LineFoldEnd
|
|
Parts.push_back(new IfStatementPart(Annotations, IfKeyword, Test, T1, Then));
|
|
for (;;) {
|
|
auto T3 = peekFirstTokenAfterAnnotationsAndModifiers();
|
|
if (T3->getKind() != NodeKind::ElseKeyword && T3->getKind() != NodeKind::ElifKeyword) {
|
|
break;
|
|
}
|
|
auto Annotations = parseAnnotations();
|
|
Tokens.get();
|
|
Expression* Test = nullptr;
|
|
if (T3->getKind() == NodeKind::ElifKeyword) {
|
|
Test = parseExpression();
|
|
}
|
|
auto T4 = expectToken<BlockStart>();
|
|
if (!T4) {
|
|
for (auto Part: Parts) {
|
|
Part->unref();
|
|
}
|
|
return nullptr;
|
|
}
|
|
std::vector<Node*> Alt;
|
|
for (;;) {
|
|
auto T5 = Tokens.peek();
|
|
if (T5->getKind() == NodeKind::BlockEnd) {
|
|
Tokens.get()->unref();
|
|
break;
|
|
}
|
|
auto Element = parseLetBodyElement();
|
|
if (Element) {
|
|
Alt.push_back(Element);
|
|
}
|
|
}
|
|
Tokens.get()->unref(); // Always a LineFoldEnd
|
|
Parts.push_back(new IfStatementPart(Annotations, T3, Test, T4, Alt));
|
|
if (T3->getKind() == NodeKind::ElseKeyword) {
|
|
break;
|
|
}
|
|
}
|
|
return new IfStatement(Parts);
|
|
}
|
|
|
|
LetDeclaration* Parser::parseLetDeclaration() {
|
|
|
|
auto Annotations = parseAnnotations();
|
|
PubKeyword* Pub = nullptr;
|
|
ForeignKeyword* Foreign = nullptr;
|
|
LetKeyword* Let;
|
|
MutKeyword* Mut = nullptr;
|
|
Pattern* Name;
|
|
std::vector<Parameter*> Params;
|
|
TypeAssert* TA = nullptr;
|
|
LetBody* Body = nullptr;
|
|
|
|
auto T0 = Tokens.get();
|
|
if (T0->getKind() == NodeKind::PubKeyword) {
|
|
Pub = static_cast<PubKeyword*>(T0);
|
|
T0 = Tokens.get();
|
|
}
|
|
if (T0->getKind() == NodeKind::ForeignKeyword) {
|
|
Foreign = static_cast<ForeignKeyword*>(T0);
|
|
T0 = Tokens.get();
|
|
}
|
|
if (T0->getKind() != NodeKind::LetKeyword) {
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T0, std::vector { NodeKind::LetKeyword });
|
|
if (Pub) {
|
|
Pub->unref();
|
|
}
|
|
if (Foreign) {
|
|
Foreign->unref();
|
|
}
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
Let = static_cast<LetKeyword*>(T0);
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::MutKeyword) {
|
|
Tokens.get();
|
|
Mut = static_cast<MutKeyword*>(T1);
|
|
}
|
|
|
|
auto T2 = Tokens.peek(0);
|
|
auto T3 = Tokens.peek(1);
|
|
auto T4 = Tokens.peek(2);
|
|
if (isOperator(T2)) {
|
|
Tokens.get();
|
|
auto P1 = parseNarrowPattern();
|
|
Params.push_back(new Parameter(P1, nullptr));
|
|
Name = new BindPattern(T2);
|
|
goto after_params;
|
|
} else if (isOperator(T3) && (T4->getKind() == NodeKind::Colon || T4->getKind() == NodeKind::Equals || T4->getKind() == NodeKind::BlockStart || T4->getKind() == NodeKind::LineFoldEnd)) {
|
|
auto P1 = parseNarrowPattern();
|
|
Params.push_back(new Parameter(P1, nullptr));
|
|
Tokens.get();
|
|
Name = new BindPattern(T3);
|
|
goto after_params;
|
|
} else if (T2->getKind() == NodeKind::LParen && isOperator(T3) && T4->getKind() == NodeKind::RParen) {
|
|
Tokens.get();
|
|
Tokens.get();
|
|
Tokens.get();
|
|
Name = new BindPattern(
|
|
new WrappedOperator(
|
|
static_cast<class LParen*>(T2),
|
|
T3,
|
|
static_cast<class RParen*>(T3)
|
|
)
|
|
);
|
|
} else if (isOperator(T3)) {
|
|
auto P1 = parseNarrowPattern();
|
|
Params.push_back(new Parameter(P1, nullptr));
|
|
Tokens.get();
|
|
auto P2 = parseNarrowPattern();
|
|
Params.push_back(new Parameter(P2, nullptr));
|
|
Name = new BindPattern(T3);
|
|
goto after_params;
|
|
} else {
|
|
Name = parseNarrowPattern();
|
|
if (!Name) {
|
|
if (Pub) {
|
|
Pub->unref();
|
|
}
|
|
if (Foreign) {
|
|
Foreign->unref();
|
|
}
|
|
Let->unref();
|
|
if (Mut) {
|
|
Mut->unref();
|
|
}
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
for (;;) {
|
|
auto T5 = Tokens.peek();
|
|
switch (T5->getKind()) {
|
|
case NodeKind::LineFoldEnd:
|
|
case NodeKind::BlockStart:
|
|
case NodeKind::Equals:
|
|
case NodeKind::Colon:
|
|
goto after_params;
|
|
default:
|
|
auto P = parseNarrowPattern();
|
|
if (!P) {
|
|
Tokens.get();
|
|
P = new BindPattern(new Identifier("_"));
|
|
}
|
|
Params.push_back(new Parameter(P, nullptr));
|
|
}
|
|
}
|
|
|
|
after_params:
|
|
|
|
auto T5 = Tokens.peek();
|
|
|
|
if (T5->getKind() == NodeKind::Colon) {
|
|
Tokens.get();
|
|
auto TE = parseTypeExpression();
|
|
if (TE) {
|
|
TA = new TypeAssert(static_cast<Colon*>(T5), TE);
|
|
} else {
|
|
skipPastLineFoldEnd();
|
|
goto finish;
|
|
}
|
|
T5 = Tokens.peek();
|
|
}
|
|
|
|
switch (T5->getKind()) {
|
|
case NodeKind::BlockStart:
|
|
{
|
|
Tokens.get();
|
|
std::vector<Node*> Elements;
|
|
for (;;) {
|
|
auto T6 = Tokens.peek();
|
|
if (T6->getKind() == NodeKind::BlockEnd) {
|
|
break;
|
|
}
|
|
auto Element = parseLetBodyElement();
|
|
if (Element) {
|
|
Elements.push_back(Element);
|
|
}
|
|
}
|
|
Tokens.get()->unref(); // Always a BlockEnd
|
|
Body = new LetBlockBody(static_cast<BlockStart*>(T5), Elements);
|
|
break;
|
|
}
|
|
case NodeKind::Equals:
|
|
{
|
|
Tokens.get();
|
|
auto E = parseExpression();
|
|
if (!E) {
|
|
skipPastLineFoldEnd();
|
|
goto finish;
|
|
}
|
|
Body = new LetExprBody(static_cast<Equals*>(T5), E);
|
|
break;
|
|
}
|
|
case NodeKind::LineFoldEnd:
|
|
break;
|
|
default:
|
|
std::vector<NodeKind> Expected { NodeKind::BlockStart, NodeKind::LineFoldEnd, NodeKind::Equals };
|
|
if (TA == nullptr) {
|
|
// First tokens of TypeAssert
|
|
Expected.push_back(NodeKind::Colon);
|
|
// First tokens of Pattern
|
|
Expected.push_back(NodeKind::Identifier);
|
|
}
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T5, Expected);
|
|
}
|
|
|
|
checkLineFoldEnd();
|
|
|
|
finish:
|
|
|
|
return new LetDeclaration(
|
|
Annotations,
|
|
Pub,
|
|
Foreign,
|
|
Let,
|
|
Mut,
|
|
Name,
|
|
Params,
|
|
TA,
|
|
Body
|
|
);
|
|
}
|
|
|
|
Node* Parser::parseLetBodyElement() {
|
|
auto T0 = peekFirstTokenAfterAnnotationsAndModifiers();
|
|
switch (T0->getKind()) {
|
|
case NodeKind::LetKeyword:
|
|
return parseLetDeclaration();
|
|
case NodeKind::ReturnKeyword:
|
|
return parseReturnStatement();
|
|
case NodeKind::IfKeyword:
|
|
return parseIfStatement();
|
|
default:
|
|
return parseExpressionStatement();
|
|
}
|
|
}
|
|
|
|
ConstraintExpression* Parser::parseConstraintExpression() {
|
|
bool HasTilde = false;
|
|
for (std::size_t I = 0; ; I++) {
|
|
auto Tok = Tokens.peek(I);
|
|
switch (Tok->getKind()) {
|
|
case NodeKind::Tilde:
|
|
HasTilde = true;
|
|
goto after_lookahead;
|
|
case NodeKind::RParen:
|
|
case NodeKind::Comma:
|
|
case NodeKind::RArrowAlt:
|
|
case NodeKind::EndOfFile:
|
|
goto after_lookahead;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
after_lookahead:
|
|
if (HasTilde) {
|
|
auto Left = parseArrowTypeExpression();
|
|
if (!Left) {
|
|
return nullptr;
|
|
}
|
|
auto Tilde = expectToken<class Tilde>();
|
|
if (!Tilde) {
|
|
Left->unref();
|
|
return nullptr;
|
|
}
|
|
auto Right = parseArrowTypeExpression();
|
|
if (!Right) {
|
|
Left->unref();
|
|
Tilde->unref();
|
|
return nullptr;
|
|
}
|
|
return new EqualityConstraintExpression { Left, Tilde, Right };
|
|
}
|
|
auto Name = expectToken<IdentifierAlt>();
|
|
if (!Name) {
|
|
return nullptr;
|
|
}
|
|
std::vector<VarTypeExpression*> TEs;
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
switch (T1->getKind()) {
|
|
case NodeKind::RParen:
|
|
case NodeKind::RArrowAlt:
|
|
case NodeKind::Comma:
|
|
goto after_vars;
|
|
case NodeKind::Identifier:
|
|
Tokens.get();
|
|
TEs.push_back(new VarTypeExpression { static_cast<Identifier*>(T1) });
|
|
break;
|
|
default:
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T1, std::vector { NodeKind::RParen, NodeKind::RArrowAlt, NodeKind::Comma, NodeKind::Identifier });
|
|
Name->unref();
|
|
return nullptr;
|
|
}
|
|
}
|
|
after_vars:
|
|
return new TypeclassConstraintExpression { Name, TEs };
|
|
}
|
|
|
|
VarTypeExpression* Parser::parseVarTypeExpression() {
|
|
auto Name = expectToken<Identifier>();
|
|
if (!Name) {
|
|
return nullptr;
|
|
}
|
|
for (auto Ch: Name->Text) {
|
|
if (!std::islower(Ch)) {
|
|
// TODO
|
|
// DE.add<TypeVarMustContainLowercaseLettersDiagnostic>(Name);
|
|
Name->unref();
|
|
return nullptr;
|
|
}
|
|
}
|
|
return new VarTypeExpression { Name };
|
|
}
|
|
|
|
InstanceDeclaration* Parser::parseInstanceDeclaration() {
|
|
auto InstanceKeyword = expectToken<class InstanceKeyword>();
|
|
if (!InstanceKeyword) {
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
auto Name = expectToken<IdentifierAlt>();
|
|
if (!Name) {
|
|
InstanceKeyword->unref();
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
std::vector<TypeExpression*> TypeExps;
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
if (T1->is<BlockStart>()) {
|
|
break;
|
|
}
|
|
auto TE = parseTypeExpression();
|
|
if (!TE) {
|
|
InstanceKeyword->unref();
|
|
Name->unref();
|
|
for (auto TE: TypeExps) {
|
|
TE->unref();
|
|
}
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
TypeExps.push_back(TE);
|
|
}
|
|
auto BlockStart = expectToken<class BlockStart>();
|
|
if (!BlockStart) {
|
|
InstanceKeyword->unref();
|
|
Name->unref();
|
|
for (auto TE: TypeExps) {
|
|
TE->unref();
|
|
}
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
std::vector<Node*> Elements;
|
|
for (;;) {
|
|
auto T2 = Tokens.peek();
|
|
if (T2->is<BlockEnd>()) {
|
|
Tokens.get()->unref();
|
|
break;
|
|
}
|
|
auto Element = parseClassElement();
|
|
if (Element) {
|
|
Elements.push_back(Element);
|
|
}
|
|
}
|
|
checkLineFoldEnd();
|
|
return new InstanceDeclaration(
|
|
InstanceKeyword,
|
|
Name,
|
|
TypeExps,
|
|
BlockStart,
|
|
Elements
|
|
);
|
|
}
|
|
|
|
ClassDeclaration* Parser::parseClassDeclaration() {
|
|
PubKeyword* PubKeyword = nullptr;
|
|
auto T0 = Tokens.peek();
|
|
if (T0->getKind() == NodeKind::PubKeyword) {
|
|
Tokens.get();
|
|
PubKeyword = static_cast<class PubKeyword*>(T0);
|
|
}
|
|
auto ClassKeyword = expectToken<class ClassKeyword>();
|
|
if (!ClassKeyword) {
|
|
if (PubKeyword) {
|
|
PubKeyword->unref();
|
|
}
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
auto Name = expectToken<IdentifierAlt>();
|
|
if (!Name) {
|
|
if (PubKeyword) {
|
|
PubKeyword->unref();
|
|
}
|
|
ClassKeyword->unref();
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
std::vector<VarTypeExpression*> TypeVars;
|
|
for (;;) {
|
|
auto T2 = Tokens.peek();
|
|
if (T2->getKind() == NodeKind::BlockStart) {
|
|
break;
|
|
}
|
|
auto TE = parseVarTypeExpression();
|
|
if (!TE) {
|
|
if (PubKeyword) {
|
|
PubKeyword->unref();
|
|
}
|
|
ClassKeyword->unref();
|
|
for (auto TV: TypeVars) {
|
|
TV->unref();
|
|
}
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
TypeVars.push_back(TE);
|
|
}
|
|
auto BlockStart = expectToken<class BlockStart>();
|
|
if (!BlockStart) {
|
|
if (PubKeyword) {
|
|
PubKeyword->unref();
|
|
}
|
|
ClassKeyword->unref();
|
|
for (auto TV: TypeVars) {
|
|
TV->unref();
|
|
}
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
std::vector<Node*> Elements;
|
|
for (;;) {
|
|
auto T2 = Tokens.peek();
|
|
if (T2->is<BlockEnd>()) {
|
|
Tokens.get()->unref();
|
|
break;
|
|
}
|
|
auto Element = parseClassElement();
|
|
if (Element) {
|
|
Elements.push_back(Element);
|
|
}
|
|
}
|
|
Tokens.get()->unref(); // Always a LineFoldEnd
|
|
return new ClassDeclaration(
|
|
PubKeyword,
|
|
ClassKeyword,
|
|
Name,
|
|
TypeVars,
|
|
BlockStart,
|
|
Elements
|
|
);
|
|
}
|
|
|
|
std::vector<RecordDeclarationField*> Parser::parseRecordDeclarationFields() {
|
|
std::vector<RecordDeclarationField*> Fields;
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::BlockEnd) {
|
|
Tokens.get()->unref();
|
|
break;
|
|
}
|
|
auto Name = expectToken<Identifier>();
|
|
if (!Name) {
|
|
skipPastLineFoldEnd();
|
|
continue;
|
|
}
|
|
auto Colon = expectToken<class Colon>();
|
|
if (!Colon) {
|
|
Name->unref();
|
|
skipPastLineFoldEnd();
|
|
continue;
|
|
}
|
|
auto TE = parseTypeExpression();
|
|
if (!TE) {
|
|
Name->unref();
|
|
Colon->unref();
|
|
skipPastLineFoldEnd();
|
|
continue;
|
|
}
|
|
checkLineFoldEnd();
|
|
Fields.push_back(new RecordDeclarationField { Name, Colon, TE });
|
|
}
|
|
return Fields;
|
|
}
|
|
|
|
RecordDeclaration* Parser::parseRecordDeclaration() {
|
|
auto T0 = Tokens.peek();
|
|
PubKeyword* Pub = nullptr;
|
|
if (T0->getKind() == NodeKind::MutKeyword) {
|
|
Tokens.get();
|
|
Pub = static_cast<PubKeyword*>(T0);
|
|
}
|
|
auto Struct = expectToken<StructKeyword>();
|
|
if (!Struct) {
|
|
if (Pub) {
|
|
Pub->unref();
|
|
}
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
auto Name = expectToken<IdentifierAlt>();
|
|
if (!Name) {
|
|
if (Pub) {
|
|
Pub->unref();
|
|
}
|
|
Struct->unref();
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
std::vector<VarTypeExpression*> Vars;
|
|
for (;;) {
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::BlockStart) {
|
|
break;
|
|
}
|
|
auto Var = parseVarTypeExpression();
|
|
if (Var) {
|
|
Vars.push_back(Var);
|
|
}
|
|
}
|
|
auto BS = expectToken<BlockStart>();
|
|
if (!BS) {
|
|
if (Pub) {
|
|
Pub->unref();
|
|
}
|
|
Struct->unref();
|
|
Name->unref();
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
auto Fields = parseRecordDeclarationFields();
|
|
Tokens.get()->unref(); // Always a LineFoldEnd
|
|
return new RecordDeclaration { Pub, Struct, Name, Vars, BS, Fields };
|
|
}
|
|
|
|
VariantDeclaration* Parser::parseVariantDeclaration() {
|
|
auto T0 = Tokens.peek();
|
|
PubKeyword* Pub = nullptr;
|
|
if (T0->getKind() == NodeKind::MutKeyword) {
|
|
Tokens.get();
|
|
Pub = static_cast<PubKeyword*>(T0);
|
|
}
|
|
auto Enum = expectToken<EnumKeyword>();
|
|
if (!Enum) {
|
|
if (Pub) {
|
|
Pub->unref();
|
|
}
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
auto Name = expectToken<IdentifierAlt>();
|
|
if (!Name) {
|
|
if (Pub) {
|
|
Pub->unref();
|
|
}
|
|
Enum->unref();
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
std::vector<VarTypeExpression*> TVs;
|
|
for (;;) {
|
|
auto T0 = Tokens.peek();
|
|
if (T0->getKind() == NodeKind::BlockStart) {
|
|
break;
|
|
}
|
|
auto Var = parseVarTypeExpression();
|
|
if (Var) {
|
|
TVs.push_back(Var);
|
|
}
|
|
}
|
|
auto BS = expectToken<BlockStart>();
|
|
if (!BS) {
|
|
if (Pub) {
|
|
Pub->unref();
|
|
}
|
|
Enum->unref();
|
|
Name->unref();
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
std::vector<VariantDeclarationMember*> Members;
|
|
for (;;) {
|
|
next_member:
|
|
auto T0 = Tokens.peek();
|
|
if (T0->getKind() == NodeKind::BlockEnd) {
|
|
Tokens.get()->unref();
|
|
break;
|
|
}
|
|
auto Name = expectToken<IdentifierAlt>();
|
|
if (!Name) {
|
|
skipPastLineFoldEnd();
|
|
continue;
|
|
}
|
|
auto T1 = Tokens.peek();
|
|
if (T1->getKind() == NodeKind::BlockStart) {
|
|
Tokens.get();
|
|
auto BS = static_cast<BlockStart*>(T1);
|
|
auto Fields = parseRecordDeclarationFields();
|
|
// TODO continue; on error in Fields
|
|
Members.push_back(new RecordVariantDeclarationMember { Name, BS, Fields });
|
|
} else {
|
|
std::vector<TypeExpression*> Elements;
|
|
for (;;) {
|
|
auto T2 = Tokens.peek();
|
|
if (T2->getKind() == NodeKind::LineFoldEnd) {
|
|
Tokens.get()->unref();
|
|
break;
|
|
}
|
|
auto TE = parsePrimitiveTypeExpression();
|
|
if (!TE) {
|
|
Name->unref();
|
|
for (auto El: Elements) {
|
|
El->unref();
|
|
}
|
|
goto next_member;
|
|
}
|
|
Elements.push_back(TE);
|
|
}
|
|
Members.push_back(new TupleVariantDeclarationMember { Name, Elements });
|
|
}
|
|
}
|
|
checkLineFoldEnd();
|
|
return new VariantDeclaration { Pub, Enum, Name, TVs, BS, Members };
|
|
}
|
|
|
|
Node* Parser::parseClassElement() {
|
|
auto T0 = Tokens.peek();
|
|
switch (T0->getKind()) {
|
|
case NodeKind::LetKeyword:
|
|
return parseLetDeclaration();
|
|
case NodeKind::TypeKeyword:
|
|
// TODO
|
|
default:
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T0, std::vector<NodeKind> { NodeKind::LetKeyword, NodeKind::TypeKeyword });
|
|
skipPastLineFoldEnd();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
Node* Parser::parseSourceElement() {
|
|
auto T0 = peekFirstTokenAfterAnnotationsAndModifiers();
|
|
switch (T0->getKind()) {
|
|
case NodeKind::LetKeyword:
|
|
return parseLetDeclaration();
|
|
case NodeKind::IfKeyword:
|
|
return parseIfStatement();
|
|
case NodeKind::ClassKeyword:
|
|
return parseClassDeclaration();
|
|
case NodeKind::InstanceKeyword:
|
|
return parseInstanceDeclaration();
|
|
case NodeKind::StructKeyword:
|
|
return parseRecordDeclaration();
|
|
case NodeKind::EnumKeyword:
|
|
return parseVariantDeclaration();
|
|
default:
|
|
return parseExpressionStatement();
|
|
}
|
|
}
|
|
|
|
SourceFile* Parser::parseSourceFile() {
|
|
std::vector<Node*> Elements;
|
|
for (;;) {
|
|
auto T0 = Tokens.peek();
|
|
if (T0->is<EndOfFile>()) {
|
|
break;
|
|
}
|
|
auto Element = parseSourceElement();
|
|
if (Element) {
|
|
Elements.push_back(Element);
|
|
}
|
|
}
|
|
return new SourceFile(File, Elements);
|
|
}
|
|
|
|
std::vector<Annotation*> Parser::parseAnnotations() {
|
|
std::vector<Annotation*> Annotations;
|
|
for (;;) {
|
|
auto T0 = Tokens.peek();
|
|
if (T0->getKind() != NodeKind::At) {
|
|
break;
|
|
}
|
|
auto At = static_cast<class At*>(T0);
|
|
Tokens.get();
|
|
auto T1 = Tokens.peek();
|
|
switch (T1->getKind()) {
|
|
case NodeKind::Colon:
|
|
{
|
|
auto Colon = static_cast<class Colon*>(T1);
|
|
Tokens.get();
|
|
auto TE = parsePrimitiveTypeExpression();
|
|
if (!TE) {
|
|
// TODO
|
|
continue;
|
|
}
|
|
Annotations.push_back(new TypeAssertAnnotation { At, Colon, TE });
|
|
continue;
|
|
}
|
|
default:
|
|
{
|
|
// auto Name = static_cast<Identifier*>(T1);
|
|
// Tokens.get();
|
|
auto E = parseExpression();
|
|
if (!E) {
|
|
At->unref();
|
|
skipPastLineFoldEnd();
|
|
continue;
|
|
}
|
|
checkLineFoldEnd();
|
|
Annotations.push_back(new ExpressionAnnotation { At, E });
|
|
continue;
|
|
}
|
|
// default:
|
|
// DE.add<UnexpectedTokenDiagnostic>(File, T1, std::vector { NodeKind::Colon, NodeKind::Identifier });
|
|
// At->unref();
|
|
// skipToLineFoldEnd();
|
|
// break;
|
|
}
|
|
next_annotation:;
|
|
}
|
|
return Annotations;
|
|
}
|
|
|
|
void Parser::skipToRBrace() {
|
|
unsigned ParenLevel = 0;
|
|
unsigned BracketLevel = 0;
|
|
unsigned BraceLevel = 0;
|
|
unsigned BlockLevel = 0;
|
|
for (;;) {
|
|
auto T0 = Tokens.peek();
|
|
switch (T0->getKind()) {
|
|
case NodeKind::EndOfFile:
|
|
return;
|
|
case NodeKind::LineFoldEnd:
|
|
Tokens.get()->unref();
|
|
if (BlockLevel == 0 && ParenLevel == 0 && BracketLevel == 0 && BlockLevel == 0) {
|
|
return;
|
|
}
|
|
break;
|
|
case NodeKind::BlockStart:
|
|
Tokens.get()->unref();
|
|
BlockLevel++;
|
|
break;
|
|
case NodeKind::BlockEnd:
|
|
Tokens.get()->unref();
|
|
BlockLevel--;
|
|
break;
|
|
case NodeKind::LParen:
|
|
Tokens.get()->unref();
|
|
ParenLevel++;
|
|
break;
|
|
case NodeKind::LBracket:
|
|
Tokens.get()->unref();
|
|
BracketLevel++;
|
|
break;
|
|
case NodeKind::LBrace:
|
|
Tokens.get()->unref();
|
|
BraceLevel++;
|
|
break;
|
|
case NodeKind::RParen:
|
|
Tokens.get()->unref();
|
|
ParenLevel--;
|
|
break;
|
|
case NodeKind::RBracket:
|
|
Tokens.get()->unref();
|
|
BracketLevel--;
|
|
break;
|
|
case NodeKind::RBrace:
|
|
if (BlockLevel == 0 && ParenLevel == 0 && BracketLevel == 0 && BlockLevel == 0) {
|
|
return;
|
|
}
|
|
Tokens.get()->unref();
|
|
BraceLevel--;
|
|
break;
|
|
default:
|
|
Tokens.get()->unref();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Parser::skipPastLineFoldEnd() {
|
|
unsigned ParenLevel = 0;
|
|
unsigned BracketLevel = 0;
|
|
unsigned BraceLevel = 0;
|
|
unsigned BlockLevel = 0;
|
|
for (;;) {
|
|
auto T0 = Tokens.get();
|
|
switch (T0->getKind()) {
|
|
case NodeKind::EndOfFile:
|
|
return;
|
|
case NodeKind::LineFoldEnd:
|
|
T0->unref();
|
|
if (BlockLevel == 0 && ParenLevel == 0 && BracketLevel == 0 && BlockLevel == 0) {
|
|
return;
|
|
}
|
|
break;
|
|
case NodeKind::BlockStart:
|
|
T0->unref();
|
|
BlockLevel++;
|
|
break;
|
|
case NodeKind::BlockEnd:
|
|
T0->unref();
|
|
BlockLevel--;
|
|
break;
|
|
case NodeKind::LParen:
|
|
T0->unref();
|
|
ParenLevel++;
|
|
break;
|
|
case NodeKind::LBracket:
|
|
T0->unref();
|
|
BracketLevel++;
|
|
break;
|
|
case NodeKind::LBrace:
|
|
T0->unref();
|
|
BraceLevel++;
|
|
break;
|
|
case NodeKind::RParen:
|
|
T0->unref();
|
|
ParenLevel--;
|
|
break;
|
|
case NodeKind::RBracket:
|
|
T0->unref();
|
|
BracketLevel--;
|
|
break;
|
|
case NodeKind::RBrace:
|
|
T0->unref();
|
|
BraceLevel--;
|
|
break;
|
|
default:
|
|
T0->unref();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Parser::checkLineFoldEnd() {
|
|
auto T0 = Tokens.peek();
|
|
if (T0->getKind() == NodeKind::LineFoldEnd) {
|
|
Tokens.get()->unref();
|
|
} else {
|
|
DE.add<UnexpectedTokenDiagnostic>(File, T0, std::vector { NodeKind::LineFoldEnd });
|
|
skipPastLineFoldEnd();
|
|
}
|
|
}
|
|
|
|
}
|
|
|