Add experimental support for compiler annotations

This commit is contained in:
Sam Vervaeck 2023-06-08 14:52:22 +02:00
parent c0c36ca698
commit d278456290
Signed by: samvv
SSH key fingerprint: SHA256:dIg0ywU1OP+ZYifrYxy8c5esO72cIKB+4/9wkZj1VaY
16 changed files with 796 additions and 314 deletions

2
.vscode/launch.json vendored
View file

@ -9,7 +9,7 @@
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/build/bolt",
"args": [ "test.bolt" ],
"args": [ "--direct-diagnostics", "verify", "test/checker/local_constraints_polymorphic_variable.bolt" ],
"cwd": "${workspaceFolder}",
"preLaunchTask": "CMake: build"
}

View file

@ -4,6 +4,7 @@
#include <cctype>
#include <istream>
#include <iterator>
#include <limits>
#include <unordered_map>
#include <variant>
#include <vector>
@ -95,6 +96,7 @@ namespace bolt {
Dot,
DotDot,
Tilde,
At,
LParen,
RParen,
LBracket,
@ -129,6 +131,8 @@ namespace bolt {
IdentifierAlt,
StringLiteral,
IntegerLiteral,
ExpressionAnnotation,
TypeAssertAnnotation,
TypeclassConstraintExpression,
EqualityConstraintExpression,
QualifiedTypeExpression,
@ -150,7 +154,7 @@ namespace bolt {
MemberExpression,
TupleExpression,
NestedExpression,
ConstantExpression,
LiteralExpression,
CallExpression,
InfixExpression,
PrefixExpression,
@ -221,7 +225,7 @@ namespace bolt {
template<>
bool is<Expression>() const noexcept {
return Kind == NodeKind::ReferenceExpression
|| Kind == NodeKind::ConstantExpression
|| Kind == NodeKind::LiteralExpression
|| Kind == NodeKind::PrefixExpression
|| Kind == NodeKind::InfixExpression
|| Kind == NodeKind::CallExpression
@ -423,6 +427,20 @@ namespace bolt {
};
class At : public Token {
public:
inline At(TextLoc StartLoc):
Token(NodeKind::At, StartLoc) {}
std::string getText() const override;
static bool classof(const Node* N) {
return N->getKind() == NodeKind::At;
}
};
class LParen : public Token {
public:
@ -949,6 +967,11 @@ namespace bolt {
return V;
}
inline int asInt() const {
ZEN_ASSERT(V >= std::numeric_limits<int>::min() && V <= std::numeric_limits<int>::max());
return V;
}
LiteralValue getValue() override;
static bool classof(const Node* N) {
@ -957,6 +980,63 @@ namespace bolt {
};
class Annotation : public Node {
public:
inline Annotation(NodeKind Kind):
Node(Kind) {}
};
class ExpressionAnnotation : public Annotation {
public:
At* At;
Expression* Expression;
inline ExpressionAnnotation(
class At* At,
class Expression* Expression
): Annotation(NodeKind::ExpressionAnnotation),
At(At),
Expression(Expression) {}
Token* getFirstToken() const override;
Token* getLastToken() const override;
inline class Expression* getExpression() const noexcept {
return Expression;
}
};
class TypeExpression;
class TypeAssertAnnotation : public Annotation {
public:
At* At;
Colon* Colon;
TypeExpression* TE;
inline TypeAssertAnnotation(
class At* At,
class Colon* Colon,
TypeExpression* TE
): Annotation(NodeKind::TypeAssertAnnotation),
At(At),
Colon(Colon),
TE(TE) {}
Token* getFirstToken() const override;
Token* getLastToken() const override;
inline TypeExpression* getTypeExpression() const noexcept {
return TE;
}
};
class TypedNode : public Node {
protected:
@ -1307,10 +1387,15 @@ namespace bolt {
class Expression : public TypedNode {
public:
std::vector<Annotation*> Annotations;
protected:
inline Expression(NodeKind Kind):
TypedNode(Kind) {}
inline Expression(NodeKind Kind, std::vector<Annotation*> Annotations = {}):
TypedNode(Kind), Annotations(Annotations) {}
};
@ -1320,13 +1405,25 @@ namespace bolt {
std::vector<std::tuple<IdentifierAlt*, Dot*>> ModulePath;
Symbol* Name;
ReferenceExpression(
inline ReferenceExpression(
std::vector<std::tuple<IdentifierAlt*, Dot*>> ModulePath,
Symbol* Name
): Expression(NodeKind::ReferenceExpression),
ModulePath(ModulePath),
Name(Name) {}
inline ReferenceExpression(
std::vector<Annotation*> Annotations,
std::vector<std::tuple<IdentifierAlt*, Dot*>> ModulePath,
Symbol* Name
): Expression(NodeKind::ReferenceExpression, Annotations),
ModulePath(ModulePath),
Name(Name) {}
inline ByteString getNameAsString() const noexcept {
return Name->getCanonicalText();
}
Token* getFirstToken() const override;
Token* getLastToken() const override;
@ -1376,6 +1473,18 @@ namespace bolt {
BlockStart(BlockStart),
Cases(Cases) {}
inline MatchExpression(
std::vector<Annotation*> Annotations,
class MatchKeyword* MatchKeyword,
Expression* Value,
class BlockStart* BlockStart,
std::vector<MatchCase*> Cases
): Expression(NodeKind::MatchExpression, Annotations),
MatchKeyword(MatchKeyword),
Value(Value),
BlockStart(BlockStart),
Cases(Cases) {}
Token* getFirstToken() const override;
Token* getLastToken() const override;
@ -1397,6 +1506,16 @@ namespace bolt {
Dot(Dot),
Name(Name) {}
inline MemberExpression(
std::vector<Annotation*> Annotations,
class Expression* E,
class Dot* Dot,
Token* Name
): Expression(NodeKind::MemberExpression, Annotations),
E(E),
Dot(Dot),
Name(Name) {}
Token* getFirstToken() const override;
Token* getLastToken() const override;
@ -1422,6 +1541,16 @@ namespace bolt {
Elements(Elements),
RParen(RParen) {}
inline TupleExpression(
std::vector<Annotation*> Annotations,
class LParen* LParen,
std::vector<std::tuple<Expression*, Comma*>> Elements,
class RParen* RParen
): Expression(NodeKind::TupleExpression, Annotations),
LParen(LParen),
Elements(Elements),
RParen(RParen) {}
Token* getFirstToken() const override;
Token* getLastToken() const override;
@ -1443,22 +1572,48 @@ namespace bolt {
Inner(Inner),
RParen(RParen) {}
inline NestedExpression(
std::vector<Annotation*> Annotations,
class LParen* LParen,
Expression* Inner,
class RParen* RParen
): Expression(NodeKind::NestedExpression, Annotations),
LParen(LParen),
Inner(Inner),
RParen(RParen) {}
Token* getFirstToken() const override;
Token* getLastToken() const override;
};
class ConstantExpression : public Expression {
class LiteralExpression : public Expression {
public:
class Literal* Token;
Literal* Token;
ConstantExpression(
class Literal* Token
): Expression(NodeKind::ConstantExpression),
LiteralExpression(
Literal* Token
): Expression(NodeKind::LiteralExpression),
Token(Token) {}
class Token* getFirstToken() const override;
LiteralExpression(
std::vector<Annotation*> Annotations,
Literal* Token
): Expression(NodeKind::LiteralExpression, Annotations),
Token(Token) {}
inline ByteString getAsText() {
ZEN_ASSERT(Token->getKind() == NodeKind::StringLiteral);
return static_cast<StringLiteral*>(Token)->Text;
}
inline int getAsInt() {
ZEN_ASSERT(Token->getKind() == NodeKind::IntegerLiteral);
return static_cast<IntegerLiteral*>(Token)->asInt();
}
class Token* getFirstToken() const override;
class Token* getLastToken() const override;
};
@ -1469,13 +1624,21 @@ namespace bolt {
Expression* Function;
std::vector<Expression*> Args;
CallExpression(
inline CallExpression(
Expression* Function,
std::vector<Expression*> Args
): Expression(NodeKind::CallExpression),
Function(Function),
Args(Args) {}
inline CallExpression(
std::vector<Annotation*> Annotations,
Expression* Function,
std::vector<Expression*> Args
): Expression(NodeKind::CallExpression, Annotations),
Function(Function),
Args(Args) {}
Token* getFirstToken() const override;
Token* getLastToken() const override;
@ -1484,15 +1647,28 @@ namespace bolt {
class InfixExpression : public Expression {
public:
Expression* LHS;
Expression* Left;
Token* Operator;
Expression* RHS;
Expression* Right;
InfixExpression(Expression* LHS, Token* Operator, Expression* RHS):
Expression(NodeKind::InfixExpression),
LHS(LHS),
Operator(Operator),
RHS(RHS) {}
inline InfixExpression(
Expression* Left,
Token* Operator,
Expression* Right
): Expression(NodeKind::InfixExpression),
Left(Left),
Operator(Operator),
Right(Right) {}
inline InfixExpression(
std::vector<Annotation*> Annotations,
Expression* Left,
Token* Operator,
Expression* Right
): Expression(NodeKind::InfixExpression, Annotations),
Left(Left),
Operator(Operator),
Right(Right) {}
Token* getFirstToken() const override;
Token* getLastToken() const override;
@ -2082,7 +2258,7 @@ namespace bolt {
template<> inline NodeKind getNodeType<BindPattern>() { return NodeKind::BindPattern; }
template<> inline NodeKind getNodeType<ReferenceExpression>() { return NodeKind::ReferenceExpression; }
template<> inline NodeKind getNodeType<NestedExpression>() { return NodeKind::NestedExpression; }
template<> inline NodeKind getNodeType<ConstantExpression>() { return NodeKind::ConstantExpression; }
template<> inline NodeKind getNodeType<LiteralExpression>() { return NodeKind::LiteralExpression; }
template<> inline NodeKind getNodeType<CallExpression>() { return NodeKind::CallExpression; }
template<> inline NodeKind getNodeType<InfixExpression>() { return NodeKind::InfixExpression; }
template<> inline NodeKind getNodeType<PrefixExpression>() { return NodeKind::PrefixExpression; }

View file

@ -1,6 +1,7 @@
#pragma once
#include "CST.hpp"
#include "zen/config.hpp"
#include "bolt/CST.hpp"
@ -24,6 +25,7 @@ namespace bolt {
BOLT_GEN_CASE(Dot)
BOLT_GEN_CASE(DotDot)
BOLT_GEN_CASE(Tilde)
BOLT_GEN_CASE(At)
BOLT_GEN_CASE(LParen)
BOLT_GEN_CASE(RParen)
BOLT_GEN_CASE(LBracket)
@ -58,6 +60,8 @@ namespace bolt {
BOLT_GEN_CASE(IdentifierAlt)
BOLT_GEN_CASE(StringLiteral)
BOLT_GEN_CASE(IntegerLiteral)
BOLT_GEN_CASE(ExpressionAnnotation)
BOLT_GEN_CASE(TypeAssertAnnotation)
BOLT_GEN_CASE(TypeclassConstraintExpression)
BOLT_GEN_CASE(EqualityConstraintExpression)
BOLT_GEN_CASE(QualifiedTypeExpression)
@ -79,7 +83,7 @@ namespace bolt {
BOLT_GEN_CASE(MemberExpression)
BOLT_GEN_CASE(TupleExpression)
BOLT_GEN_CASE(NestedExpression)
BOLT_GEN_CASE(ConstantExpression)
BOLT_GEN_CASE(LiteralExpression)
BOLT_GEN_CASE(CallExpression)
BOLT_GEN_CASE(InfixExpression)
BOLT_GEN_CASE(PrefixExpression)
@ -112,371 +116,387 @@ namespace bolt {
}
void visitToken(Token* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitEquals(Equals* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitColon(Colon* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitComma(Comma* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitDot(Dot* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitDotDot(DotDot* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitTilde(Tilde* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitAt(At* N) {
static_cast<D*>(this)->visitToken(N);
}
void visitLParen(LParen* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitRParen(RParen* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitLBracket(LBracket* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitRBracket(RBracket* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitLBrace(LBrace* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitRBrace(RBrace* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitRArrow(RArrow* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitRArrowAlt(RArrowAlt* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitLetKeyword(LetKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitForeignKeyword(ForeignKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitMutKeyword(MutKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitPubKeyword(PubKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitTypeKeyword(TypeKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitReturnKeyword(ReturnKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitModKeyword(ModKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitStructKeyword(StructKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitEnumKeyword(EnumKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitClassKeyword(ClassKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitInstanceKeyword(InstanceKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitElifKeyword(ElifKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitIfKeyword(IfKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitElseKeyword(ElseKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitMatchKeyword(MatchKeyword* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitInvalid(Invalid* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitEndOfFile(EndOfFile* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitBlockStart(BlockStart* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitBlockEnd(BlockEnd* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitLineFoldEnd(LineFoldEnd* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitCustomOperator(CustomOperator* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitAssignment(Assignment* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitIdentifier(Identifier* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitIdentifierAlt(IdentifierAlt* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitStringLiteral(StringLiteral* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitIntegerLiteral(IntegerLiteral* N) {
visitToken(N);
static_cast<D*>(this)->visitToken(N);
}
void visitAnnotation(Annotation* N) {
static_cast<D*>(this)->visitNode(N);
}
void visitTypeAssertAnnotation(TypeAssertAnnotation* N) {
static_cast<D*>(this)->visitAnnotation(N);
}
void visitExpressionAnnotation(ExpressionAnnotation* N) {
static_cast<D*>(this)->visitAnnotation(N);
}
void visitConstraintExpression(ConstraintExpression* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitTypeclassConstraintExpression(TypeclassConstraintExpression* N) {
visitConstraintExpression(N);
static_cast<D*>(this)->visitConstraintExpression(N);
}
void visitEqualityConstraintExpression(EqualityConstraintExpression* N) {
visitConstraintExpression(N);
static_cast<D*>(this)->visitConstraintExpression(N);
}
void visitTypeExpression(TypeExpression* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitQualifiedTypeExpression(QualifiedTypeExpression* N) {
visitTypeExpression(N);
static_cast<D*>(this)->visitTypeExpression(N);
}
void visitReferenceTypeExpression(ReferenceTypeExpression* N) {
visitTypeExpression(N);
static_cast<D*>(this)->visitTypeExpression(N);
}
void visitArrowTypeExpression(ArrowTypeExpression* N) {
visitTypeExpression(N);
static_cast<D*>(this)->visitTypeExpression(N);
}
void visitAppTypeExpression(AppTypeExpression* N) {
visitTypeExpression(N);
static_cast<D*>(this)->visitTypeExpression(N);
}
void visitVarTypeExpression(VarTypeExpression* N) {
visitTypeExpression(N);
static_cast<D*>(this)->visitTypeExpression(N);
}
void visitNestedTypeExpression(NestedTypeExpression* N) {
visitTypeExpression(N);
static_cast<D*>(this)->visitTypeExpression(N);
}
void visitTupleTypeExpression(TupleTypeExpression* N) {
visitTypeExpression(N);
static_cast<D*>(this)->visitTypeExpression(N);
}
void visitPattern(Pattern* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitBindPattern(BindPattern* N) {
visitPattern(N);
static_cast<D*>(this)->visitPattern(N);
}
void visitLiteralPattern(LiteralPattern* N) {
visitPattern(N);
static_cast<D*>(this)->visitPattern(N);
}
void visitNamedPattern(NamedPattern* N) {
visitPattern(N);
static_cast<D*>(this)->visitPattern(N);
}
void visitTuplePattern(TuplePattern* N) {
visitPattern(N);
static_cast<D*>(this)->visitPattern(N);
}
void visitNestedPattern(NestedPattern* N) {
visitPattern(N);
static_cast<D*>(this)->visitPattern(N);
}
void visitListPattern(ListPattern* N) {
visitPattern(N);
static_cast<D*>(this)->visitPattern(N);
}
void visitExpression(Expression* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitReferenceExpression(ReferenceExpression* N) {
visitExpression(N);
static_cast<D*>(this)->visitExpression(N);
}
void visitMatchCase(MatchCase* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitMatchExpression(MatchExpression* N) {
visitExpression(N);
static_cast<D*>(this)->visitExpression(N);
}
void visitMemberExpression(MemberExpression* N) {
visitExpression(N);
static_cast<D*>(this)->visitExpression(N);
}
void visitTupleExpression(TupleExpression* N) {
visitExpression(N);
static_cast<D*>(this)->visitExpression(N);
}
void visitNestedExpression(NestedExpression* N) {
visitExpression(N);
static_cast<D*>(this)->visitExpression(N);
}
void visitConstantExpression(ConstantExpression* N) {
visitExpression(N);
void visitLiteralExpression(LiteralExpression* N) {
static_cast<D*>(this)->visitExpression(N);
}
void visitCallExpression(CallExpression* N) {
visitExpression(N);
static_cast<D*>(this)->visitExpression(N);
}
void visitInfixExpression(InfixExpression* N) {
visitExpression(N);
static_cast<D*>(this)->visitExpression(N);
}
void visitPrefixExpression(PrefixExpression* N) {
visitExpression(N);
static_cast<D*>(this)->visitExpression(N);
}
void visitRecordExpressionField(RecordExpressionField* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitRecordExpression(RecordExpression* N) {
visitExpression(N);
static_cast<D*>(this)->visitExpression(N);
}
void visitStatement(Statement* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitExpressionStatement(ExpressionStatement* N) {
visitStatement(N);
static_cast<D*>(this)->visitStatement(N);
}
void visitReturnStatement(ReturnStatement* N) {
visitStatement(N);
static_cast<D*>(this)->visitStatement(N);
}
void visitIfStatement(IfStatement* N) {
visitStatement(N);
static_cast<D*>(this)->visitStatement(N);
}
void visitIfStatementPart(IfStatementPart* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitTypeAssert(TypeAssert* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitParameter(Parameter* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitLetBody(LetBody* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitLetBlockBody(LetBlockBody* N) {
visitLetBody(N);
static_cast<D*>(this)->visitLetBody(N);
}
void visitLetExprBody(LetExprBody* N) {
visitLetBody(N);
static_cast<D*>(this)->visitLetBody(N);
}
void visitLetDeclaration(LetDeclaration* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitRecordDeclarationField(RecordDeclarationField* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitRecordDeclaration(RecordDeclaration* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitVariantDeclaration(VariantDeclaration* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitVariantDeclarationMember(VariantDeclarationMember* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitTupleVariantDeclarationMember(TupleVariantDeclarationMember* N) {
visitVariantDeclarationMember(N);
static_cast<D*>(this)->visitVariantDeclarationMember(N);
}
void visitRecordVariantDeclarationMember(RecordVariantDeclarationMember* N) {
visitVariantDeclarationMember(N);
static_cast<D*>(this)->visitVariantDeclarationMember(N);
}
void visitClassDeclaration(ClassDeclaration* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitInstanceDeclaration(InstanceDeclaration* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
void visitSourceFile(SourceFile* N) {
visitNode(N);
static_cast<D*>(this)->visitNode(N);
}
public:
@ -495,6 +515,7 @@ namespace bolt {
BOLT_GEN_CHILD_CASE(Dot)
BOLT_GEN_CHILD_CASE(DotDot)
BOLT_GEN_CHILD_CASE(Tilde)
BOLT_GEN_CHILD_CASE(At)
BOLT_GEN_CHILD_CASE(LParen)
BOLT_GEN_CHILD_CASE(RParen)
BOLT_GEN_CHILD_CASE(LBracket)
@ -529,6 +550,8 @@ namespace bolt {
BOLT_GEN_CHILD_CASE(IdentifierAlt)
BOLT_GEN_CHILD_CASE(StringLiteral)
BOLT_GEN_CHILD_CASE(IntegerLiteral)
BOLT_GEN_CHILD_CASE(ExpressionAnnotation)
BOLT_GEN_CHILD_CASE(TypeAssertAnnotation)
BOLT_GEN_CHILD_CASE(TypeclassConstraintExpression)
BOLT_GEN_CHILD_CASE(EqualityConstraintExpression)
BOLT_GEN_CHILD_CASE(QualifiedTypeExpression)
@ -550,7 +573,7 @@ namespace bolt {
BOLT_GEN_CHILD_CASE(MemberExpression)
BOLT_GEN_CHILD_CASE(TupleExpression)
BOLT_GEN_CHILD_CASE(NestedExpression)
BOLT_GEN_CHILD_CASE(ConstantExpression)
BOLT_GEN_CHILD_CASE(LiteralExpression)
BOLT_GEN_CHILD_CASE(CallExpression)
BOLT_GEN_CHILD_CASE(InfixExpression)
BOLT_GEN_CHILD_CASE(PrefixExpression)
@ -596,6 +619,9 @@ namespace bolt {
void visitEachChild(Tilde* N) {
}
void visitEachChild(At* N) {
}
void visitEachChild(LParen* N) {
}
@ -698,6 +724,17 @@ namespace bolt {
void visitEachChild(IntegerLiteral* N) {
}
void visitEachChild(ExpressionAnnotation* N) {
BOLT_VISIT(N->At);
BOLT_VISIT(N->Expression);
}
void visitEachChild(TypeAssertAnnotation* N) {
BOLT_VISIT(N->At);
BOLT_VISIT(N->Colon);
BOLT_VISIT(N->TE);
}
void visitEachChild(TypeclassConstraintExpression* N) {
BOLT_VISIT(N->Name);
for (auto TE: N->TEs) {
@ -809,6 +846,9 @@ namespace bolt {
}
void visitEachChild(ReferenceExpression* N) {
for (auto A: N->Annotations) {
BOLT_VISIT(A);
}
for (auto [Name, Dot]: N->ModulePath) {
BOLT_VISIT(Name);
BOLT_VISIT(Dot);
@ -823,6 +863,9 @@ namespace bolt {
}
void visitEachChild(MatchExpression* N) {
for (auto A: N->Annotations) {
BOLT_VISIT(A);
}
BOLT_VISIT(N->MatchKeyword);
if (N->Value) {
BOLT_VISIT(N->Value);
@ -834,12 +877,18 @@ namespace bolt {
}
void visitEachChild(MemberExpression* N) {
for (auto A: N->Annotations) {
BOLT_VISIT(A);
}
BOLT_VISIT(N->getExpression());
BOLT_VISIT(N->Dot);
BOLT_VISIT(N->Name);
}
void visitEachChild(TupleExpression* N) {
for (auto A: N->Annotations) {
BOLT_VISIT(A);
}
BOLT_VISIT(N->LParen);
for (auto [E, Comma]: N->Elements) {
BOLT_VISIT(E);
@ -851,16 +900,25 @@ namespace bolt {
}
void visitEachChild(NestedExpression* N) {
for (auto A: N->Annotations) {
BOLT_VISIT(A);
}
BOLT_VISIT(N->LParen);
BOLT_VISIT(N->Inner);
BOLT_VISIT(N->RParen);
}
void visitEachChild(ConstantExpression* N) {
void visitEachChild(LiteralExpression* N) {
for (auto A: N->Annotations) {
BOLT_VISIT(A);
}
BOLT_VISIT(N->Token);
}
void visitEachChild(CallExpression* N) {
for (auto A: N->Annotations) {
BOLT_VISIT(A);
}
BOLT_VISIT(N->Function);
for (auto Arg: N->Args) {
BOLT_VISIT(Arg);
@ -868,12 +926,18 @@ namespace bolt {
}
void visitEachChild(InfixExpression* N) {
BOLT_VISIT(N->LHS);
for (auto A: N->Annotations) {
BOLT_VISIT(A);
}
BOLT_VISIT(N->Left);
BOLT_VISIT(N->Operator);
BOLT_VISIT(N->RHS);
BOLT_VISIT(N->Right);
}
void visitEachChild(PrefixExpression* N) {
for (auto A: N->Annotations) {
BOLT_VISIT(A);
}
BOLT_VISIT(N->Operator);
BOLT_VISIT(N->Argument);
}
@ -885,6 +949,9 @@ namespace bolt {
}
void visitEachChild(RecordExpression* N) {
for (auto A: N->Annotations) {
BOLT_VISIT(A);
}
BOLT_VISIT(N->LBrace);
for (auto [Field, Comma]: N->Fields) {
BOLT_VISIT(Field);

View file

@ -54,6 +54,8 @@ namespace bolt {
Diagnostics.clear();
}
void sort();
std::size_t countDiagnostics() const noexcept {
return Diagnostics.size();
}
@ -217,6 +219,7 @@ namespace bolt {
void write(const std::string_view& S);
void write(std::size_t N);
void write(char C);
public:

View file

@ -1,11 +1,8 @@
#pragma once
#include <cwchar>
#include <vector>
#include <stdexcept>
#include <memory>
#include <iostream>
#include "bolt/ByteString.hpp"
#include "bolt/String.hpp"
@ -21,7 +18,6 @@ namespace bolt {
UnificationError,
TypeclassMissing,
InstanceNotFound,
ClassNotFound,
TupleIndexOutOfRange,
InvalidTypeToTypeclass,
FieldNotFound,
@ -45,6 +41,23 @@ namespace bolt {
return nullptr;
}
virtual unsigned getCode() const noexcept = 0;
};
class UnexpectedStringDiagnostic : public Diagnostic {
public:
TextFile& File;
TextLoc Location;
String Actual;
inline UnexpectedStringDiagnostic(TextFile& File, TextLoc Location, String Actual):
Diagnostic(DiagnosticKind::UnexpectedString), File(File), Location(Location), Actual(Actual) {}
unsigned getCode() const noexcept override {
return 1001;
}
};
@ -58,17 +71,9 @@ namespace bolt {
inline UnexpectedTokenDiagnostic(TextFile& File, Token* Actual, std::vector<NodeKind> Expected):
Diagnostic(DiagnosticKind::UnexpectedToken), File(File), Actual(Actual), Expected(Expected) {}
};
class UnexpectedStringDiagnostic : public Diagnostic {
public:
TextFile& File;
TextLoc Location;
String Actual;
inline UnexpectedStringDiagnostic(TextFile& File, TextLoc Location, String Actual):
Diagnostic(DiagnosticKind::UnexpectedString), File(File), Location(Location), Actual(Actual) {}
unsigned getCode() const noexcept override {
return 1101;
}
};
@ -85,6 +90,10 @@ namespace bolt {
return Initiator;
}
unsigned getCode() const noexcept override {
return 2005;
}
};
class UnificationErrorDiagnostic : public Diagnostic {
@ -111,6 +120,10 @@ namespace bolt {
return Source;
}
unsigned getCode() const noexcept override {
return 2010;
}
};
class TypeclassMissingDiagnostic : public Diagnostic {
@ -126,6 +139,10 @@ namespace bolt {
return Decl;
}
unsigned getCode() const noexcept override {
return 2201;
}
};
class InstanceNotFoundDiagnostic : public Diagnostic {
@ -142,15 +159,9 @@ namespace bolt {
return Source;
}
};
class ClassNotFoundDiagnostic : public Diagnostic {
public:
ByteString Name;
inline ClassNotFoundDiagnostic(ByteString Name):
Diagnostic(DiagnosticKind::ClassNotFound), Name(Name) {}
unsigned getCode() const noexcept override {
return 2251;
}
};
@ -163,6 +174,10 @@ namespace bolt {
inline TupleIndexOutOfRangeDiagnostic(TTuple* Tuple, std::size_t I):
Diagnostic(DiagnosticKind::TupleIndexOutOfRange), Tuple(Tuple), I(I) {}
unsigned getCode() const noexcept override {
return 2015;
}
};
class InvalidTypeToTypeclassDiagnostic : public Diagnostic {
@ -179,6 +194,10 @@ namespace bolt {
return Source;
}
unsigned getCode() const noexcept override {
return 2060;
}
};
class FieldNotFoundDiagnostic : public Diagnostic {
@ -192,6 +211,10 @@ namespace bolt {
inline FieldNotFoundDiagnostic(ByteString Name, Type* Ty, TypePath Path, Node* Source):
Diagnostic(DiagnosticKind::FieldNotFound), Name(Name), Ty(Ty), Path(Path), Source(Source) {}
unsigned getCode() const noexcept override {
return 2017;
}
};
}

View file

@ -94,6 +94,8 @@ namespace bolt {
VarTypeExpression* parseVarTypeExpression();
ReferenceTypeExpression* parseReferenceTypeExpression();
std::vector<Annotation*> parseAnnotations();
void checkLineFoldEnd();
void skipToLineFoldEnd();

View file

@ -13,9 +13,12 @@
namespace bolt {
class Token;
class DiagnosticEngine;
class Scanner : public BufferedStream<Token*> {
DiagnosticEngine& DE;
TextFile& File;
Stream<Char>& Chars;
@ -41,13 +44,17 @@ namespace bolt {
return Chars.peek(Offset);
}
std::string scanIdentifier();
Token* readNullable();
protected:
Token* read() override;
public:
Scanner(TextFile& File, Stream<Char>& Chars);
Scanner(DiagnosticEngine& DE, TextFile& File, Stream<Char>& Chars);
};

View file

@ -345,6 +345,22 @@ namespace bolt {
return true;
}
Token* ExpressionAnnotation::getFirstToken() const {
return At;
}
Token* ExpressionAnnotation::getLastToken() const {
return Expression->getLastToken();
}
Token* TypeAssertAnnotation::getFirstToken() const {
return At;
}
Token* TypeAssertAnnotation::getLastToken() const {
return TE->getLastToken();
}
Token* TypeclassConstraintExpression::getFirstToken() const {
return Name;
}
@ -553,11 +569,11 @@ namespace bolt {
return RParen;
}
Token* ConstantExpression::getFirstToken() const {
Token* LiteralExpression::getFirstToken() const {
return Token;
}
Token* ConstantExpression::getLastToken() const {
Token* LiteralExpression::getLastToken() const {
return Token;
}
@ -573,11 +589,11 @@ namespace bolt {
}
Token* InfixExpression::getFirstToken() const {
return LHS->getFirstToken();
return Left->getFirstToken();
}
Token* InfixExpression::getLastToken() const {
return RHS->getLastToken();
return Right->getLastToken();
}
Token* PrefixExpression::getFirstToken() const {
@ -938,6 +954,10 @@ namespace bolt {
return "~";
}
std::string At::getText() const {
return "@";
}
std::string ClassKeyword::getText() const {
return "class";
}

View file

@ -904,6 +904,12 @@ namespace bolt {
Type* Ty;
for (auto A: X->Annotations) {
if (A->getKind() == NodeKind::TypeAssertAnnotation) {
inferTypeExpression(static_cast<TypeAssertAnnotation*>(A)->TE);
}
}
switch (X->getKind()) {
case NodeKind::MatchExpression:
@ -942,9 +948,9 @@ namespace bolt {
break;
}
case NodeKind::ConstantExpression:
case NodeKind::LiteralExpression:
{
auto Const = static_cast<ConstantExpression*>(X);
auto Const = static_cast<LiteralExpression*>(X);
Ty = inferLiteral(Const->Token);
break;
}
@ -1009,8 +1015,8 @@ namespace bolt {
auto OpTy = instantiate(Scm, Infix->Operator);
Ty = createTypeVar();
std::vector<Type*> ArgTys;
ArgTys.push_back(inferExpression(Infix->LHS));
ArgTys.push_back(inferExpression(Infix->RHS));
ArgTys.push_back(inferExpression(Infix->Left));
ArgTys.push_back(inferExpression(Infix->Right));
makeEqual(TArrow::build(ArgTys, Ty), OpTy, X);
break;
}

View file

@ -48,6 +48,25 @@ namespace bolt {
Diagnostic::Diagnostic(DiagnosticKind Kind):
std::runtime_error("a compiler error occurred without being caught"), Kind(Kind) {}
bool sourceLocLessThan(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();
};
void DiagnosticStore::sort() {
std::sort(Diagnostics.begin(), Diagnostics.end(), sourceLocLessThan);
}
static std::string describe(NodeKind Type) {
switch (Type) {
case NodeKind::Identifier:
@ -122,7 +141,7 @@ namespace bolt {
return "a function or variable reference";
case NodeKind::MatchExpression:
return "a match-expression";
case NodeKind::ConstantExpression:
case NodeKind::LiteralExpression:
return "a literal expression";
case NodeKind::MemberExpression:
return "an accessor of a member";
@ -132,6 +151,8 @@ namespace bolt {
return "a branch of an if-statement";
case NodeKind::ListPattern:
return "a list pattern";
case NodeKind::TypeAssertAnnotation:
return "an annotation for a type assertion";
default:
ZEN_UNREACHABLE
}
@ -478,6 +499,10 @@ namespace bolt {
Out << S;
}
void ConsoleDiagnostics::write(char C) {
Out << C;
}
void ConsoleDiagnostics::write(std::size_t I) {
Out << I;
}
@ -849,16 +874,6 @@ namespace bolt {
break;
}
case DiagnosticKind::ClassNotFound:
{
auto E = static_cast<const ClassNotFoundDiagnostic&>(D);
writePrefix(E);
write("the type class ");
writeTypeclassName(E.Name);
write(" was not found.\n\n");
break;
}
case DiagnosticKind::TupleIndexOutOfRange:
{
auto E = static_cast<const TupleIndexOutOfRangeDiagnostic&>(D);

View file

@ -16,9 +16,9 @@ namespace bolt {
// ZEN_ASSERT(Decl && Decl->getKind() == NodeKind::FunctionDeclaration);
// return static_cast<FunctionDeclaration*>(Decl);
}
case NodeKind::ConstantExpression:
case NodeKind::LiteralExpression:
{
auto CE = static_cast<ConstantExpression*>(X);
auto CE = static_cast<LiteralExpression*>(X);
switch (CE->Token->getKind()) {
case NodeKind::IntegerLiteral:
return static_cast<IntegerLiteral*>(CE->Token)->V;

View file

@ -609,6 +609,7 @@ after_tuple_element:
}
Expression* Parser::parsePrimitiveExpression() {
auto Annotations = parseAnnotations();
auto T0 = Tokens.peek();
switch (T0->getKind()) {
case NodeKind::Identifier:
@ -634,7 +635,7 @@ after_tuple_element:
DE.add<UnexpectedTokenDiagnostic>(File, T3, std::vector { NodeKind::Identifier, NodeKind::IdentifierAlt });
return nullptr;
}
return new ReferenceExpression(ModulePath, static_cast<Symbol*>(T3));
return new ReferenceExpression(Annotations, ModulePath, static_cast<Symbol*>(T3));
}
case NodeKind::LParen:
{
@ -687,21 +688,29 @@ after_tuple_element:
}
after_tuple_elements:
if (Elements.size() == 1 && !std::get<1>(Elements.front())) {
return new NestedExpression(LParen, std::get<0>(Elements.front()), RParen);
return new NestedExpression(Annotations, LParen, std::get<0>(Elements.front()), RParen);
}
return new TupleExpression { LParen, Elements, RParen };
return new TupleExpression { Annotations, LParen, Elements, RParen };
}
case NodeKind::MatchKeyword:
return parseMatchExpression();
case NodeKind::IntegerLiteral:
case NodeKind::StringLiteral:
Tokens.get();
return new ConstantExpression(static_cast<Literal*>(T0));
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 });
DE.add<UnexpectedTokenDiagnostic>(File, T0, std::vector {
NodeKind::MatchKeyword,
NodeKind::Identifier,
NodeKind::IdentifierAlt,
NodeKind::LParen,
NodeKind::LBrace,
NodeKind::IntegerLiteral,
NodeKind::StringLiteral
});
return nullptr;
}
}
@ -722,7 +731,8 @@ after_tuple_elements:
case NodeKind::Identifier:
Tokens.get();
Tokens.get();
E = new MemberExpression { E, static_cast<Dot*>(T1), T2 };
E = new MemberExpression { E->Annotations, E, static_cast<Dot*>(T1), T2 };
E->Annotations.clear();
break;
default:
goto finish;
@ -761,7 +771,9 @@ finish:
if (Args.empty()) {
return Operator;
}
return new CallExpression(Operator, Args);
auto Annotations = Operator->Annotations;
Operator->Annotations.clear();
return new CallExpression(Annotations, Operator, Args);
}
Expression* Parser::parseUnaryExpression() {
@ -1518,6 +1530,54 @@ next_member:
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();
skipToLineFoldEnd();
continue;
}
checkLineFoldEnd();
Annotations.push_back(new ExpressionAnnotation { At, E });
break;
}
// default:
// DE.add<UnexpectedTokenDiagnostic>(File, T1, std::vector { NodeKind::Colon, NodeKind::Identifier });
// At->unref();
// skipToLineFoldEnd();
// break;
}
next_annotation:;
}
return Annotations;
}
void Parser::skipToLineFoldEnd() {
unsigned Level = 0;
for (;;) {

View file

@ -9,6 +9,7 @@
#include "bolt/Integer.hpp"
#include "bolt/CST.hpp"
#include "bolt/Diagnostics.hpp"
#include "bolt/DiagnosticEngine.hpp"
#include "bolt/Scanner.hpp"
namespace bolt {
@ -47,6 +48,12 @@ namespace bolt {
}
}
static bool isDirectiveIdentifierStart(Char Chr) {
return (Chr >= 65 && Chr <= 90) // Uppercase letter
|| (Chr >= 96 && Chr <= 122) // Lowercase letter
|| Chr == '_';
}
static bool isIdentifierPart(Char Chr) {
return (Chr >= 65 && Chr <= 90) // Uppercase letter
|| (Chr >= 96 && Chr <= 122) // Lowercase letter
@ -77,10 +84,29 @@ namespace bolt {
{ "enum", NodeKind::EnumKeyword },
};
Scanner::Scanner(TextFile& File, Stream<Char>& Chars):
File(File), Chars(Chars) {}
Scanner::Scanner(DiagnosticEngine& DE, TextFile& File, Stream<Char>& Chars):
DE(DE), File(File), Chars(Chars) {}
Token* Scanner::read() {
std::string Scanner::scanIdentifier() {
auto Loc = getCurrentLoc();
auto C0 = getChar();
if (!isDirectiveIdentifierStart(C0)) {
DE.add<UnexpectedStringDiagnostic>(File, Loc, std::string { C0 });
return nullptr;
}
ByteString Text { static_cast<char>(C0) };
for (;;) {
auto C1 = peekChar();
if (!isIdentifierPart(C1)) {
break;
}
Text.push_back(C1);
getChar();
}
return Text;
}
Token* Scanner::readNullable() {
TextLoc StartLoc;
Char C0;
@ -92,6 +118,23 @@ namespace bolt {
continue;
}
if (C0 == '#') {
getChar();
auto C1 = peekChar(0);
auto C2 = peekChar(1);
if (C1 == '!' && C2 == '!') {
getChar();
getChar();
auto Name = scanIdentifier();
std::string Value;
for (;;) {
C0 = getChar();
Value.push_back(C0);
if (C0 == '\n' || C0 == EOF) {
break;
}
}
continue;
}
for (;;) {
C0 = getChar();
if (C0 == '\n' || C0 == EOF) {
@ -278,7 +321,8 @@ digit_finish:
case '\'': Text.push_back('\''); break;
case '"': Text.push_back('"'); break;
default:
throw UnexpectedStringDiagnostic(File, Loc, String { static_cast<char>(C1) });
DE.add<UnexpectedStringDiagnostic>(File, Loc, String { static_cast<char>(C1) });
return nullptr;
}
Escaping = false;
} else {
@ -305,7 +349,8 @@ after_string_contents:
getChar();
auto C2 = peekChar();
if (C2 == '.') {
throw UnexpectedStringDiagnostic(File, getCurrentLoc(), String { static_cast<char>(C2) });
DE.add<UnexpectedStringDiagnostic>(File, getCurrentLoc(), String { static_cast<char>(C2) });
return nullptr;
}
return new DotDot(StartLoc);
}
@ -347,7 +392,6 @@ after_string_contents:
}
return new CustomOperator(Text, StartLoc);
}
#define BOLT_SIMPLE_TOKEN(ch, name) case ch: return new name(StartLoc);
@ -360,14 +404,26 @@ after_string_contents:
BOLT_SIMPLE_TOKEN('{', LBrace)
BOLT_SIMPLE_TOKEN('}', RBrace)
BOLT_SIMPLE_TOKEN('~', Tilde)
BOLT_SIMPLE_TOKEN('@', At)
default:
throw UnexpectedStringDiagnostic(File, StartLoc, String { static_cast<char>(C0) });
DE.add<UnexpectedStringDiagnostic>(File, StartLoc, String { static_cast<char>(C0) });
return nullptr;
}
}
Token* Scanner::read() {
for (;;) {
auto T0 = readNullable();
if (T0) {
// EndOFFile is guaranteed to be produced, so that ends the stream.
return T0;
}
}
}
Punctuator::Punctuator(Stream<Token*>& Tokens):
Tokens(Tokens) {
Frames.push(FrameType::Block);

View file

@ -306,118 +306,99 @@ namespace bolt {
ZEN_UNREACHABLE
}
// bool Type::operator==(const Type& Other) const noexcept {
// switch (Kind) {
// case TypeKind::Var:
// if (Other.Kind != TypeKind::Var) {
// return false;
// }
// return static_cast<const TVar*>(this)->Id == static_cast<const TVar&>(Other).Id;
// case TypeKind::Tuple:
// {
// if (Other.Kind != TypeKind::Tuple) {
// return false;
// }
// auto A = static_cast<const TTuple&>(*this);
// auto B = static_cast<const TTuple&>(Other);
// if (A.ElementTypes.size() != B.ElementTypes.size()) {
// return false;
// }
// for (auto [T1, T2]: zen::zip(A.ElementTypes, B.ElementTypes)) {
// if (*T1 != *T2) {
// return false;
// }
// }
// return true;
// }
// case TypeKind::TupleIndex:
// {
// if (Other.Kind != TypeKind::TupleIndex) {
// return false;
// }
// auto A = static_cast<const TTupleIndex&>(*this);
// auto B = static_cast<const TTupleIndex&>(Other);
// return A.I == B.I && *A.Ty == *B.Ty;
// }
// case TypeKind::Con:
// {
// if (Other.Kind != TypeKind::Con) {
// return false;
// }
// auto A = static_cast<const TCon&>(*this);
// auto B = static_cast<const TCon&>(Other);
// if (A.Id != B.Id) {
// return false;
// }
// if (A.Args.size() != B.Args.size()) {
// return false;
// }
// for (auto [T1, T2]: zen::zip(A.Args, B.Args)) {
// if (*T1 != *T2) {
// return false;
// }
// }
// return true;
// }
// case TypeKind::Arrow:
// {
// if (Other.Kind != TypeKind::Arrow) {
// return false;
// }
// auto A = static_cast<const TArrow&>(*this);
// auto B = static_cast<const TArrow&>(Other);
// /* ArrowCursor C1 { &A }; */
// /* ArrowCursor C2 { &B }; */
// /* for (;;) { */
// /* auto T1 = C1.next(); */
// /* auto T2 = C2.next(); */
// /* if (T1 == nullptr && T2 == nullptr) { */
// /* break; */
// /* } */
// /* if (T1 == nullptr || T2 == nullptr || *T1 != *T2) { */
// /* return false; */
// /* } */
// /* } */
// if (A.ParamTypes.size() != B.ParamTypes.size()) {
// return false;
// }
// for (auto [T1, T2]: zen::zip(A.ParamTypes, B.ParamTypes)) {
// if (*T1 != *T2) {
// return false;
// }
// }
// return A.ReturnType != B.ReturnType;
// }
// case TypeKind::Absent:
// if (Other.Kind != TypeKind::Absent) {
// return false;
// }
// return true;
// case TypeKind::Nil:
// if (Other.Kind != TypeKind::Nil) {
// return false;
// }
// return true;
// case TypeKind::Present:
// {
// if (Other.Kind != TypeKind::Present) {
// return false;
// }
// auto A = static_cast<const TPresent&>(*this);
// auto B = static_cast<const TPresent&>(Other);
// return *A.Ty == *B.Ty;
// }
// case TypeKind::Field:
// {
// if (Other.Kind != TypeKind::Field) {
// return false;
// }
// auto A = static_cast<const TField&>(*this);
// auto B = static_cast<const TField&>(Other);
// return *A.Ty == *B.Ty && *A.RestTy == *B.RestTy;
// }
// }
// }
bool Type::operator==(const Type& Other) const noexcept {
switch (Kind) {
case TypeKind::Var:
if (Other.Kind != TypeKind::Var) {
return false;
}
return static_cast<const TVar*>(this)->Id == static_cast<const TVar&>(Other).Id;
case TypeKind::Tuple:
{
if (Other.Kind != TypeKind::Tuple) {
return false;
}
auto A = static_cast<const TTuple&>(*this);
auto B = static_cast<const TTuple&>(Other);
if (A.ElementTypes.size() != B.ElementTypes.size()) {
return false;
}
for (auto [T1, T2]: zen::zip(A.ElementTypes, B.ElementTypes)) {
if (*T1 != *T2) {
return false;
}
}
return true;
}
case TypeKind::TupleIndex:
{
if (Other.Kind != TypeKind::TupleIndex) {
return false;
}
auto A = static_cast<const TTupleIndex&>(*this);
auto B = static_cast<const TTupleIndex&>(Other);
return A.I == B.I && *A.Ty == *B.Ty;
}
case TypeKind::Con:
{
if (Other.Kind != TypeKind::Con) {
return false;
}
auto A = static_cast<const TCon&>(*this);
auto B = static_cast<const TCon&>(Other);
if (A.Id != B.Id) {
return false;
}
return true;
}
case TypeKind::App:
{
if (Other.Kind != TypeKind::App) {
return false;
}
auto A = static_cast<const TApp&>(*this);
auto B = static_cast<const TApp&>(Other);
return *A.Op == *B.Op && *A.Arg == *B.Arg;
}
case TypeKind::Arrow:
{
if (Other.Kind != TypeKind::Arrow) {
return false;
}
auto A = static_cast<const TArrow&>(*this);
auto B = static_cast<const TArrow&>(Other);
return *A.ParamType == *B.ParamType && *A.ReturnType == *B.ReturnType;
}
case TypeKind::Absent:
if (Other.Kind != TypeKind::Absent) {
return false;
}
return true;
case TypeKind::Nil:
if (Other.Kind != TypeKind::Nil) {
return false;
}
return true;
case TypeKind::Present:
{
if (Other.Kind != TypeKind::Present) {
return false;
}
auto A = static_cast<const TPresent&>(*this);
auto B = static_cast<const TPresent&>(Other);
return *A.Ty == *B.Ty;
}
case TypeKind::Field:
{
if (Other.Kind != TypeKind::Field) {
return false;
}
auto A = static_cast<const TField&>(*this);
auto B = static_cast<const TField&>(Other);
return A.Name == B.Name && *A.Ty == *B.Ty && *A.RestTy == *B.RestTy;
}
}
}
TypeIterator Type::begin() {
return TypeIterator { this, getStartIndex() };

View file

@ -4,11 +4,13 @@
#include <iostream>
#include <fstream>
#include <algorithm>
#include <map>
#include "zen/config.hpp"
#include "zen/po.hpp"
#include "bolt/CST.hpp"
#include "bolt/CSTVisitor.hpp"
#include "bolt/DiagnosticEngine.hpp"
#include "bolt/Diagnostics.hpp"
#include "bolt/Scanner.hpp"
@ -38,10 +40,14 @@ namespace po = zen::po;
int main(int Argc, const char* Argv[]) {
auto Match = po::program("bolt", "The offical compiler for the Bolt programming language")
.flag(po::flag<bool>("additional-syntax", "Enable additional Bolt syntax for asserting compiler state"))
.flag(po::flag<bool>("direct-diagnostics", "Immediately print diagnostics without sorting them first")) // TODO support default values in zen::po
.subcommand(
po::command("check", "Check sources for programming mistakes")
.pos_arg("file", po::some))
.subcommand(
po::command("verify", "Verify integrity of the compiler on selected file(s)")
.pos_arg("file", po::some))
.subcommand(
po::command("eval", "Run sources")
.pos_arg("file", po::some)
@ -51,10 +57,12 @@ int main(int Argc, const char* Argv[]) {
ZEN_ASSERT(Match.has_subcommand());
auto DirectDiagnostics = Match.has_flag("direct-diagnostics") && Match.get_flag<bool>("direct-diagnostics");
auto [Name, Submatch] = Match.subcommand();
auto IsVerify = Name == "verify";
auto DirectDiagnostics = Match.has_flag("direct-diagnostics") && Match.get_flag<bool>("direct-diagnostics") && !IsVerify;
auto AdditionalSyntax = Match.has_flag("additional-syntax") && Match.get_flag<bool>("additional-syntax");
ConsoleDiagnostics DE;
LanguageConfig Config;
@ -65,7 +73,7 @@ int main(int Argc, const char* Argv[]) {
auto Text = readFile(Filename);
TextFile File { Filename, Text };
VectorStream<ByteString, Char> Chars(Text, EOF);
Scanner S(File, Chars);
Scanner S(DE, File, Chars);
Punctuator PT(S);
Parser P(File, PT, DE);
@ -86,28 +94,78 @@ int main(int Argc, const char* Argv[]) {
TheChecker.check(SF);
}
auto lessThan = [](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(), lessThan);
if (IsVerify) {
for (auto D: DS.Diagnostics) {
DE.addDiagnostic(D);
}
struct Visitor : public CSTVisitor<Visitor> {
Checker& C;
DiagnosticEngine& DE;
void visitExpression(Expression* N) {
for (auto A: N->Annotations) {
if (A->getKind() == NodeKind::TypeAssertAnnotation) {
auto Left = C.getType(N);
auto Right = static_cast<TypeAssertAnnotation*>(A)->getTypeExpression()->getType();
std::cerr << "verify " << describe(Left) << " == " << describe(Right) << std::endl;
if (*Left != *Right) {
DE.add<UnificationErrorDiagnostic>(Left, Right, TypePath(), TypePath(), A);
}
}
}
visitEachChild(N);
}
};
Visitor V { {}, TheChecker, DE };
for (auto SF: SourceFiles) {
V.visit(SF);
}
struct EDVisitor : public CSTVisitor<EDVisitor> {
std::multimap<std::size_t, unsigned> Expected;
void visitExpressionAnnotation(ExpressionAnnotation* N) {
if (N->getExpression()->is<CallExpression>()) {
auto CE = static_cast<CallExpression*>(N->getExpression());
if (CE->Function->is<ReferenceExpression>()) {
auto RE = static_cast<ReferenceExpression*>(CE->Function);
if (RE->getNameAsString() == "expect_diagnostic") {
ZEN_ASSERT(CE->Args.size() == 1 && CE->Args[0]->is<LiteralExpression>());
Expected.emplace(N->Parent->getStartLine(), static_cast<LiteralExpression*>(CE->Args[0])->getAsInt());
}
}
}
}
};
EDVisitor V1;
for (auto SF: SourceFiles) {
V1.visit(SF);
}
for (auto D: DS.Diagnostics) {
auto N = D->getNode();
if (!N) {
DE.addDiagnostic(D);
} else {
auto Line = N->getStartLine();
auto Match = V1.Expected.find(Line);
if (Match != V1.Expected.end() && Match->second == D->getCode()) {
std::cerr << "skipped 1 diagnostic" << std::endl;
} else {
DE.addDiagnostic(D);
}
}
}
} else {
DS.sort();
for (auto D: DS.Diagnostics) {
DE.addDiagnostic(D);
}
if (DE.hasError()) {
return 1;
}
if (DE.hasError()) {
return 1;
}
if (Name == "eval") {

View file

@ -0,0 +1,8 @@
let fac n.
n + 1
return n
@expect_diagnostic 2010
(@:Int fac 1) + (@:Bool True)