diff --git a/include/bolt/CST.hpp b/include/bolt/CST.hpp index 665f5db1e..55c694edd 100644 --- a/include/bolt/CST.hpp +++ b/include/bolt/CST.hpp @@ -131,8 +131,13 @@ namespace bolt { void setParents(); - virtual Token* getFirstToken() = 0; - virtual Token* getLastToken() = 0; + virtual Token* getFirstToken() const = 0; + virtual Token* getLastToken() const = 0; + + virtual std::size_t getStartLine() const; + virtual std::size_t getStartColumn() const; + virtual std::size_t getEndLine() const; + virtual std::size_t getEndColumn() const; inline NodeKind getKind() const noexcept { return Kind; @@ -159,11 +164,12 @@ namespace bolt { return static_cast(this); } - TextRange getRange(); + TextRange getRange() const; inline Node(NodeKind Type): Kind(Type) {} + const SourceFile* getSourceFile() const; SourceFile* getSourceFile(); virtual Scope* getScope(); @@ -223,12 +229,12 @@ namespace bolt { virtual std::string getText() const = 0; - inline Token* getFirstToken() override { - return this; + inline Token* getFirstToken() const override { + ZEN_UNREACHABLE } - inline Token* getLastToken() override { - return this; + inline Token* getLastToken() const override { + ZEN_UNREACHABLE } inline TextLoc getStartLoc() { @@ -897,8 +903,8 @@ namespace bolt { Name(Name), TEs(TEs) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; static bool classof(const Node* N) { return N->getKind() == NodeKind::TypeclassConstraintExpression; @@ -922,8 +928,8 @@ namespace bolt { Tilde(Tilde), Right(Right) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; static bool classof(const Node* N) { return N->getKind() == NodeKind::EqualityConstraintExpression; @@ -947,8 +953,8 @@ namespace bolt { RArrowAlt(RArrowAlt), TE(TE) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; static bool classof(const Node* N) { return N->getKind() == NodeKind::QualifiedTypeExpression; @@ -969,8 +975,8 @@ namespace bolt { ModulePath(ModulePath), Name(Name) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; SymbolPath getSymbolPath() const; @@ -989,8 +995,8 @@ namespace bolt { ParamTypes(ParamTypes), ReturnType(ReturnType) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1002,8 +1008,8 @@ namespace bolt { inline VarTypeExpression(Identifier* Name): TypeExpression(NodeKind::VarTypeExpression), Name(Name) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1023,8 +1029,8 @@ namespace bolt { TE(TE), RParen(RParen) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1044,8 +1050,8 @@ namespace bolt { Elements(Elements), RParen(RParen) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1067,8 +1073,8 @@ namespace bolt { ): Pattern(NodeKind::BindPattern), Name(Name) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; static bool classof(const Node* N) { return N->getKind() == NodeKind::BindPattern; @@ -1085,8 +1091,8 @@ namespace bolt { Pattern(NodeKind::LiteralPattern), Literal(Literal) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; static bool classof(const Node* N) { return N->getKind() == NodeKind::LiteralPattern; @@ -1115,8 +1121,8 @@ namespace bolt { ModulePath(ModulePath), Name(Name) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; SymbolPath getSymbolPath() const; @@ -1138,8 +1144,8 @@ namespace bolt { RArrowAlt(RArrowAlt), Expression(Expression) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1162,8 +1168,8 @@ namespace bolt { BlockStart(BlockStart), Cases(Cases) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1183,8 +1189,8 @@ namespace bolt { Dot(Dot), Name(Name) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; inline Expression* getExpression() const { return E; @@ -1208,8 +1214,8 @@ namespace bolt { Elements(Elements), RParen(RParen) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1229,8 +1235,8 @@ namespace bolt { Inner(Inner), RParen(RParen) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1244,8 +1250,8 @@ namespace bolt { ): Expression(NodeKind::ConstantExpression), Token(Token) {} - class Token* getFirstToken() override; - class Token* getLastToken() override; + class Token* getFirstToken() const override; + class Token* getLastToken() const override; }; @@ -1262,8 +1268,8 @@ namespace bolt { Function(Function), Args(Args) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1280,8 +1286,8 @@ namespace bolt { Operator(Operator), RHS(RHS) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1298,8 +1304,8 @@ namespace bolt { Operator(Operator), Argument(Argument) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1319,8 +1325,8 @@ namespace bolt { ExpressionStatement(class Expression* Expression): Statement(NodeKind::ExpressionStatement), Expression(Expression) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1343,8 +1349,8 @@ namespace bolt { BlockStart(BlockStart), Elements(Elements) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1356,8 +1362,8 @@ namespace bolt { inline IfStatement(std::vector Parts): Statement(NodeKind::IfStatement), Parts(Parts) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1374,8 +1380,8 @@ namespace bolt { ReturnKeyword(ReturnKeyword), Expression(Expression) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1392,8 +1398,8 @@ namespace bolt { Colon(Colon), TypeExpression(TypeExpression) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1410,8 +1416,8 @@ namespace bolt { class Pattern* Pattern; class TypeAssert* TypeAssert; - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1435,8 +1441,8 @@ namespace bolt { BlockStart(BlockStart), Elements(Elements) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1453,8 +1459,8 @@ namespace bolt { Equals(Equals), Expression(Expression) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1502,8 +1508,8 @@ namespace bolt { return TheScope; } - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; static bool classof(const Node* N) { return N->getKind() == NodeKind::LetDeclaration; @@ -1533,8 +1539,8 @@ namespace bolt { BlockStart(BlockStart), Elements(Elements) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; static bool classof(const Node* N) { return N->getKind() == NodeKind::InstanceDeclaration; @@ -1567,8 +1573,8 @@ namespace bolt { BlockStart(BlockStart), Elements(Elements) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; static bool classof(const Node* N) { return N->getKind() == NodeKind::ClassDeclaration; @@ -1592,8 +1598,8 @@ namespace bolt { class Colon* Colon; class TypeExpression* TypeExpression; - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1619,8 +1625,8 @@ namespace bolt { BlockStart(BlockStart), Fields(Fields) {} - Token* getFirstToken() override; - Token* getLastToken() override; + Token* getFirstToken() const override; + Token* getLastToken() const override; }; @@ -1641,8 +1647,12 @@ namespace bolt { return File; } - Token* getFirstToken() override; - Token* getLastToken() override; + inline const TextFile& getTextFile() const { + return File; + } + + Token* getFirstToken() const override; + Token* getLastToken() const override; inline Scope* getScope() override { if (TheScope == nullptr) { diff --git a/include/bolt/Diagnostics.hpp b/include/bolt/Diagnostics.hpp index 32453b9ca..e6ef1dec9 100644 --- a/include/bolt/Diagnostics.hpp +++ b/include/bolt/Diagnostics.hpp @@ -39,6 +39,11 @@ namespace bolt { return Kind; } + virtual Node* getNode() const { + return nullptr; + } + + }; class UnexpectedTokenDiagnostic : public Diagnostic { @@ -74,6 +79,10 @@ namespace bolt { inline BindingNotFoundDiagnostic(ByteString Name, Node* Initiator): Diagnostic(DiagnosticKind::BindingNotFound), Name(Name), Initiator(Initiator) {} + inline Node* getNode() const override { + return Initiator; + } + }; class UnificationErrorDiagnostic : public Diagnostic { @@ -88,6 +97,10 @@ namespace bolt { inline UnificationErrorDiagnostic(Type* Left, Type* Right, TypePath LeftPath, TypePath RightPath, Node* Source): Diagnostic(DiagnosticKind::UnificationError), Left(Left), Right(Right), LeftPath(LeftPath), RightPath(RightPath), Source(Source) {} + inline Node* getNode() const override { + return Source; + } + }; class TypeclassMissingDiagnostic : public Diagnostic { @@ -99,6 +112,10 @@ namespace bolt { inline TypeclassMissingDiagnostic(TypeclassSignature Sig, LetDeclaration* Decl): Diagnostic(DiagnosticKind::TypeclassMissing), Sig(Sig), Decl(Decl) {} + inline Node* getNode() const override { + return Decl; + } + }; class InstanceNotFoundDiagnostic : public Diagnostic { @@ -111,6 +128,10 @@ namespace bolt { inline InstanceNotFoundDiagnostic(ByteString TypeclassName, TCon* Ty, Node* Source): Diagnostic(DiagnosticKind::InstanceNotFound), TypeclassName(TypeclassName), Ty(Ty), Source(Source) {} + inline Node* getNode() const override { + return Source; + } + }; class ClassNotFoundDiagnostic : public Diagnostic { @@ -138,29 +159,56 @@ namespace bolt { public: Type* Actual; + std::vector Classes; + Node* Source; - inline InvalidTypeToTypeclassDiagnostic(Type* Actual): - Diagnostic(DiagnosticKind::InvalidTypeToTypeclass) {} + inline InvalidTypeToTypeclassDiagnostic(Type* Actual, std::vector Classes, Node* Source): + Diagnostic(DiagnosticKind::InvalidTypeToTypeclass), Actual(Actual), Classes(Classes), Source(Source) {} + + inline Node* getNode() const override { + return Source; + } }; class DiagnosticEngine { - protected: - public: - virtual void addDiagnostic(const Diagnostic& Diagnostic) = 0; + virtual void addDiagnostic(Diagnostic* Diagnostic) = 0; template void add(Ts&&... Args) { - D Diag { std::forward(Args)... }; - addDiagnostic(Diag); + addDiagnostic(new D { std::forward(Args)... }); } virtual ~DiagnosticEngine() {} }; + /** + * Keeps diagnostics alive in-memory until a seperate procedure processes them. + */ + class DiagnosticStore : public DiagnosticEngine { + public: + + std::vector Diagnostics; + + void addDiagnostic(Diagnostic* Diagnostic) { + Diagnostics.push_back(Diagnostic); + } + + void clear() { + Diagnostics.clear(); + } + + ~DiagnosticStore() { + for (auto D: Diagnostics) { + delete D; + } + } + + }; + enum class Color { None, Black, @@ -198,12 +246,25 @@ namespace bolt { ); void writeExcerpt( - TextFile& File, + const TextFile& File, TextRange ToPrint, TextRange ToHighlight, Color HighlightColor ); + void writeNode(const Node* N); + + void writePrefix(const Diagnostic& D); + void writeBinding(const ByteString& Name); + void writeType(std::size_t I); + void writeType(const Type* Ty); + void writeLoc(const TextFile& File, const TextLoc& Loc); + void writeTypeclassName(const ByteString& Name); + void writeTypeclassSignature(const TypeclassSignature& Sig); + + void write(const std::string_view& S); + void write(std::size_t N); + public: unsigned ExcerptLinesPre = 2; @@ -213,9 +274,10 @@ namespace bolt { bool PrintExcerpts = true; bool EnableColors = true; - void addDiagnostic(const Diagnostic& Diagnostic) override; - ConsoleDiagnostics(std::ostream& Out = std::cerr); + void addDiagnostic(Diagnostic* Diagnostic) override; + }; + } diff --git a/include/bolt/Parser.hpp b/include/bolt/Parser.hpp index 7aaeadfd8..3816266d5 100644 --- a/include/bolt/Parser.hpp +++ b/include/bolt/Parser.hpp @@ -9,6 +9,7 @@ namespace bolt { + class DiagnosticEngine; class Scanner; enum OperatorFlags { @@ -62,6 +63,7 @@ namespace bolt { class Parser { TextFile& File; + DiagnosticEngine& DE; Stream& Tokens; @@ -90,7 +92,7 @@ namespace bolt { public: - Parser(TextFile& File, Stream& S); + Parser(TextFile& File, Stream& S, DiagnosticEngine& DE); TypeExpression* parseTypeExpression(); diff --git a/include/bolt/Text.hpp b/include/bolt/Text.hpp index 5a7921f95..2bfebc447 100644 --- a/include/bolt/Text.hpp +++ b/include/bolt/Text.hpp @@ -52,9 +52,9 @@ namespace bolt { TextFile(ByteString Path, ByteString Text); - size_t getLine(size_t Offset); - size_t getColumn(size_t Offset); - size_t getStartOffset(size_t Line); + size_t getLine(size_t Offset) const; + size_t getColumn(size_t Offset) const; + size_t getStartOffset(size_t Line) const; size_t getLineCount() const; diff --git a/src/CST.cc b/src/CST.cc index 7082195ea..3e345d352 100644 --- a/src/CST.cc +++ b/src/CST.cc @@ -92,18 +92,44 @@ namespace bolt { return Source->Parent->getScope(); } + const SourceFile* Node::getSourceFile() const { + const Node* CurrNode = this; + for (;;) { + if (CurrNode->Kind == NodeKind::SourceFile) { + return static_cast(CurrNode); + } + CurrNode = CurrNode->Parent; + ZEN_ASSERT(CurrNode != nullptr); + } + } SourceFile* Node::getSourceFile() { - auto CurrNode = this; + Node* CurrNode = this; for (;;) { if (CurrNode->Kind == NodeKind::SourceFile) { return static_cast(CurrNode); } CurrNode = CurrNode->Parent; ZEN_ASSERT(CurrNode != nullptr); - } + } } - TextRange Node::getRange() { + std::size_t Node::getStartLine() const { + return getFirstToken()->getStartLine(); + } + + std::size_t Node::getStartColumn() const { + return getFirstToken()->getStartColumn(); + } + + std::size_t Node::getEndLine() const { + return getLastToken()->getEndLine(); + } + + std::size_t Node::getEndColumn() const { + return getLastToken()->getEndColumn(); + } + + TextRange Node::getRange() const { return TextRange { getFirstToken()->getStartLoc(), getLastToken()->getEndLoc(), @@ -169,273 +195,273 @@ namespace bolt { return true; } - Token* TypeclassConstraintExpression::getFirstToken() { + Token* TypeclassConstraintExpression::getFirstToken() const { return Name; } - Token* TypeclassConstraintExpression::getLastToken() { + Token* TypeclassConstraintExpression::getLastToken() const { if (!TEs.empty()) { return TEs.back()->getLastToken(); } return Name; } - Token* EqualityConstraintExpression::getFirstToken() { + Token* EqualityConstraintExpression::getFirstToken() const { return Left->getFirstToken(); } - Token* EqualityConstraintExpression::getLastToken() { + Token* EqualityConstraintExpression::getLastToken() const { return Left->getLastToken(); } - Token* QualifiedTypeExpression::getFirstToken() { + Token* QualifiedTypeExpression::getFirstToken() const { if (!Constraints.empty()) { return std::get<0>(Constraints.front())->getFirstToken(); } return TE->getFirstToken(); } - Token* QualifiedTypeExpression::getLastToken() { + Token* QualifiedTypeExpression::getLastToken() const { return TE->getLastToken(); } - Token* ReferenceTypeExpression::getFirstToken() { + Token* ReferenceTypeExpression::getFirstToken() const { if (!ModulePath.empty()) { return std::get<0>(ModulePath.front()); } return Name; } - Token* ReferenceTypeExpression::getLastToken() { + Token* ReferenceTypeExpression::getLastToken() const { return Name; } - Token* ArrowTypeExpression::getFirstToken() { + Token* ArrowTypeExpression::getFirstToken() const { if (ParamTypes.size()) { return ParamTypes.front()->getFirstToken(); } return ReturnType->getFirstToken(); } - Token* ArrowTypeExpression::getLastToken() { + Token* ArrowTypeExpression::getLastToken() const { return ReturnType->getLastToken(); } - Token* VarTypeExpression::getLastToken() { + Token* VarTypeExpression::getLastToken() const { return Name; } - Token* VarTypeExpression::getFirstToken() { + Token* VarTypeExpression::getFirstToken() const { return Name; } - Token* NestedTypeExpression::getLastToken() { + Token* NestedTypeExpression::getLastToken() const { return LParen; } - Token* NestedTypeExpression::getFirstToken() { + Token* NestedTypeExpression::getFirstToken() const { return RParen; } - Token* TupleTypeExpression::getLastToken() { + Token* TupleTypeExpression::getLastToken() const { return LParen; } - Token* TupleTypeExpression::getFirstToken() { + Token* TupleTypeExpression::getFirstToken() const { return RParen; } - Token* BindPattern::getFirstToken() { + Token* BindPattern::getFirstToken() const { return Name; } - Token* BindPattern::getLastToken() { + Token* BindPattern::getLastToken() const { return Name; } - Token* LiteralPattern::getFirstToken() { + Token* LiteralPattern::getFirstToken() const { return Literal; } - Token* LiteralPattern::getLastToken() { + Token* LiteralPattern::getLastToken() const { return Literal; } - Token* ReferenceExpression::getFirstToken() { + Token* ReferenceExpression::getFirstToken() const { if (!ModulePath.empty()) { return std::get<0>(ModulePath.front()); } return Name; } - Token* ReferenceExpression::getLastToken() { + Token* ReferenceExpression::getLastToken() const { return Name; } - Token* MatchCase::getFirstToken() { + Token* MatchCase::getFirstToken() const { return Pattern->getFirstToken(); } - Token* MatchCase::getLastToken() { + Token* MatchCase::getLastToken() const { return Expression->getLastToken(); } - Token* MatchExpression::getFirstToken() { + Token* MatchExpression::getFirstToken() const { return MatchKeyword; } - Token* MatchExpression::getLastToken() { + Token* MatchExpression::getLastToken() const { if (!Cases.empty()) { return Cases.back()->getLastToken(); } return BlockStart; } - Token* MemberExpression::getFirstToken() { + Token* MemberExpression::getFirstToken() const { return E->getFirstToken(); } - Token* MemberExpression::getLastToken() { + Token* MemberExpression::getLastToken() const { return Name; } - Token* TupleExpression::getFirstToken() { + Token* TupleExpression::getFirstToken() const { return LParen; } - Token* TupleExpression::getLastToken() { + Token* TupleExpression::getLastToken() const { return RParen; } - Token* NestedExpression::getFirstToken() { + Token* NestedExpression::getFirstToken() const { return LParen; } - Token* NestedExpression::getLastToken() { + Token* NestedExpression::getLastToken() const { return RParen; } - Token* ConstantExpression::getFirstToken() { + Token* ConstantExpression::getFirstToken() const { return Token; } - Token* ConstantExpression::getLastToken() { + Token* ConstantExpression::getLastToken() const { return Token; } - Token* CallExpression::getFirstToken() { + Token* CallExpression::getFirstToken() const { return Function->getFirstToken(); } - Token* CallExpression::getLastToken() { + Token* CallExpression::getLastToken() const { if (Args.size()) { return Args.back()->getLastToken(); } return Function->getLastToken(); } - Token* InfixExpression::getFirstToken() { + Token* InfixExpression::getFirstToken() const { return LHS->getFirstToken(); } - Token* InfixExpression::getLastToken() { + Token* InfixExpression::getLastToken() const { return RHS->getLastToken(); } - Token* PrefixExpression::getFirstToken() { + Token* PrefixExpression::getFirstToken() const { return Operator; } - Token* PrefixExpression::getLastToken() { + Token* PrefixExpression::getLastToken() const { return Argument->getLastToken(); } - Token* ExpressionStatement::getFirstToken() { + Token* ExpressionStatement::getFirstToken() const { return Expression->getFirstToken(); } - Token* ExpressionStatement::getLastToken() { + Token* ExpressionStatement::getLastToken() const { return Expression->getLastToken(); } - Token* ReturnStatement::getFirstToken() { + Token* ReturnStatement::getFirstToken() const { return ReturnKeyword; } - Token* ReturnStatement::getLastToken() { + Token* ReturnStatement::getLastToken() const { if (Expression) { return Expression->getLastToken(); } return ReturnKeyword; } - Token* IfStatementPart::getFirstToken() { + Token* IfStatementPart::getFirstToken() const { return Keyword; } - Token* IfStatementPart::getLastToken() { + Token* IfStatementPart::getLastToken() const { if (Elements.size()) { return Elements.back()->getLastToken(); } return BlockStart; } - Token* IfStatement::getFirstToken() { + Token* IfStatement::getFirstToken() const { ZEN_ASSERT(Parts.size()); return Parts.front()->getFirstToken(); } - Token* IfStatement::getLastToken() { + Token* IfStatement::getLastToken() const { ZEN_ASSERT(Parts.size()); return Parts.back()->getLastToken(); } - Token* TypeAssert::getFirstToken() { + Token* TypeAssert::getFirstToken() const { return Colon; } - Token* TypeAssert::getLastToken() { + Token* TypeAssert::getLastToken() const { return TypeExpression->getLastToken(); } - Token* Parameter::getFirstToken() { + Token* Parameter::getFirstToken() const { return Pattern->getFirstToken(); } - Token* Parameter::getLastToken() { + Token* Parameter::getLastToken() const { if (TypeAssert) { return TypeAssert->getLastToken(); } return Pattern->getLastToken(); } - Token* LetBlockBody::getFirstToken() { + Token* LetBlockBody::getFirstToken() const { return BlockStart; } - Token* LetBlockBody::getLastToken() { + Token* LetBlockBody::getLastToken() const { if (Elements.size()) { return Elements.back()->getLastToken(); } return BlockStart; } - Token* LetExprBody::getFirstToken() { + Token* LetExprBody::getFirstToken() const { return Equals; } - Token* LetExprBody::getLastToken() { + Token* LetExprBody::getLastToken() const { return Expression->getLastToken(); } - Token* LetDeclaration::getFirstToken() { + Token* LetDeclaration::getFirstToken() const { if (PubKeyword) { return PubKeyword; } return LetKeyword; } - Token* LetDeclaration::getLastToken() { + Token* LetDeclaration::getLastToken() const { if (Body) { return Body->getLastToken(); } @@ -448,61 +474,61 @@ namespace bolt { return Pattern->getLastToken(); } - Token* StructDeclarationField::getFirstToken() { + Token* StructDeclarationField::getFirstToken() const { return Name; } - Token* StructDeclarationField::getLastToken() { + Token* StructDeclarationField::getLastToken() const { return TypeExpression->getLastToken(); } - Token* StructDeclaration::getFirstToken() { + Token* StructDeclaration::getFirstToken() const { if (PubKeyword) { return PubKeyword; } return StructKeyword; } - Token* StructDeclaration::getLastToken() { + Token* StructDeclaration::getLastToken() const { if (Fields.size()) { Fields.back()->getLastToken(); } return BlockStart; } - Token* InstanceDeclaration::getFirstToken() { + Token* InstanceDeclaration::getFirstToken() const { return InstanceKeyword; } - Token* InstanceDeclaration::getLastToken() { + Token* InstanceDeclaration::getLastToken() const { if (!Elements.empty()) { return Elements.back()->getLastToken(); } return BlockStart; } - Token* ClassDeclaration::getFirstToken() { + Token* ClassDeclaration::getFirstToken() const { if (PubKeyword != nullptr) { return PubKeyword; } return ClassKeyword; } - Token* ClassDeclaration::getLastToken() { + Token* ClassDeclaration::getLastToken() const { if (!Elements.empty()) { return Elements.back()->getLastToken(); } return BlockStart; } - Token* SourceFile::getFirstToken() { + Token* SourceFile::getFirstToken() const { if (Elements.size()) { return Elements.front()->getFirstToken(); } return nullptr; } - Token* SourceFile::getLastToken() { + Token* SourceFile::getLastToken() const { if (Elements.size()) { return Elements.back()->getLastToken(); } diff --git a/src/Checker.cc b/src/Checker.cc index 3c61cf49d..7a96f7e81 100644 --- a/src/Checker.cc +++ b/src/Checker.cc @@ -1064,7 +1064,7 @@ namespace bolt { propagateClassTycon(Class, llvm::cast(Ty)); } } else if (!Classes.empty()) { - DE.add(Ty); + DE.add(Ty, std::vector(Classes.begin(), Classes.end()), Source); } }; diff --git a/src/Diagnostics.cc b/src/Diagnostics.cc index f4f49ee4a..2e0badf91 100644 --- a/src/Diagnostics.cc +++ b/src/Diagnostics.cc @@ -4,11 +4,11 @@ #include #include -#include "bolt/CST.hpp" #include "zen/config.hpp" +#include "bolt/CST.hpp" +#include "bolt/Type.hpp" #include "bolt/Diagnostics.hpp" -#include "bolt/Checker.hpp" #define ANSI_RESET "\u001b[0m" #define ANSI_BOLD "\u001b[1m" @@ -314,7 +314,7 @@ namespace bolt { } void ConsoleDiagnostics::writeExcerpt( - TextFile& File, + const TextFile& File, TextRange ToPrint, TextRange ToHighlight, Color HighlightColor @@ -353,166 +353,259 @@ namespace bolt { } - void ConsoleDiagnostics::addDiagnostic(const Diagnostic& D) { + void ConsoleDiagnostics::write(const std::string_view& S) { + Out << S; + } - switch (D.getKind()) { + void ConsoleDiagnostics::write(std::size_t I) { + Out << I; + } + + void ConsoleDiagnostics::writeBinding(const ByteString& Name) { + write("'"); + write(Name); + write("'"); + } + + void ConsoleDiagnostics::writeType(const Type* Ty) { + setForegroundColor(Color::Green); + write(describe(Ty)); + resetStyles(); + } + + void ConsoleDiagnostics::writeType(std::size_t I) { + setForegroundColor(Color::Green); + write(I); + resetStyles(); + } + + void ConsoleDiagnostics::writeNode(const Node* N) { + auto Range = N->getRange(); + writeExcerpt(N->getSourceFile()->getTextFile(), Range, Range, Color::Red); + } + + void ConsoleDiagnostics::writeLoc(const TextFile& File, const TextLoc& Loc) { + setForegroundColor(Color::Yellow); + write(File.getPath()); + write(":"); + write(Loc.Line); + write(":"); + write(Loc.Column); + write(":"); + resetStyles(); + } + + void ConsoleDiagnostics::writePrefix(const Diagnostic& D) { + setForegroundColor(Color::Red); + setBold(true); + write("error: "); + resetStyles(); + } + + void ConsoleDiagnostics::writeTypeclassName(const ByteString& Name) { + setForegroundColor(Color::Magenta); + write(Name); + resetStyles(); + } + + void ConsoleDiagnostics::writeTypeclassSignature(const TypeclassSignature& Sig) { + setForegroundColor(Color::Magenta); + write(Sig.Id); + for (auto TV: Sig.Params) { + write(" "); + write(describe(TV)); + } + resetStyles(); + } + + void ConsoleDiagnostics::addDiagnostic(Diagnostic* D) { + + switch (D->getKind()) { case DiagnosticKind::BindingNotFound: { - auto E = static_cast(D); - Out << ANSI_BOLD ANSI_FG_RED "error: " ANSI_RESET "binding '" << E.Name << "' was not found\n\n"; + auto E = static_cast(*D); + writePrefix(E); + write("binding '"); + writeBinding(E.Name); + write(" was not found\n\n"); if (E.Initiator != nullptr) { auto Range = E.Initiator->getRange(); //std::cerr << Range.Start.Line << ":" << Range.Start.Column << "-" << Range.End.Line << ":" << Range.End.Column << "\n"; writeExcerpt(E.Initiator->getSourceFile()->getTextFile(), Range, Range, Color::Red); Out << "\n"; } - return; + break; } case DiagnosticKind::UnexpectedToken: { - auto E = static_cast(D); - setForegroundColor(Color::Red); - setBold(true); - Out << "error: "; - resetStyles(); - setForegroundColor(Color::Yellow); - Out << E.File.getPath() << ":" << E.Actual->getStartLine() << ":" << E.Actual->getStartColumn() << ":"; - resetStyles(); - Out << " expected "; + auto E = static_cast(*D); + writePrefix(E); + writeLoc(E.File, E.Actual->getStartLoc()); + write(" expected "); switch (E.Expected.size()) { case 0: - Out << "nothing"; + write("nothing"); break; case 1: - Out << describe(E.Expected[0]); + write(describe(E.Expected[0])); break; default: auto Iter = E.Expected.begin(); Out << describe(*Iter++); NodeKind Prev = *Iter++; while (Iter != E.Expected.end()) { - Out << ", " << describe(Prev); + write(", "); + write(describe(Prev)); Prev = *Iter++; } - Out << " or " << describe(Prev); + write(" or "); + write(describe(Prev)); break; } - Out << " but instead got '" << E.Actual->getText() << "'\n\n"; + write(" but instead got '"); + write(E.Actual->getText()); + write("'\n\n"); writeExcerpt(E.File, E.Actual->getRange(), E.Actual->getRange(), Color::Red); - Out << "\n"; - return; + write("\n"); + break; } case DiagnosticKind::UnexpectedString: { - auto E = static_cast(D); - setForegroundColor(Color::Red); - setBold(true); - Out << "error: "; - resetStyles(); - Out << E.File.getPath() << ":" << E.Location.Line << ":" << E.Location.Column << ": unexpected '"; + auto E = static_cast(*D); + writePrefix(E); + writeLoc(E.File, E.Location); + write(" unexpected '"); for (auto Chr: E.Actual) { switch (Chr) { case '\\': - Out << "\\\\"; + write("\\\\"); break; case '\'': - Out << "\\'"; + write("\\'"); break; default: - Out << Chr; + write(Chr); break; } } - Out << "'\n\n"; + write("'\n\n"); TextRange Range { E.Location, E.Location + E.Actual }; writeExcerpt(E.File, Range, Range, Color::Red); - Out << "\n"; - return; + write("\n"); + break; } case DiagnosticKind::UnificationError: { - auto E = static_cast(D); - setForegroundColor(Color::Red); - setBold(true); - Out << "error: "; - resetStyles(); + auto E = static_cast(*D); + writePrefix(E); auto Left = E.Left->resolve(E.LeftPath); auto Right = E.Right->resolve(E.RightPath); - Out << "the types " << ANSI_FG_GREEN << describe(Left) << ANSI_RESET - << " and " << ANSI_FG_GREEN << describe(Right) << ANSI_RESET << " failed to match\n\n"; + write("the types "); + writeType(Left); + write(" and "); + writeType(Right); + write(" failed to match\n\n"); if (E.Source) { - auto Range = E.Source->getRange(); - writeExcerpt(E.Source->getSourceFile()->getTextFile(), Range, Range, Color::Red); + writeNode(E.Source); Out << "\n"; } if (!E.LeftPath.empty()) { setForegroundColor(Color::Yellow); setBold(true); - Out << " info: "; + write(" info: "); resetStyles(); - Out << "type " << ANSI_FG_GREEN << describe(Left) << ANSI_RESET << " occurs in the full type " << ANSI_FG_GREEN << describe(E.Left) << ANSI_RESET << "\n\n"; + write("the type "); + writeType(Left); + write(" occurs in the full type "); + writeType(E.Left); + write("\n\n"); } if (!E.RightPath.empty()) { setForegroundColor(Color::Yellow); setBold(true); - Out << " info: "; + write(" info: "); resetStyles(); - Out << "type " << ANSI_FG_GREEN << describe(Right) << ANSI_RESET << " occurs in the full type " << ANSI_FG_GREEN << describe(E.Right) << ANSI_RESET << "\n\n"; + write("the type "); + writeType(Right); + write(" occurs in the full type "); + writeType(E.Right); + write("\n\n"); } - return; + break; } case DiagnosticKind::TypeclassMissing: { - auto E = static_cast(D); - setForegroundColor(Color::Red); - setBold(true); - Out << "error: "; - resetStyles(); - Out << "the type class " << ANSI_FG_YELLOW << E.Sig.Id; - for (auto TV: E.Sig.Params) { - Out << " " << describe(TV); - } - Out << ANSI_RESET << " is missing from the declaration's type signature\n\n"; - auto Range = E.Decl->getRange(); - writeExcerpt(E.Decl->getSourceFile()->getTextFile(), Range, Range, Color::Yellow); - Out << "\n\n"; - return; + auto E = static_cast(*D); + writePrefix(E); + write("the type class "); + writeTypeclassSignature(E.Sig); + write(" is missing from the declaration's type signature\n\n"); + writeNode(E.Decl); + write("\n\n"); + break; } case DiagnosticKind::InstanceNotFound: { - auto E = static_cast(D); - setForegroundColor(Color::Red); - setBold(true); - Out << "error: "; - resetStyles(); - Out << "a type class instance " << ANSI_FG_YELLOW << E.TypeclassName << " " << describe(E.Ty) << ANSI_RESET " was not found.\n\n"; - auto Range = E.Source->getRange(); - //std::cerr << Range.Start.Line << ":" << Range.Start.Column << "-" << Range.End.Line << ":" << Range.End.Column << "\n"; - writeExcerpt(E.Source->getSourceFile()->getTextFile(), Range, Range, Color::Red); - Out << "\n"; - return; + auto E = static_cast(*D); + writePrefix(E); + write("a type class instance "); + writeTypeclassName(E.TypeclassName); + writeType(E.Ty); + write(" was not found.\n\n"); + writeNode(E.Source); + write("\n"); + break; } case DiagnosticKind::ClassNotFound: { - auto E = static_cast(D); - setForegroundColor(Color::Red); - setBold(true); - Out << "error: "; - resetStyles(); - Out << "the type class " << ANSI_FG_YELLOW << E.Name << ANSI_RESET " was not found.\n\n"; - return; + auto E = static_cast(*D); + writePrefix(E); + write("the type class "); + writeTypeclassName(E.Name); + write(" was not found.\n\n"); + break; + } + + case DiagnosticKind::TupleIndexOutOfRange: + { + auto E = static_cast(*D); + writePrefix(E); + write("the index "); + writeType(E.I); + write(" is out of range for tuple "); + writeType(E.Tuple); + break; + } + + case DiagnosticKind::InvalidTypeToTypeclass: + { + auto E = static_cast(*D); + writePrefix(E); + write("the type "); + writeType(E.Actual); + write(" was applied to type class names "); + bool First = true; + for (auto Class: E.Classes) { + if (First) First = false; + else write(", "); + writeTypeclassName(Class); + } + write(" but this is invalid\n\n"); + break; } } - ZEN_UNREACHABLE + // Since this DiagnosticEngine is expected to own the diagnostic, we simply + // destroy the processed diagnostic so that there are no memory leaks. + delete D; } } diff --git a/src/Parser.cc b/src/Parser.cc index 0a5806901..98a7f95c7 100644 --- a/src/Parser.cc +++ b/src/Parser.cc @@ -38,8 +38,8 @@ namespace bolt { Mapping.emplace(Name, OperatorInfo { Precedence, Flags }); } - Parser::Parser(TextFile& File, Stream& S): - File(File), Tokens(S) { + Parser::Parser(TextFile& File, Stream& S, DiagnosticEngine& DE): + File(File), Tokens(S), DE(DE) { ExprOperators.add("**", OperatorFlags_InfixR, 10); ExprOperators.add("*", OperatorFlags_InfixL, 5); ExprOperators.add("/", OperatorFlags_InfixL, 5); diff --git a/src/Text.cc b/src/Text.cc index ab2e8f968..f7e38a11b 100644 --- a/src/Text.cc +++ b/src/Text.cc @@ -22,11 +22,11 @@ namespace bolt { return LineOffsets.size(); } - size_t TextFile::getStartOffset(size_t Line) { + size_t TextFile::getStartOffset(size_t Line) const { return LineOffsets[Line-1]; } - size_t TextFile::getLine(size_t Offset) { + size_t TextFile::getLine(size_t Offset) const { ZEN_ASSERT(Offset < Text.size()); for (size_t I = 0; I < LineOffsets.size(); ++I) { if (LineOffsets[I] > Offset) { @@ -36,7 +36,7 @@ namespace bolt { ZEN_UNREACHABLE } - size_t TextFile::getColumn(size_t Offset) { + size_t TextFile::getColumn(size_t Offset) const { auto Line = getLine(Offset); auto StartOffset = getStartOffset(Line); return Offset - StartOffset + 1 ; diff --git a/src/main.cc b/src/main.cc index 917ab0009..4a754f9d5 100644 --- a/src/main.cc +++ b/src/main.cc @@ -3,6 +3,7 @@ #include #include +#include #include "zen/config.hpp" @@ -44,22 +45,39 @@ int main(int argc, const char* argv[]) { VectorStream Chars(Text, EOF); Scanner S(File, Chars); Punctuator PT(S); - Parser P(File, PT); + Parser P(File, PT, DE); - SourceFile* SF; - - try { - SF = P.parseSourceFile(); - } catch (Diagnostic& D) { - DE.addDiagnostic(D); + auto SF = P.parseSourceFile(); + if (SF == nullptr) { return 1; } SF->setParents(); - Checker TheChecker { Config, DE }; + DiagnosticStore DS; + Checker TheChecker { Config, DS }; TheChecker.check(SF); + auto LT = [](const Diagnostic* L, const Diagnostic* R) { + auto N1 = L->getNode(); + auto N2 = R->getNode(); + if (N1 == nullptr && N2 == nullptr) { + return false; + } + if (N1 == nullptr) { + return true; + } + if (N2 == nullptr) { + return false; + } + return N1->getStartLine() < N2->getStartLine() || N1->getStartColumn() < N2->getStartColumn(); + }; + std::sort(DS.Diagnostics.begin(), DS.Diagnostics.end(), LT); + + for (auto D: DS.Diagnostics) { + DE.addDiagnostic(D); + } + return 0; }