Remove indentation in namespaces

This commit is contained in:
Sam Vervaeck 2024-02-19 14:32:24 +01:00
parent 60f1e4519e
commit 800a72f041
Signed by: samvv
SSH key fingerprint: SHA256:dIg0ywU1OP+ZYifrYxy8c5esO72cIKB+4/9wkZj1VaY
25 changed files with 11626 additions and 11624 deletions

View file

@ -6,9 +6,9 @@
namespace bolt { namespace bolt {
using ByteString = std::string; using ByteString = std::string;
using ByteStringView = std::string_view; using ByteStringView = std::string_view;
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -16,328 +16,328 @@
namespace bolt { namespace bolt {
std::string describe(const Type* Ty); // For debugging only std::string describe(const Type* Ty); // For debugging only
enum class SymKind { enum class SymKind {
Type, Type,
Var, Var,
}; };
class DiagnosticEngine; class DiagnosticEngine;
class Constraint; class Constraint;
using ConstraintSet = std::vector<Constraint*>; using ConstraintSet = std::vector<Constraint*>;
enum class SchemeKind : unsigned char { enum class SchemeKind : unsigned char {
Forall, Forall,
}; };
class Scheme { class Scheme {
const SchemeKind Kind; const SchemeKind Kind;
protected: protected:
inline Scheme(SchemeKind Kind): inline Scheme(SchemeKind Kind):
Kind(Kind) {} Kind(Kind) {}
public: public:
inline SchemeKind getKind() const noexcept { inline SchemeKind getKind() const noexcept {
return Kind; return Kind;
}
virtual ~Scheme() {}
};
class Forall : public Scheme {
public:
TVSet* TVs;
ConstraintSet* Constraints;
class Type* Type;
inline Forall(class Type* Type):
Scheme(SchemeKind::Forall), TVs(new TVSet), Constraints(new ConstraintSet), Type(Type) {}
inline Forall(
TVSet* TVs,
ConstraintSet* Constraints,
class Type* Type
): Scheme(SchemeKind::Forall),
TVs(TVs),
Constraints(Constraints),
Type(Type) {}
static bool classof(const Scheme* Scm) {
return Scm->getKind() == SchemeKind::Forall;
}
};
class TypeEnv {
std::unordered_map<std::tuple<ByteString, SymKind>, Scheme*> Mapping;
public:
Scheme* lookup(ByteString Name, SymKind Kind) {
auto Key = std::make_tuple(Name, Kind);
auto Match = Mapping.find(Key);
if (Match == Mapping.end()) {
return nullptr;
} }
return Match->second;
}
virtual ~Scheme() {} void add(ByteString Name, Scheme* Scm, SymKind Kind) {
auto Key = std::make_tuple(Name, Kind);
ZEN_ASSERT(!Mapping.count(Key))
// auto F = static_cast<Forall*>(Scm);
// std::cerr << Name << " : forall ";
// for (auto TV: *F->TVs) {
// std::cerr << describe(TV) << " ";
// }
// std::cerr << ". " << describe(F->Type) << "\n";
Mapping.emplace(Key, Scm);
}
}; };
class Forall : public Scheme {
public:
TVSet* TVs; enum class ConstraintKind {
ConstraintSet* Constraints; Equal,
class Type* Type; Field,
Many,
Empty,
};
inline Forall(class Type* Type): class Constraint {
Scheme(SchemeKind::Forall), TVs(new TVSet), Constraints(new ConstraintSet), Type(Type) {}
inline Forall( const ConstraintKind Kind;
TVSet* TVs,
ConstraintSet* Constraints,
class Type* Type
): Scheme(SchemeKind::Forall),
TVs(TVs),
Constraints(Constraints),
Type(Type) {}
static bool classof(const Scheme* Scm) { public:
return Scm->getKind() == SchemeKind::Forall;
}
}; inline Constraint(ConstraintKind Kind):
Kind(Kind) {}
class TypeEnv { inline ConstraintKind getKind() const noexcept {
return Kind;
}
std::unordered_map<std::tuple<ByteString, SymKind>, Scheme*> Mapping; Constraint* substitute(const TVSub& Sub);
public: virtual ~Constraint() {}
Scheme* lookup(ByteString Name, SymKind Kind) { };
auto Key = std::make_tuple(Name, Kind);
auto Match = Mapping.find(Key);
if (Match == Mapping.end()) {
return nullptr;
}
return Match->second;
}
void add(ByteString Name, Scheme* Scm, SymKind Kind) { class CEqual : public Constraint {
auto Key = std::make_tuple(Name, Kind); public:
ZEN_ASSERT(!Mapping.count(Key))
// auto F = static_cast<Forall*>(Scm);
// std::cerr << Name << " : forall ";
// for (auto TV: *F->TVs) {
// std::cerr << describe(TV) << " ";
// }
// std::cerr << ". " << describe(F->Type) << "\n";
Mapping.emplace(Key, Scm);
}
}; Type* Left;
Type* Right;
Node* Source;
inline CEqual(Type* Left, Type* Right, Node* Source = nullptr):
Constraint(ConstraintKind::Equal), Left(Left), Right(Right), Source(Source) {}
enum class ConstraintKind { };
Equal,
Field,
Many,
Empty,
};
class Constraint { class CField : public Constraint {
public:
const ConstraintKind Kind; Type* TupleTy;
size_t I;
Type* FieldTy;
Node* Source;
public: inline CField(Type* TupleTy, size_t I, Type* FieldTy, Node* Source = nullptr):
Constraint(ConstraintKind::Field), TupleTy(TupleTy), I(I), FieldTy(FieldTy), Source(Source) {}
inline Constraint(ConstraintKind Kind): };
Kind(Kind) {}
inline ConstraintKind getKind() const noexcept { class CMany : public Constraint {
return Kind; public:
}
Constraint* substitute(const TVSub& Sub); ConstraintSet& Elements;
virtual ~Constraint() {} inline CMany(ConstraintSet& Elements):
Constraint(ConstraintKind::Many), Elements(Elements) {}
}; };
class CEqual : public Constraint { class CEmpty : public Constraint {
public: public:
Type* Left; inline CEmpty():
Type* Right; Constraint(ConstraintKind::Empty) {}
Node* Source;
inline CEqual(Type* Left, Type* Right, Node* Source = nullptr): };
Constraint(ConstraintKind::Equal), Left(Left), Right(Right), Source(Source) {}
}; using InferContextFlagsMask = unsigned;
class CField : public Constraint { class InferContext {
public: public:
Type* TupleTy; /**
size_t I; * A heap-allocated list of type variables that eventually will become part of a Forall scheme.
Type* FieldTy; */
Node* Source; TVSet* TVs;
inline CField(Type* TupleTy, size_t I, Type* FieldTy, Node* Source = nullptr): /**
Constraint(ConstraintKind::Field), TupleTy(TupleTy), I(I), FieldTy(FieldTy), Source(Source) {} * A heap-allocated list of constraints that eventually will become part of a Forall scheme.
*/
ConstraintSet* Constraints;
}; TypeEnv Env;
class CMany : public Constraint { Type* ReturnType = nullptr;
public:
ConstraintSet& Elements; InferContext* Parent = nullptr;
inline CMany(ConstraintSet& Elements): };
Constraint(ConstraintKind::Many), Elements(Elements) {}
}; class Checker {
class CEmpty : public Constraint { friend class Unifier;
public: friend class UnificationFrame;
inline CEmpty(): const LanguageConfig& Config;
Constraint(ConstraintKind::Empty) {} DiagnosticEngine& DE;
}; size_t NextConTypeId = 0;
size_t NextTypeVarId = 0;
using InferContextFlagsMask = unsigned; Type* BoolType;
Type* ListType;
Type* IntType;
Type* StringType;
Type* UnitType;
class InferContext { Graph<Node*> RefGraph;
public:
/** std::unordered_map<ByteString, std::vector<InstanceDeclaration*>> InstanceMap;
* A heap-allocated list of type variables that eventually will become part of a Forall scheme.
*/
TVSet* TVs;
/** /// Inference context management
* A heap-allocated list of constraints that eventually will become part of a Forall scheme.
*/
ConstraintSet* Constraints;
TypeEnv Env; InferContext* ActiveContext;
Type* ReturnType = nullptr; InferContext& getContext();
void setContext(InferContext* Ctx);
void popContext();
InferContext* Parent = nullptr; void makeEqual(Type* A, Type* B, Node* Source);
}; void addConstraint(Constraint* Constraint);
class Checker { /**
* Get the return type for the current context. If none could be found, the
* program will abort.
*/
Type* getReturnType();
friend class Unifier; /// Type inference
friend class UnificationFrame;
const LanguageConfig& Config; void forwardDeclare(Node* Node);
DiagnosticEngine& DE; void forwardDeclareFunctionDeclaration(LetDeclaration* N, TVSet* TVs, ConstraintSet* Constraints);
size_t NextConTypeId = 0; Type* inferExpression(Expression* Expression);
size_t NextTypeVarId = 0; Type* inferTypeExpression(TypeExpression* TE, bool AutoVars = true);
Type* inferLiteral(Literal* Lit);
Type* inferPattern(Pattern* Pattern, ConstraintSet* Constraints = new ConstraintSet, TVSet* TVs = new TVSet);
Type* BoolType; void infer(Node* node);
Type* ListType; void inferFunctionDeclaration(LetDeclaration* N);
Type* IntType; void inferConstraintExpression(ConstraintExpression* C);
Type* StringType;
Type* UnitType;
Graph<Node*> RefGraph; /// Factory methods
std::unordered_map<ByteString, std::vector<InstanceDeclaration*>> InstanceMap; Type* createConType(ByteString Name);
Type* createTypeVar();
Type* createRigidVar(ByteString Name);
InferContext* createInferContext(
InferContext* Parent = nullptr,
TVSet* TVs = new TVSet,
ConstraintSet* Constraints = new ConstraintSet
);
/// Inference context management /// Environment manipulation
InferContext* ActiveContext; Scheme* lookup(ByteString Name, SymKind Kind);
InferContext& getContext(); /**
void setContext(InferContext* Ctx); * Looks up a type/variable and ensures that it is a monomorphic type.
void popContext(); *
* This method is mainly syntactic sugar to make it clear in the code when a
* monomorphic type is expected.
*
* Note that if the type is not monomorphic the program will abort with a
* stack trace. It wil **not** print a user-friendly error message.
*
* \returns If the type/variable could not be found `nullptr` is returned.
* Otherwise, a [Type] is returned.
*/
Type* lookupMono(ByteString Name, SymKind Kind);
void makeEqual(Type* A, Type* B, Node* Source); void addBinding(ByteString Name, Scheme* Scm, SymKind Kind);
void addConstraint(Constraint* Constraint); /// Constraint solving
/** /**
* Get the return type for the current context. If none could be found, the * The queue that is used during solving to store any unsolved constraints.
* program will abort. */
*/ std::deque<class Constraint*> Queue;
Type* getReturnType();
/// Type inference /**
* Unify two types, using `Source` as source location.
*
* \returns Whether a type variable was assigned a type or not.
*/
bool unify(Type* Left, Type* Right, Node* Source);
void forwardDeclare(Node* Node); void solve(Constraint* Constraint);
void forwardDeclareFunctionDeclaration(LetDeclaration* N, TVSet* TVs, ConstraintSet* Constraints);
Type* inferExpression(Expression* Expression); /// Helpers
Type* inferTypeExpression(TypeExpression* TE, bool AutoVars = true);
Type* inferLiteral(Literal* Lit);
Type* inferPattern(Pattern* Pattern, ConstraintSet* Constraints = new ConstraintSet, TVSet* TVs = new TVSet);
void infer(Node* node); void populate(SourceFile* SF);
void inferFunctionDeclaration(LetDeclaration* N);
void inferConstraintExpression(ConstraintExpression* C);
/// Factory methods /**
* Verifies that type class signatures on type asserts in let-declarations
* correctly declare the right type classes.
*/
void checkTypeclassSigs(Node* N);
Type* createConType(ByteString Name); Type* instantiate(Scheme* S, Node* Source);
Type* createTypeVar();
Type* createRigidVar(ByteString Name);
InferContext* createInferContext(
InferContext* Parent = nullptr,
TVSet* TVs = new TVSet,
ConstraintSet* Constraints = new ConstraintSet
);
/// Environment manipulation void initialize(Node* N);
Scheme* lookup(ByteString Name, SymKind Kind); public:
/** Checker(const LanguageConfig& Config, DiagnosticEngine& DE);
* Looks up a type/variable and ensures that it is a monomorphic type.
*
* This method is mainly syntactic sugar to make it clear in the code when a
* monomorphic type is expected.
*
* Note that if the type is not monomorphic the program will abort with a
* stack trace. It wil **not** print a user-friendly error message.
*
* \returns If the type/variable could not be found `nullptr` is returned.
* Otherwise, a [Type] is returned.
*/
Type* lookupMono(ByteString Name, SymKind Kind);
void addBinding(ByteString Name, Scheme* Scm, SymKind Kind); /**
* \internal
*/
Type* solveType(Type* Ty);
/// Constraint solving void check(SourceFile* SF);
/** inline Type* getBoolType() const {
* The queue that is used during solving to store any unsolved constraints. return BoolType;
*/ }
std::deque<class Constraint*> Queue;
/** inline Type* getStringType() const {
* Unify two types, using `Source` as source location. return StringType;
* }
* \returns Whether a type variable was assigned a type or not.
*/
bool unify(Type* Left, Type* Right, Node* Source);
void solve(Constraint* Constraint); inline Type* getIntType() const {
return IntType;
}
/// Helpers Type* getType(TypedNode* Node);
void populate(SourceFile* SF); };
/**
* Verifies that type class signatures on type asserts in let-declarations
* correctly declare the right type classes.
*/
void checkTypeclassSigs(Node* N);
Type* instantiate(Scheme* S, Node* Source);
void initialize(Node* N);
public:
Checker(const LanguageConfig& Config, DiagnosticEngine& DE);
/**
* \internal
*/
Type* solveType(Type* Ty);
void check(SourceFile* SF);
inline Type* getBoolType() const {
return BoolType;
}
inline Type* getStringType() const {
return StringType;
}
inline Type* getIntType() const {
return IntType;
}
Type* getType(TypedNode* Node);
};
} }

View file

@ -3,50 +3,50 @@
namespace bolt { namespace bolt {
class LanguageConfig { class LanguageConfig {
enum ConfigFlags {
ConfigFlags_TypeVarsRequireForall = 1 << 0,
};
unsigned Flags = 0;
public:
void setTypeVarsRequireForall(bool Enable) {
if (Enable) {
Flags |= ConfigFlags_TypeVarsRequireForall;
} else {
Flags |= ~ConfigFlags_TypeVarsRequireForall;
}
}
bool typeVarsRequireForall() const noexcept {
return Flags & ConfigFlags_TypeVarsRequireForall;
}
bool hasImmediateDiagnostics() const noexcept {
// TODO make this a configuration flag
return true;
}
enum ConfigFlags {
ConfigFlags_TypeVarsRequireForall = 1 << 0,
}; };
template<typename D, typename B> unsigned Flags = 0;
D* cast(B* base) {
ZEN_ASSERT(D::classof(base)); public:
return static_cast<D*>(base);
void setTypeVarsRequireForall(bool Enable) {
if (Enable) {
Flags |= ConfigFlags_TypeVarsRequireForall;
} else {
Flags |= ~ConfigFlags_TypeVarsRequireForall;
}
} }
template<typename D, typename B> bool typeVarsRequireForall() const noexcept {
const D* cast(const B* base) { return Flags & ConfigFlags_TypeVarsRequireForall;
ZEN_ASSERT(D::classof(base));
return static_cast<const D*>(base);
} }
template<typename D, typename T> bool hasImmediateDiagnostics() const noexcept {
bool isa(const T* value) { // TODO make this a configuration flag
return D::classof(value); return true;
} }
};
template<typename D, typename B>
D* cast(B* base) {
ZEN_ASSERT(D::classof(base));
return static_cast<D*>(base);
}
template<typename D, typename B>
const D* cast(const B* base) {
ZEN_ASSERT(D::classof(base));
return static_cast<const D*>(base);
}
template<typename D, typename T>
bool isa(const T* value) {
return D::classof(value);
}
} }

View file

@ -9,181 +9,181 @@
namespace bolt { namespace bolt {
class Node; class Node;
class Type; class Type;
class TypeclassSignature; class TypeclassSignature;
class Diagnostic; class Diagnostic;
enum class Color { enum class Color {
None, None,
Black, Black,
White, White,
Red, Red,
Yellow, Yellow,
Green, Green,
Blue, Blue,
Cyan, Cyan,
Magenta, Magenta,
}; };
enum StyleFlags : unsigned { enum StyleFlags : unsigned {
StyleFlags_None = 0, StyleFlags_None = 0,
StyleFlags_Bold = 1 << 0, StyleFlags_Bold = 1 << 0,
StyleFlags_Underline = 1 << 1, StyleFlags_Underline = 1 << 1,
StyleFlags_Italic = 1 << 2, StyleFlags_Italic = 1 << 2,
}; };
class Style { class Style {
unsigned Flags = StyleFlags_None; unsigned Flags = StyleFlags_None;
Color FgColor = Color::None; Color FgColor = Color::None;
Color BgColor = Color::None; Color BgColor = Color::None;
public: public:
Color getForegroundColor() const noexcept { Color getForegroundColor() const noexcept {
return FgColor; return FgColor;
}
Color getBackgroundColor() const noexcept {
return BgColor;
}
void setForegroundColor(Color NewColor) noexcept {
FgColor = NewColor;
}
void setBackgroundColor(Color NewColor) noexcept {
BgColor = NewColor;
}
bool hasForegroundColor() const noexcept {
return FgColor != Color::None;
}
bool hasBackgroundColor() const noexcept {
return BgColor != Color::None;
}
void clearForegroundColor() noexcept {
FgColor = Color::None;
}
void clearBackgroundColor() noexcept {
BgColor = Color::None;
}
bool isUnderline() const noexcept {
return Flags & StyleFlags_Underline;
}
bool isItalic() const noexcept {
return Flags & StyleFlags_Italic;
}
bool isBold() const noexcept {
return Flags & StyleFlags_Bold;
}
void setUnderline(bool Enable) noexcept {
if (Enable) {
Flags |= StyleFlags_Underline;
} else {
Flags &= ~StyleFlags_Underline;
} }
}
Color getBackgroundColor() const noexcept { void setItalic(bool Enable) noexcept {
return BgColor; if (Enable) {
Flags |= StyleFlags_Italic;
} else {
Flags &= ~StyleFlags_Italic;
} }
}
void setForegroundColor(Color NewColor) noexcept { void setBold(bool Enable) noexcept {
FgColor = NewColor; if (Enable) {
Flags |= StyleFlags_Bold;
} else {
Flags &= ~StyleFlags_Bold;
} }
}
void setBackgroundColor(Color NewColor) noexcept { void reset() noexcept {
BgColor = NewColor; FgColor = Color::None;
} BgColor = Color::None;
Flags = 0;
}
bool hasForegroundColor() const noexcept { };
return FgColor != Color::None;
}
bool hasBackgroundColor() const noexcept { /**
return BgColor != Color::None; * Prints any diagnostic message that was added to it to the console.
} */
class ConsolePrinter {
void clearForegroundColor() noexcept { std::ostream& Out;
FgColor = Color::None;
}
void clearBackgroundColor() noexcept { Style ActiveStyle;
BgColor = Color::None;
}
bool isUnderline() const noexcept { void setForegroundColor(Color C);
return Flags & StyleFlags_Underline; void setBackgroundColor(Color C);
} void applyStyles();
bool isItalic() const noexcept { void setBold(bool Enable);
return Flags & StyleFlags_Italic; void setItalic(bool Enable);
} void setUnderline(bool Enable);
void resetStyles();
bool isBold() const noexcept { void writeGutter(
return Flags & StyleFlags_Bold; std::size_t GutterWidth,
} std::string Text
);
void setUnderline(bool Enable) noexcept { void writeHighlight(
if (Enable) { std::size_t GutterWidth,
Flags |= StyleFlags_Underline; TextRange Range,
} else { Color HighlightColor,
Flags &= ~StyleFlags_Underline; std::size_t Line,
} std::size_t LineLength
} );
void setItalic(bool Enable) noexcept { void writeExcerpt(
if (Enable) { const TextFile& File,
Flags |= StyleFlags_Italic; TextRange ToPrint,
} else { TextRange ToHighlight,
Flags &= ~StyleFlags_Italic; Color HighlightColor
} );
}
void setBold(bool Enable) noexcept { void writeNode(const Node* N);
if (Enable) {
Flags |= StyleFlags_Bold;
} else {
Flags &= ~StyleFlags_Bold;
}
}
void reset() noexcept { void writePrefix(const Diagnostic& D);
FgColor = Color::None; void writeBinding(const ByteString& Name);
BgColor = Color::None; void writeType(std::size_t I);
Flags = 0; void writeType(const Type* Ty, const TypePath& Underline);
} 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);
void write(char C);
/** public:
* Prints any diagnostic message that was added to it to the console.
*/
class ConsolePrinter {
std::ostream& Out; unsigned ExcerptLinesPre = 2;
unsigned ExcerptLinesPost = 2;
std::size_t MaxTypeSubsitutionCount = 0;
bool PrintFilePosition = true;
bool PrintExcerpts = true;
bool EnableColors = true;
Style ActiveStyle; ConsolePrinter(std::ostream& Out = std::cerr);
void setForegroundColor(Color C); void writeDiagnostic(const Diagnostic& D);
void setBackgroundColor(Color C);
void applyStyles();
void setBold(bool Enable); };
void setItalic(bool Enable);
void setUnderline(bool Enable);
void resetStyles();
void writeGutter(
std::size_t GutterWidth,
std::string Text
);
void writeHighlight(
std::size_t GutterWidth,
TextRange Range,
Color HighlightColor,
std::size_t Line,
std::size_t LineLength
);
void writeExcerpt(
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, const TypePath& Underline);
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);
void write(char C);
public:
unsigned ExcerptLinesPre = 2;
unsigned ExcerptLinesPost = 2;
std::size_t MaxTypeSubsitutionCount = 0;
bool PrintFilePosition = true;
bool PrintExcerpts = true;
bool EnableColors = true;
ConsolePrinter(std::ostream& Out = std::cerr);
void writeDiagnostic(const Diagnostic& D);
};
} }

View file

@ -7,78 +7,78 @@
namespace bolt { namespace bolt {
class ConsolePrinter; class ConsolePrinter;
class Diagnostic; class Diagnostic;
class TypeclassSignature; class TypeclassSignature;
class Type; class Type;
class Node; class Node;
class DiagnosticEngine { class DiagnosticEngine {
protected: protected:
bool HasError = false; bool HasError = false;
virtual void addDiagnostic(Diagnostic* Diagnostic) = 0; virtual void addDiagnostic(Diagnostic* Diagnostic) = 0;
public: public:
bool FailOnError = false; bool FailOnError = false;
inline bool hasError() const noexcept { inline bool hasError() const noexcept {
return HasError; return HasError;
} }
template<typename D, typename ...Ts> template<typename D, typename ...Ts>
void add(Ts&&... Args) { void add(Ts&&... Args) {
// if (FailOnError) { // if (FailOnError) {
// ZEN_PANIC("An error diagnostic caused the program to abort."); // ZEN_PANIC("An error diagnostic caused the program to abort.");
// } // }
HasError = true; HasError = true;
addDiagnostic(new D { std::forward<Ts>(Args)... }); addDiagnostic(new D { std::forward<Ts>(Args)... });
} }
virtual ~DiagnosticEngine() {} virtual ~DiagnosticEngine() {}
}; };
/** /**
* Keeps diagnostics alive in-memory until a seperate procedure processes them. * Keeps diagnostics alive in-memory until a seperate procedure processes them.
*/ */
class DiagnosticStore : public DiagnosticEngine { class DiagnosticStore : public DiagnosticEngine {
public: public:
std::vector<Diagnostic*> Diagnostics; std::vector<Diagnostic*> Diagnostics;
void addDiagnostic(Diagnostic* Diagnostic) { void addDiagnostic(Diagnostic* Diagnostic) {
Diagnostics.push_back(Diagnostic); Diagnostics.push_back(Diagnostic);
} }
void clear() { void clear() {
Diagnostics.clear(); Diagnostics.clear();
} }
void sort(); void sort();
std::size_t countDiagnostics() const noexcept { std::size_t countDiagnostics() const noexcept {
return Diagnostics.size(); return Diagnostics.size();
} }
~DiagnosticStore(); ~DiagnosticStore();
}; };
class ConsoleDiagnostics : public DiagnosticEngine { class ConsoleDiagnostics : public DiagnosticEngine {
ConsolePrinter& ThePrinter; ConsolePrinter& ThePrinter;
protected: protected:
void addDiagnostic(Diagnostic* Diagnostic) override; void addDiagnostic(Diagnostic* Diagnostic) override;
public: public:
ConsoleDiagnostics(ConsolePrinter& ThePrinter); ConsoleDiagnostics(ConsolePrinter& ThePrinter);
}; };
} }

View file

@ -10,237 +10,237 @@
namespace bolt { namespace bolt {
enum class DiagnosticKind : unsigned char { enum class DiagnosticKind : unsigned char {
BindingNotFound, BindingNotFound,
FieldNotFound, FieldNotFound,
InstanceNotFound, InstanceNotFound,
InvalidTypeToTypeclass, InvalidTypeToTypeclass,
NotATuple, NotATuple,
TupleIndexOutOfRange, TupleIndexOutOfRange,
TypeclassMissing, TypeclassMissing,
UnexpectedString, UnexpectedString,
UnexpectedToken, UnexpectedToken,
UnificationError, UnificationError,
}; };
class Diagnostic { class Diagnostic {
const DiagnosticKind Kind; const DiagnosticKind Kind;
protected: protected:
Diagnostic(DiagnosticKind Kind); Diagnostic(DiagnosticKind Kind);
public: public:
inline DiagnosticKind getKind() const noexcept { inline DiagnosticKind getKind() const noexcept {
return Kind; return Kind;
} }
virtual Node* getNode() const { virtual Node* getNode() const {
return nullptr; return nullptr;
} }
virtual unsigned getCode() const noexcept = 0; virtual unsigned getCode() const noexcept = 0;
virtual ~Diagnostic() {} virtual ~Diagnostic() {}
}; };
class UnexpectedStringDiagnostic : public Diagnostic { class UnexpectedStringDiagnostic : public Diagnostic {
public: public:
TextFile& File; TextFile& File;
TextLoc Location; TextLoc Location;
String Actual; String Actual;
inline UnexpectedStringDiagnostic(TextFile& File, TextLoc Location, String Actual): inline UnexpectedStringDiagnostic(TextFile& File, TextLoc Location, String Actual):
Diagnostic(DiagnosticKind::UnexpectedString), File(File), Location(Location), Actual(Actual) {} Diagnostic(DiagnosticKind::UnexpectedString), File(File), Location(Location), Actual(Actual) {}
unsigned getCode() const noexcept override { unsigned getCode() const noexcept override {
return 1001; return 1001;
} }
}; };
class UnexpectedTokenDiagnostic : public Diagnostic { class UnexpectedTokenDiagnostic : public Diagnostic {
public: public:
TextFile& File; TextFile& File;
Token* Actual; Token* Actual;
std::vector<NodeKind> Expected; std::vector<NodeKind> Expected;
inline UnexpectedTokenDiagnostic(TextFile& File, Token* Actual, std::vector<NodeKind> Expected): inline UnexpectedTokenDiagnostic(TextFile& File, Token* Actual, std::vector<NodeKind> Expected):
Diagnostic(DiagnosticKind::UnexpectedToken), File(File), Actual(Actual), Expected(Expected) {} Diagnostic(DiagnosticKind::UnexpectedToken), File(File), Actual(Actual), Expected(Expected) {}
unsigned getCode() const noexcept override { unsigned getCode() const noexcept override {
return 1101; return 1101;
} }
}; };
class BindingNotFoundDiagnostic : public Diagnostic { class BindingNotFoundDiagnostic : public Diagnostic {
public: public:
ByteString Name; ByteString Name;
Node* Initiator; Node* Initiator;
inline BindingNotFoundDiagnostic(ByteString Name, Node* Initiator): inline BindingNotFoundDiagnostic(ByteString Name, Node* Initiator):
Diagnostic(DiagnosticKind::BindingNotFound), Name(Name), Initiator(Initiator) {} Diagnostic(DiagnosticKind::BindingNotFound), Name(Name), Initiator(Initiator) {}
inline Node* getNode() const override { inline Node* getNode() const override {
return Initiator; return Initiator;
} }
unsigned getCode() const noexcept override { unsigned getCode() const noexcept override {
return 2005; return 2005;
} }
}; };
class UnificationErrorDiagnostic : public Diagnostic { class UnificationErrorDiagnostic : public Diagnostic {
public: public:
Type* OrigLeft; Type* OrigLeft;
Type* OrigRight; Type* OrigRight;
TypePath LeftPath; TypePath LeftPath;
TypePath RightPath; TypePath RightPath;
Node* Source; Node* Source;
inline UnificationErrorDiagnostic(Type* OrigLeft, Type* OrigRight, TypePath LeftPath, TypePath RightPath, Node* Source): inline UnificationErrorDiagnostic(Type* OrigLeft, Type* OrigRight, TypePath LeftPath, TypePath RightPath, Node* Source):
Diagnostic(DiagnosticKind::UnificationError), OrigLeft(OrigLeft), OrigRight(OrigRight), LeftPath(LeftPath), RightPath(RightPath), Source(Source) {} Diagnostic(DiagnosticKind::UnificationError), OrigLeft(OrigLeft), OrigRight(OrigRight), LeftPath(LeftPath), RightPath(RightPath), Source(Source) {}
inline Type* getLeft() const { inline Type* getLeft() const {
return OrigLeft->resolve(LeftPath); return OrigLeft->resolve(LeftPath);
} }
inline Type* getRight() const { inline Type* getRight() const {
return OrigRight->resolve(RightPath); return OrigRight->resolve(RightPath);
} }
inline Node* getNode() const override { inline Node* getNode() const override {
return Source; return Source;
} }
unsigned getCode() const noexcept override { unsigned getCode() const noexcept override {
return 2010; return 2010;
} }
}; };
class TypeclassMissingDiagnostic : public Diagnostic { class TypeclassMissingDiagnostic : public Diagnostic {
public: public:
TypeclassSignature Sig; TypeclassSignature Sig;
Node* Decl; Node* Decl;
inline TypeclassMissingDiagnostic(TypeclassSignature Sig, Node* Decl): inline TypeclassMissingDiagnostic(TypeclassSignature Sig, Node* Decl):
Diagnostic(DiagnosticKind::TypeclassMissing), Sig(Sig), Decl(Decl) {} Diagnostic(DiagnosticKind::TypeclassMissing), Sig(Sig), Decl(Decl) {}
inline Node* getNode() const override { inline Node* getNode() const override {
return Decl; return Decl;
} }
unsigned getCode() const noexcept override { unsigned getCode() const noexcept override {
return 2201; return 2201;
} }
}; };
class InstanceNotFoundDiagnostic : public Diagnostic { class InstanceNotFoundDiagnostic : public Diagnostic {
public: public:
ByteString TypeclassName; ByteString TypeclassName;
Type* Ty; Type* Ty;
Node* Source; Node* Source;
inline InstanceNotFoundDiagnostic(ByteString TypeclassName, Type* Ty, Node* Source): inline InstanceNotFoundDiagnostic(ByteString TypeclassName, Type* Ty, Node* Source):
Diagnostic(DiagnosticKind::InstanceNotFound), TypeclassName(TypeclassName), Ty(Ty), Source(Source) {} Diagnostic(DiagnosticKind::InstanceNotFound), TypeclassName(TypeclassName), Ty(Ty), Source(Source) {}
inline Node* getNode() const override { inline Node* getNode() const override {
return Source; return Source;
} }
unsigned getCode() const noexcept override { unsigned getCode() const noexcept override {
return 2251; return 2251;
} }
}; };
class TupleIndexOutOfRangeDiagnostic : public Diagnostic { class TupleIndexOutOfRangeDiagnostic : public Diagnostic {
public: public:
Type* Tuple; Type* Tuple;
std::size_t I; std::size_t I;
Node* Source; Node* Source;
inline TupleIndexOutOfRangeDiagnostic(Type* Tuple, std::size_t I, Node* Source): inline TupleIndexOutOfRangeDiagnostic(Type* Tuple, std::size_t I, Node* Source):
Diagnostic(DiagnosticKind::TupleIndexOutOfRange), Tuple(Tuple), I(I), Source(Source) {} Diagnostic(DiagnosticKind::TupleIndexOutOfRange), Tuple(Tuple), I(I), Source(Source) {}
inline Node * getNode() const override { inline Node * getNode() const override {
return Source; return Source;
} }
unsigned getCode() const noexcept override { unsigned getCode() const noexcept override {
return 2015; return 2015;
} }
}; };
class InvalidTypeToTypeclassDiagnostic : public Diagnostic { class InvalidTypeToTypeclassDiagnostic : public Diagnostic {
public: public:
Type* Actual; Type* Actual;
std::vector<TypeclassId> Classes; std::vector<TypeclassId> Classes;
Node* Source; Node* Source;
inline InvalidTypeToTypeclassDiagnostic(Type* Actual, std::vector<TypeclassId> Classes, Node* Source): inline InvalidTypeToTypeclassDiagnostic(Type* Actual, std::vector<TypeclassId> Classes, Node* Source):
Diagnostic(DiagnosticKind::InvalidTypeToTypeclass), Actual(Actual), Classes(Classes), Source(Source) {} Diagnostic(DiagnosticKind::InvalidTypeToTypeclass), Actual(Actual), Classes(Classes), Source(Source) {}
inline Node* getNode() const override { inline Node* getNode() const override {
return Source; return Source;
} }
unsigned getCode() const noexcept override { unsigned getCode() const noexcept override {
return 2060; return 2060;
} }
}; };
class FieldNotFoundDiagnostic : public Diagnostic { class FieldNotFoundDiagnostic : public Diagnostic {
public: public:
ByteString Name; ByteString Name;
Type* Ty; Type* Ty;
TypePath Path; TypePath Path;
Node* Source; Node* Source;
inline FieldNotFoundDiagnostic(ByteString Name, Type* Ty, TypePath Path, Node* Source): inline FieldNotFoundDiagnostic(ByteString Name, Type* Ty, TypePath Path, Node* Source):
Diagnostic(DiagnosticKind::FieldNotFound), Name(Name), Ty(Ty), Path(Path), Source(Source) {} Diagnostic(DiagnosticKind::FieldNotFound), Name(Name), Ty(Ty), Path(Path), Source(Source) {}
unsigned getCode() const noexcept override { unsigned getCode() const noexcept override {
return 2017; return 2017;
} }
}; };
class NotATupleDiagnostic : public Diagnostic { class NotATupleDiagnostic : public Diagnostic {
public: public:
Type* Ty; Type* Ty;
Node* Source; Node* Source;
inline NotATupleDiagnostic(Type* Ty, Node* Source): inline NotATupleDiagnostic(Type* Ty, Node* Source):
Diagnostic(DiagnosticKind::NotATuple), Ty(Ty), Source(Source) {} Diagnostic(DiagnosticKind::NotATuple), Ty(Ty), Source(Source) {}
inline Node * getNode() const override { inline Node * getNode() const override {
return Source; return Source;
} }
unsigned getCode() const noexcept override { unsigned getCode() const noexcept override {
return 2016; return 2016;
} }
}; };
} }

View file

@ -9,179 +9,180 @@
namespace bolt { namespace bolt {
enum class ValueKind { enum class ValueKind {
Empty, Empty,
String, String,
Integer, Integer,
Tuple, Tuple,
SourceFunction, SourceFunction,
NativeFunction, NativeFunction,
};
class Value {
using NativeFunction = std::function<Value(std::vector<Value>)>;
using Tuple = std::vector<Value>;
ValueKind Kind;
union {
ByteString S;
Integer I;
LetDeclaration* D;
NativeFunction F;
Tuple T;
}; };
class Value { public:
using NativeFunction = std::function<Value(std::vector<Value>)>; Value():
Kind(ValueKind::Empty) {}
using Tuple = std::vector<Value>; Value(ByteString S):
Kind(ValueKind::String), S(S) {}
ValueKind Kind; Value(Integer I):
Kind(ValueKind::Integer), I(I) {}
union { Value(LetDeclaration* D):
ByteString S; Kind(ValueKind::SourceFunction), D(D) {}
Integer I;
LetDeclaration* D;
NativeFunction F;
Tuple T;
};
public: Value(NativeFunction F):
Kind(ValueKind::NativeFunction), F(F) {}
Value(): Value(std::vector<Value> T):
Kind(ValueKind::Empty) {} Kind(ValueKind::Tuple), T(T) {}
Value(ByteString S): Value(const Value& V):
Kind(ValueKind::String), S(S) {} Kind(V.Kind) {
Value(Integer I):
Kind(ValueKind::Integer), I(I) {}
Value(LetDeclaration* D):
Kind(ValueKind::SourceFunction), D(D) {}
Value(NativeFunction F):
Kind(ValueKind::NativeFunction), F(F) {}
Value(std::vector<Value> T):
Kind(ValueKind::Tuple), T(T) {}
Value(const Value& V):
Kind(V.Kind) {
switch (Kind) {
case ValueKind::String:
new (&S) ByteString(V.S);
break;
case ValueKind::Integer:
new (&I) Integer(V.I);
break;
case ValueKind::Tuple:
new (&I) Tuple(V.T);
break;
case ValueKind::SourceFunction:
new (&D) LetDeclaration*(V.D);
break;
case ValueKind::NativeFunction:
new (&F) NativeFunction(V.F);
break;
case ValueKind::Empty:
break;
}
}
Value& operator=(const Value& Other) noexcept {
Kind = Other.Kind;
switch (Kind) { switch (Kind) {
case ValueKind::String: case ValueKind::String:
new (&S) ByteString(Other.S); new (&S) ByteString(V.S);
break; break;
case ValueKind::Integer: case ValueKind::Integer:
new (&I) Integer(Other.I); new (&I) Integer(V.I);
break; break;
case ValueKind::Tuple: case ValueKind::Tuple:
new (&I) Tuple(Other.T); new (&I) Tuple(V.T);
break; break;
case ValueKind::SourceFunction: case ValueKind::SourceFunction:
new (&D) LetDeclaration*(Other.D); new (&D) LetDeclaration*(V.D);
break; break;
case ValueKind::NativeFunction: case ValueKind::NativeFunction:
new (&F) NativeFunction(Other.F); new (&F) NativeFunction(V.F);
break;
case ValueKind::Empty:
break;
}
return *this;
}
// Add move constructor and move assignment methods
inline ValueKind getKind() const noexcept {
return Kind;
}
inline ByteString& asString() {
ZEN_ASSERT(Kind == ValueKind::String);
return S;
}
inline LetDeclaration* getDeclaration() {
ZEN_ASSERT(Kind == ValueKind::SourceFunction);
return D;
}
inline NativeFunction getBinding() {
ZEN_ASSERT(Kind == ValueKind::NativeFunction);
return F;
}
static Value binding(NativeFunction F) {
return Value(F);
}
static Value unit() {
return Value(Tuple {});
}
~Value() {
switch (Kind) {
case ValueKind::String:
S.~ByteString();
break;
case ValueKind::Integer:
I.~Integer();
break;
case ValueKind::Tuple:
T.~Tuple();
break;
case ValueKind::SourceFunction:
break;
case ValueKind::NativeFunction:
F.~NativeFunction();
break; break;
case ValueKind::Empty: case ValueKind::Empty:
break; break;
} }
} }
}; Value& operator=(const Value& Other) noexcept {
Kind = Other.Kind;
class Env { switch (Kind) {
case ValueKind::String:
std::unordered_map<ByteString, Value> Bindings; new (&S) ByteString(Other.S);
break;
public: case ValueKind::Integer:
new (&I) Integer(Other.I);
void add(const ByteString& Name, Value V) { break;
Bindings.emplace(Name, V); case ValueKind::Tuple:
new (&I) Tuple(Other.T);
break;
case ValueKind::SourceFunction:
new (&D) LetDeclaration*(Other.D);
break;
case ValueKind::NativeFunction:
new (&F) NativeFunction(Other.F);
break;
case ValueKind::Empty:
break;
} }
return *this;
}
Value& lookup(const ByteString& Name) { // Add move constructor and move assignment methods
auto Match = Bindings.find(Name);
ZEN_ASSERT(Match != Bindings.end()); inline ValueKind getKind() const noexcept {
return Match->second; return Kind;
}
inline ByteString& asString() {
ZEN_ASSERT(Kind == ValueKind::String);
return S;
}
inline LetDeclaration* getDeclaration() {
ZEN_ASSERT(Kind == ValueKind::SourceFunction);
return D;
}
inline NativeFunction getBinding() {
ZEN_ASSERT(Kind == ValueKind::NativeFunction);
return F;
}
static Value binding(NativeFunction F) {
return Value(F);
}
static Value unit() {
return Value(Tuple {});
}
~Value() {
switch (Kind) {
case ValueKind::String:
S.~ByteString();
break;
case ValueKind::Integer:
I.~Integer();
break;
case ValueKind::Tuple:
T.~Tuple();
break;
case ValueKind::SourceFunction:
break;
case ValueKind::NativeFunction:
F.~NativeFunction();
break;
case ValueKind::Empty:
break;
} }
}
}; };
class Evaluator { class Env {
public: std::unordered_map<ByteString, Value> Bindings;
void assignPattern(Pattern* P, Value& V, Env& E); public:
Value apply(Value Op, std::vector<Value> Args); void add(const ByteString& Name, Value V) {
Bindings.emplace(Name, V);
}
Value evaluateExpression(Expression* N, Env& E); Value& lookup(const ByteString& Name) {
auto Match = Bindings.find(Name);
ZEN_ASSERT(Match != Bindings.end());
return Match->second;
}
void evaluate(Node* N, Env& E); };
class Evaluator {
public:
void assignPattern(Pattern* P, Value& V, Env& E);
Value apply(Value Op, std::vector<Value> Args);
Value evaluateExpression(Expression* N, Env& E);
void evaluate(Node* N, Env& E);
};
};
} }

View file

@ -3,7 +3,7 @@
namespace bolt { namespace bolt {
using Integer = long long; using Integer = long long;
} }

View file

@ -9,144 +9,144 @@
namespace bolt { namespace bolt {
class DiagnosticEngine; class DiagnosticEngine;
class Scanner; class Scanner;
enum OperatorFlags { enum OperatorFlags {
OperatorFlags_Prefix = 1, OperatorFlags_Prefix = 1,
OperatorFlags_Suffix = 2, OperatorFlags_Suffix = 2,
OperatorFlags_InfixL = 4, OperatorFlags_InfixL = 4,
OperatorFlags_InfixR = 8, OperatorFlags_InfixR = 8,
}; };
struct OperatorInfo { struct OperatorInfo {
int Precedence; int Precedence;
unsigned Flags; unsigned Flags;
inline bool isPrefix() const noexcept { inline bool isPrefix() const noexcept {
return Flags & OperatorFlags_Prefix; return Flags & OperatorFlags_Prefix;
} }
inline bool isSuffix() const noexcept { inline bool isSuffix() const noexcept {
return Flags & OperatorFlags_Suffix; return Flags & OperatorFlags_Suffix;
} }
inline bool isInfix() const noexcept { inline bool isInfix() const noexcept {
return Flags & (OperatorFlags_InfixL | OperatorFlags_InfixR); return Flags & (OperatorFlags_InfixL | OperatorFlags_InfixR);
} }
inline bool isRightAssoc() const noexcept { inline bool isRightAssoc() const noexcept {
return Flags & OperatorFlags_InfixR; return Flags & OperatorFlags_InfixR;
} }
}; };
class OperatorTable { class OperatorTable {
std::unordered_map<std::string, OperatorInfo> Mapping; std::unordered_map<std::string, OperatorInfo> Mapping;
public: public:
void add(std::string Name, unsigned Flags, int Precedence); void add(std::string Name, unsigned Flags, int Precedence);
std::optional<OperatorInfo> getInfix(Token* T); std::optional<OperatorInfo> getInfix(Token* T);
bool isInfix(Token* T); bool isInfix(Token* T);
bool isPrefix(Token* T); bool isPrefix(Token* T);
bool isSuffix(Token* T); bool isSuffix(Token* T);
}; };
class Parser { class Parser {
TextFile& File; TextFile& File;
DiagnosticEngine& DE; DiagnosticEngine& DE;
Stream<Token*>& Tokens; Stream<Token*>& Tokens;
OperatorTable ExprOperators; OperatorTable ExprOperators;
Token* peekFirstTokenAfterAnnotationsAndModifiers(); Token* peekFirstTokenAfterAnnotationsAndModifiers();
Token* expectToken(NodeKind Ty); Token* expectToken(NodeKind Ty);
std::vector<RecordDeclarationField*> parseRecordDeclarationFields(); std::vector<RecordDeclarationField*> parseRecordDeclarationFields();
std::optional<std::vector<std::tuple<RecordPatternField*, Comma*>>> parseRecordPatternFields(); std::optional<std::vector<std::tuple<RecordPatternField*, Comma*>>> parseRecordPatternFields();
template<typename T> template<typename T>
T* expectToken() { T* expectToken() {
return static_cast<T*>(expectToken(getNodeType<T>())); return static_cast<T*>(expectToken(getNodeType<T>()));
} }
Expression* parseInfixOperatorAfterExpression(Expression* LHS, int MinPrecedence); Expression* parseInfixOperatorAfterExpression(Expression* LHS, int MinPrecedence);
MatchExpression* parseMatchExpression(); MatchExpression* parseMatchExpression();
Expression* parseMemberExpression(); Expression* parseMemberExpression();
RecordExpression* parseRecordExpression(); RecordExpression* parseRecordExpression();
Expression* parsePrimitiveExpression(); Expression* parsePrimitiveExpression();
ConstraintExpression* parseConstraintExpression(); ConstraintExpression* parseConstraintExpression();
TypeExpression* parseAppTypeExpression(); TypeExpression* parseAppTypeExpression();
TypeExpression* parsePrimitiveTypeExpression(); TypeExpression* parsePrimitiveTypeExpression();
TypeExpression* parseQualifiedTypeExpression(); TypeExpression* parseQualifiedTypeExpression();
TypeExpression* parseArrowTypeExpression(); TypeExpression* parseArrowTypeExpression();
VarTypeExpression* parseVarTypeExpression(); VarTypeExpression* parseVarTypeExpression();
ReferenceTypeExpression* parseReferenceTypeExpression(); ReferenceTypeExpression* parseReferenceTypeExpression();
std::vector<Annotation*> parseAnnotations(); std::vector<Annotation*> parseAnnotations();
void checkLineFoldEnd(); void checkLineFoldEnd();
void skipPastLineFoldEnd(); void skipPastLineFoldEnd();
void skipToRBrace(); void skipToRBrace();
public: public:
Parser(TextFile& File, Stream<Token*>& S, DiagnosticEngine& DE); Parser(TextFile& File, Stream<Token*>& S, DiagnosticEngine& DE);
TypeExpression* parseTypeExpression(); TypeExpression* parseTypeExpression();
ListPattern* parseListPattern(); ListPattern* parseListPattern();
Pattern* parsePrimitivePattern(bool IsNarrow); Pattern* parsePrimitivePattern(bool IsNarrow);
Pattern* parseWidePattern(); Pattern* parseWidePattern();
Pattern* parseNarrowPattern(); Pattern* parseNarrowPattern();
Parameter* parseParam(); Parameter* parseParam();
ReferenceExpression* parseReferenceExpression(); ReferenceExpression* parseReferenceExpression();
Expression* parseUnaryExpression(); Expression* parseUnaryExpression();
Expression* parseExpression(); Expression* parseExpression();
Expression* parseCallExpression(); Expression* parseCallExpression();
IfStatement* parseIfStatement(); IfStatement* parseIfStatement();
ReturnStatement* parseReturnStatement(); ReturnStatement* parseReturnStatement();
ExpressionStatement* parseExpressionStatement(); ExpressionStatement* parseExpressionStatement();
Node* parseLetBodyElement(); Node* parseLetBodyElement();
LetDeclaration* parseLetDeclaration(); LetDeclaration* parseLetDeclaration();
Node* parseClassElement(); Node* parseClassElement();
ClassDeclaration* parseClassDeclaration(); ClassDeclaration* parseClassDeclaration();
InstanceDeclaration* parseInstanceDeclaration(); InstanceDeclaration* parseInstanceDeclaration();
RecordDeclaration* parseRecordDeclaration(); RecordDeclaration* parseRecordDeclaration();
VariantDeclaration* parseVariantDeclaration(); VariantDeclaration* parseVariantDeclaration();
Node* parseSourceElement(); Node* parseSourceElement();
SourceFile* parseSourceFile(); SourceFile* parseSourceFile();
}; };
} }

View file

@ -12,73 +12,73 @@
namespace bolt { namespace bolt {
class Token; class Token;
class DiagnosticEngine; class DiagnosticEngine;
class Scanner : public BufferedStream<Token*> { class Scanner : public BufferedStream<Token*> {
DiagnosticEngine& DE; DiagnosticEngine& DE;
TextFile& File; TextFile& File;
Stream<Char>& Chars; Stream<Char>& Chars;
TextLoc CurrLoc; TextLoc CurrLoc;
inline TextLoc getCurrentLoc() const { inline TextLoc getCurrentLoc() const {
return CurrLoc; return CurrLoc;
}
inline Char getChar() {
auto Chr = Chars.get();
if (Chr == '\n') {
CurrLoc.Line += 1;
CurrLoc.Column = 1;
} else {
CurrLoc.Column += 1;
} }
return Chr;
}
inline Char getChar() { inline Char peekChar(std::size_t Offset = 0) {
auto Chr = Chars.get(); return Chars.peek(Offset);
if (Chr == '\n') { }
CurrLoc.Line += 1;
CurrLoc.Column = 1;
} else {
CurrLoc.Column += 1;
}
return Chr;
}
inline Char peekChar(std::size_t Offset = 0) { std::string scanIdentifier();
return Chars.peek(Offset);
}
std::string scanIdentifier(); Token* readNullable();
Token* readNullable(); protected:
protected: Token* read() override;
Token* read() override; public:
public: Scanner(DiagnosticEngine& DE, TextFile& File, Stream<Char>& Chars);
Scanner(DiagnosticEngine& DE, TextFile& File, Stream<Char>& Chars); };
}; enum class FrameType {
Block,
LineFold,
Fallthrough,
};
enum class FrameType { class Punctuator : public BufferedStream<Token*> {
Block,
LineFold,
Fallthrough,
};
class Punctuator : public BufferedStream<Token*> { Stream<Token*>& Tokens;
Stream<Token*>& Tokens; std::stack<FrameType> Frames;
std::stack<TextLoc> Locations;
std::stack<FrameType> Frames; protected:
std::stack<TextLoc> Locations;
protected: virtual Token* read() override;
virtual Token* read() override; public:
public: Punctuator(Stream<Token*>& Tokens);
Punctuator(Stream<Token*>& Tokens); };
};
} }

View file

@ -8,74 +8,74 @@
namespace bolt { namespace bolt {
template<typename T> template<typename T>
class Stream { class Stream {
public: public:
virtual T get() = 0; virtual T get() = 0;
virtual T peek(std::size_t Offset = 0) = 0; virtual T peek(std::size_t Offset = 0) = 0;
virtual ~Stream() {} virtual ~Stream() {}
}; };
template<typename ContainerT, typename T = typename ContainerT::value_type> template<typename ContainerT, typename T = typename ContainerT::value_type>
class VectorStream : public Stream<T> { class VectorStream : public Stream<T> {
public: public:
using value_type = T; using value_type = T;
ContainerT& Data; ContainerT& Data;
value_type Sentry; value_type Sentry;
std::size_t Offset; std::size_t Offset;
VectorStream(ContainerT& Data, value_type Sentry, std::size_t Offset = 0): VectorStream(ContainerT& Data, value_type Sentry, std::size_t Offset = 0):
Data(Data), Sentry(Sentry), Offset(Offset) {} Data(Data), Sentry(Sentry), Offset(Offset) {}
value_type get() override { value_type get() override {
return Offset < Data.size() ? Data[Offset++] : Sentry; return Offset < Data.size() ? Data[Offset++] : Sentry;
}
value_type peek(std::size_t Offset2) override {
auto I = Offset + Offset2;
return I < Data.size() ? Data[I] : Sentry;
}
};
template<typename T>
class BufferedStream : public Stream<T> {
std::deque<T> Buffer;
protected:
virtual T read() = 0;
public:
using value_type = T;
value_type get() override {
if (Buffer.empty()) {
return read();
} else {
auto Keep = Buffer.front();
Buffer.pop_front();
Keep->unref();
return Keep;
} }
}
value_type peek(std::size_t Offset2) override { value_type peek(std::size_t Offset = 0) override {
auto I = Offset + Offset2; while (Buffer.size() <= Offset) {
return I < Data.size() ? Data[I] : Sentry; auto Item = read();
Item->ref();
Buffer.push_back(Item);
} }
return Buffer[Offset];
}
}; };
template<typename T>
class BufferedStream : public Stream<T> {
std::deque<T> Buffer;
protected:
virtual T read() = 0;
public:
using value_type = T;
value_type get() override {
if (Buffer.empty()) {
return read();
} else {
auto Keep = Buffer.front();
Buffer.pop_front();
Keep->unref();
return Keep;
}
}
value_type peek(std::size_t Offset = 0) override {
while (Buffer.size() <= Offset) {
auto Item = read();
Item->ref();
Buffer.push_back(Item);
}
return Buffer[Offset];
}
};
} }

View file

@ -7,9 +7,9 @@
namespace bolt { namespace bolt {
using Char = char; using Char = char;
using String = std::basic_string<Char>; using String = std::basic_string<Char>;
} }

View file

@ -11,135 +11,136 @@
namespace bolt { namespace bolt {
template<typename V> template<typename V>
class Graph { class Graph {
std::unordered_set<V> Vertices; std::unordered_set<V> Vertices;
std::unordered_multimap<V, V> Edges; std::unordered_multimap<V, V> Edges;
public: public:
void addVertex(V Vert) { void addVertex(V Vert) {
Vertices.emplace(Vert); Vertices.emplace(Vert);
} }
void addEdge(V A, V B) { void addEdge(V A, V B) {
Vertices.emplace(A); Vertices.emplace(A);
Vertices.emplace(B); Vertices.emplace(B);
Edges.emplace(A, B); Edges.emplace(A, B);
} }
std::size_t countVertices() const { std::size_t countVertices() const {
return Vertices.size(); return Vertices.size();
} }
bool hasVertex(const V& Vert) const { bool hasVertex(const V& Vert) const {
return Vertices.count(Vert); return Vertices.count(Vert);
} }
bool hasEdge(const V& From) const { bool hasEdge(const V& From) const {
return Edges.count(From); return Edges.count(From);
} }
bool hasEdge(const V& From, const V& To) const { bool hasEdge(const V& From, const V& To) const {
for (auto X: Edges.equal_range(From)) { for (auto X: Edges.equal_range(From)) {
if (X == To) { if (X == To) {
return true; return true;
}
} }
} }
}
auto getTargetVertices(const V& From) const { auto getTargetVertices(const V& From) const {
return zen::make_iterator_range(Edges.equal_range(From)).map_second(); return zen::make_iterator_range(Edges.equal_range(From)).map_second();
} }
auto getVertices() const { auto getVertices() const {
return zen::make_iterator_range(Vertices); return zen::make_iterator_range(Vertices);
} }
private:
struct TarjanVertexData {
std::optional<std::size_t> Index;
std::size_t LowLink;
bool OnStack = false;
};
class TarjanSolver {
public:
std::vector<std::vector<V>> SCCs;
private: private:
struct TarjanVertexData { const Graph& G;
std::optional<std::size_t> Index; std::unordered_map<V, TarjanVertexData> Map;
std::size_t LowLink; std::size_t Index = 0;
bool OnStack = false; std::stack<V> Stack;
};
class TarjanSolver { TarjanVertexData& getData(V From) {
public: return Map.emplace(From, TarjanVertexData {}).first->second;
}
std::vector<std::vector<V>> SCCs; void visitCycle(const V& From) {
private: auto& DataFrom = getData(From);
DataFrom.Index = Index;
DataFrom.LowLink = Index;
Index++;
Stack.push(From);
DataFrom.OnStack = true;
const Graph& G; for (const auto& To: G.getTargetVertices(From)) {
std::unordered_map<V, TarjanVertexData> Map; auto& DataTo = getData(To);
std::size_t Index = 0; if (!DataTo.Index) {
std::stack<V> Stack; visitCycle(To);
DataFrom.LowLink = std::min(DataFrom.LowLink, DataTo.LowLink);
TarjanVertexData& getData(V From) { } else if (DataTo.OnStack) {
return Map.emplace(From, TarjanVertexData {}).first->second; DataFrom.LowLink = std::min(DataFrom.LowLink, *DataTo.Index);
}
void visitCycle(const V& From) {
auto& DataFrom = getData(From);
DataFrom.Index = Index;
DataFrom.LowLink = Index;
Index++;
Stack.push(From);
DataFrom.OnStack = true;
for (const auto& To: G.getTargetVertices(From)) {
auto& DataTo = getData(To);
if (!DataTo.Index) {
visitCycle(To);
DataFrom.LowLink = std::min(DataFrom.LowLink, DataTo.LowLink);
} else if (DataTo.OnStack) {
DataFrom.LowLink = std::min(DataFrom.LowLink, *DataTo.Index);
}
}
if (DataFrom.LowLink == DataFrom.Index) {
std::vector<V> SCC;
for (;;) {
auto& X = Stack.top();
Stack.pop();
auto& DataX = getData(X);
DataX.OnStack = false;
SCC.push_back(X);
if (X == From) {
break;
}
}
SCCs.push_back(SCC);
}
}
public:
TarjanSolver(const Graph& G):
G(G) {}
void solve() {
for (auto From: G.Vertices) {
if (!Map.count(From)) {
visitCycle(From);
}
} }
} }
}; if (DataFrom.LowLink == DataFrom.Index) {
std::vector<V> SCC;
for (;;) {
auto& X = Stack.top();
Stack.pop();
auto& DataX = getData(X);
DataX.OnStack = false;
SCC.push_back(X);
if (X == From) {
break;
}
}
SCCs.push_back(SCC);
}
public: }
std::vector<std::vector<V>> strongconnect() const { public:
TarjanSolver S { *this };
S.solve(); TarjanSolver(const Graph& G):
return S.SCCs; G(G) {}
void solve() {
for (auto From: G.Vertices) {
if (!Map.count(From)) {
visitCycle(From);
}
}
} }
}; };
public:
std::vector<std::vector<V>> strongconnect() const {
TarjanSolver S { *this };
S.solve();
return S.SCCs;
}
};
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -38,44 +38,44 @@
namespace bolt { namespace bolt {
Diagnostic::Diagnostic(DiagnosticKind Kind): Diagnostic::Diagnostic(DiagnosticKind Kind):
Kind(Kind) {} Kind(Kind) {}
bool sourceLocLessThan(const Diagnostic* L, const Diagnostic* R) { bool sourceLocLessThan(const Diagnostic* L, const Diagnostic* R) {
auto N1 = L->getNode(); auto N1 = L->getNode();
auto N2 = R->getNode(); auto N2 = R->getNode();
if (N1 == nullptr && N2 == nullptr) { if (N1 == nullptr && N2 == nullptr) {
return false; 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);
} }
if (N1 == nullptr) {
DiagnosticStore::~DiagnosticStore() { return true;
for (auto D: Diagnostics) {
delete D;
}
} }
if (N2 == nullptr) {
return false;
}
return N1->getStartLine() < N2->getStartLine() || N1->getStartColumn() < N2->getStartColumn();
};
ConsoleDiagnostics::ConsoleDiagnostics(ConsolePrinter& P): void DiagnosticStore::sort() {
ThePrinter(P) {} std::sort(Diagnostics.begin(), Diagnostics.end(), sourceLocLessThan);
}
void ConsoleDiagnostics::addDiagnostic(Diagnostic* D) { DiagnosticStore::~DiagnosticStore() {
for (auto D: Diagnostics) {
ThePrinter.writeDiagnostic(*D);
// Since this DiagnosticEngine is expected to own the diagnostic, we simply
// destroy the processed diagnostic so that there are no memory leaks.
delete D; delete D;
} }
}
ConsoleDiagnostics::ConsoleDiagnostics(ConsolePrinter& P):
ThePrinter(P) {}
void ConsoleDiagnostics::addDiagnostic(Diagnostic* D) {
ThePrinter.writeDiagnostic(*D);
// Since this DiagnosticEngine is expected to own the diagnostic, we simply
// destroy the processed diagnostic so that there are no memory leaks.
delete D;
}
} }

View file

@ -6,122 +6,122 @@
namespace bolt { namespace bolt {
Value Evaluator::evaluateExpression(Expression* X, Env& Env) { Value Evaluator::evaluateExpression(Expression* X, Env& Env) {
switch (X->getKind()) { switch (X->getKind()) {
case NodeKind::ReferenceExpression: case NodeKind::ReferenceExpression:
{ {
auto RE = static_cast<ReferenceExpression*>(X); auto RE = static_cast<ReferenceExpression*>(X);
return Env.lookup(getCanonicalText(RE->Name)); return Env.lookup(getCanonicalText(RE->Name));
// auto Decl = RE->getScope()->lookup(RE->getSymbolPath()); // auto Decl = RE->getScope()->lookup(RE->getSymbolPath());
// ZEN_ASSERT(Decl && Decl->getKind() == NodeKind::FunctionDeclaration); // ZEN_ASSERT(Decl && Decl->getKind() == NodeKind::FunctionDeclaration);
// return static_cast<FunctionDeclaration*>(Decl); // return static_cast<FunctionDeclaration*>(Decl);
}
case NodeKind::LiteralExpression:
{
auto CE = static_cast<LiteralExpression*>(X);
switch (CE->Token->getKind()) {
case NodeKind::IntegerLiteral:
return static_cast<IntegerLiteral*>(CE->Token)->V;
case NodeKind::StringLiteral:
return static_cast<StringLiteral*>(CE->Token)->Text;
default:
ZEN_UNREACHABLE
}
}
case NodeKind::CallExpression:
{
auto CE = static_cast<CallExpression*>(X);
auto Op = evaluateExpression(CE->Function, Env);
std::vector<Value> Args;
for (auto Arg: CE->Args) {
Args.push_back(evaluateExpression(Arg, Env));
}
return apply(Op, Args);
}
default:
ZEN_UNREACHABLE
} }
} case NodeKind::LiteralExpression:
{
void Evaluator::assignPattern(Pattern* P, Value& V, Env& E) { auto CE = static_cast<LiteralExpression*>(X);
switch (P->getKind()) { switch (CE->Token->getKind()) {
case NodeKind::BindPattern: case NodeKind::IntegerLiteral:
{ return static_cast<IntegerLiteral*>(CE->Token)->V;
auto BP = static_cast<BindPattern*>(P); case NodeKind::StringLiteral:
E.add(getCanonicalText(BP->Name), V); return static_cast<StringLiteral*>(CE->Token)->Text;
break; default:
ZEN_UNREACHABLE
} }
default:
ZEN_UNREACHABLE
} }
} case NodeKind::CallExpression:
{
Value Evaluator::apply(Value Op, std::vector<Value> Args) { auto CE = static_cast<CallExpression*>(X);
switch (Op.getKind()) { auto Op = evaluateExpression(CE->Function, Env);
case ValueKind::SourceFunction: std::vector<Value> Args;
{ for (auto Arg: CE->Args) {
auto Fn = Op.getDeclaration(); Args.push_back(evaluateExpression(Arg, Env));
Env NewEnv;
for (auto [Param, Arg]: zen::zip(Fn->Params, Args)) {
assignPattern(Param->Pattern, Arg, NewEnv);
}
switch (Fn->Body->getKind()) {
case NodeKind::LetExprBody:
return evaluateExpression(static_cast<LetExprBody*>(Fn->Body)->Expression, NewEnv);
default:
ZEN_UNREACHABLE
}
} }
case ValueKind::NativeFunction: return apply(Op, Args);
{
auto Fn = Op.getBinding();
return Fn(Args);
}
default:
ZEN_UNREACHABLE
} }
default:
ZEN_UNREACHABLE
} }
}
void Evaluator::evaluate(Node* N, Env& E) { void Evaluator::assignPattern(Pattern* P, Value& V, Env& E) {
switch (N->getKind()) { switch (P->getKind()) {
case NodeKind::SourceFile: case NodeKind::BindPattern:
{ {
auto SF = static_cast<SourceFile*>(N); auto BP = static_cast<BindPattern*>(P);
for (auto Element: SF->Elements) { E.add(getCanonicalText(BP->Name), V);
evaluate(Element, E); break;
} }
break; default:
ZEN_UNREACHABLE
}
}
Value Evaluator::apply(Value Op, std::vector<Value> Args) {
switch (Op.getKind()) {
case ValueKind::SourceFunction:
{
auto Fn = Op.getDeclaration();
Env NewEnv;
for (auto [Param, Arg]: zen::zip(Fn->Params, Args)) {
assignPattern(Param->Pattern, Arg, NewEnv);
} }
case NodeKind::ExpressionStatement: switch (Fn->Body->getKind()) {
{ case NodeKind::LetExprBody:
auto ES = static_cast<ExpressionStatement*>(N); return evaluateExpression(static_cast<LetExprBody*>(Fn->Body)->Expression, NewEnv);
evaluateExpression(ES->Expression, E); default:
break; ZEN_UNREACHABLE
} }
case NodeKind::LetDeclaration: }
{ case ValueKind::NativeFunction:
auto Decl = static_cast<LetDeclaration*>(N); {
if (Decl->isFunction()) { auto Fn = Op.getBinding();
E.add(Decl->getNameAsString(), Decl); return Fn(Args);
} else { }
Value V; default:
if (Decl->Body) { ZEN_UNREACHABLE
switch (Decl->Body->getKind()) { }
case NodeKind::LetExprBody: }
{
auto Body = static_cast<LetExprBody*>(Decl->Body); void Evaluator::evaluate(Node* N, Env& E) {
V = evaluateExpression(Body->Expression, E); switch (N->getKind()) {
} case NodeKind::SourceFile:
default: {
ZEN_UNREACHABLE auto SF = static_cast<SourceFile*>(N);
for (auto Element: SF->Elements) {
evaluate(Element, E);
}
break;
}
case NodeKind::ExpressionStatement:
{
auto ES = static_cast<ExpressionStatement*>(N);
evaluateExpression(ES->Expression, E);
break;
}
case NodeKind::LetDeclaration:
{
auto Decl = static_cast<LetDeclaration*>(N);
if (Decl->isFunction()) {
E.add(Decl->getNameAsString(), Decl);
} else {
Value V;
if (Decl->Body) {
switch (Decl->Body->getKind()) {
case NodeKind::LetExprBody:
{
auto Body = static_cast<LetExprBody*>(Decl->Body);
V = evaluateExpression(Body->Expression, E);
} }
default:
ZEN_UNREACHABLE
} }
} }
break;
} }
default: break;
ZEN_UNREACHABLE
} }
default:
ZEN_UNREACHABLE
} }
}
} }

File diff suppressed because it is too large Load diff

View file

@ -13,495 +13,495 @@
namespace bolt { namespace bolt {
static inline bool isWhiteSpace(Char Chr) { static inline bool isWhiteSpace(Char Chr) {
switch (Chr) { switch (Chr) {
case ' ': case ' ':
case '\n': case '\n':
case '\r': case '\r':
case '\t': case '\t':
return true; return true;
default: default:
return false; return false;
}
} }
static inline bool isOperatorPart(Char Chr) {
switch (Chr) {
case '+':
case '-':
case '*':
case '/':
case '^':
case '&':
case '|':
case '%':
case '$':
case '!':
case '?':
case '>':
case '<':
case '=':
return true;
default:
return false;
}
}
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
|| (Chr >= 48 && Chr <= 57) // Digit
|| Chr == '_';
}
static int toDigit(Char Chr) {
ZEN_ASSERT(Chr >= 48 && Chr <= 57);
return Chr - 48;
}
std::unordered_map<ByteString, NodeKind> Keywords = {
{ "pub", NodeKind::PubKeyword },
{ "let", NodeKind::LetKeyword },
{ "foreign", NodeKind::ForeignKeyword },
{ "mut", NodeKind::MutKeyword },
{ "return", NodeKind::ReturnKeyword },
{ "type", NodeKind::TypeKeyword },
{ "mod", NodeKind::ModKeyword },
{ "if", NodeKind::IfKeyword },
{ "else", NodeKind::ElseKeyword },
{ "elif", NodeKind::ElifKeyword },
{ "match", NodeKind::MatchKeyword },
{ "class", NodeKind::ClassKeyword },
{ "instance", NodeKind::InstanceKeyword },
{ "struct", NodeKind::StructKeyword },
{ "enum", NodeKind::EnumKeyword },
};
Scanner::Scanner(DiagnosticEngine& DE, TextFile& File, Stream<Char>& Chars):
DE(DE), File(File), Chars(Chars) {}
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() { static inline bool isOperatorPart(Char Chr) {
switch (Chr) {
case '+':
case '-':
case '*':
case '/':
case '^':
case '&':
case '|':
case '%':
case '$':
case '!':
case '?':
case '>':
case '<':
case '=':
return true;
default:
return false;
}
}
TextLoc StartLoc; static bool isDirectiveIdentifierStart(Char Chr) {
Char C0; return (Chr >= 65 && Chr <= 90) // Uppercase letter
|| (Chr >= 96 && Chr <= 122) // Lowercase letter
|| Chr == '_';
}
for (;;) { static bool isIdentifierPart(Char Chr) {
StartLoc = getCurrentLoc(); return (Chr >= 65 && Chr <= 90) // Uppercase letter
C0 = getChar(); || (Chr >= 96 && Chr <= 122) // Lowercase letter
if (isWhiteSpace(C0)) { || (Chr >= 48 && Chr <= 57) // Digit
continue; || Chr == '_';
} }
if (C0 == '#') {
auto C1 = peekChar(0); static int toDigit(Char Chr) {
auto C2 = peekChar(1); ZEN_ASSERT(Chr >= 48 && Chr <= 57);
if (C1 == '!' && C2 == '!') { return Chr - 48;
getChar(); }
getChar();
auto Name = scanIdentifier(); std::unordered_map<ByteString, NodeKind> Keywords = {
std::string Value; { "pub", NodeKind::PubKeyword },
for (;;) { { "let", NodeKind::LetKeyword },
C0 = getChar(); { "foreign", NodeKind::ForeignKeyword },
Value.push_back(C0); { "mut", NodeKind::MutKeyword },
if (C0 == '\n' || C0 == EOF) { { "return", NodeKind::ReturnKeyword },
break; { "type", NodeKind::TypeKeyword },
} { "mod", NodeKind::ModKeyword },
} { "if", NodeKind::IfKeyword },
continue; { "else", NodeKind::ElseKeyword },
} { "elif", NodeKind::ElifKeyword },
{ "match", NodeKind::MatchKeyword },
{ "class", NodeKind::ClassKeyword },
{ "instance", NodeKind::InstanceKeyword },
{ "struct", NodeKind::StructKeyword },
{ "enum", NodeKind::EnumKeyword },
};
Scanner::Scanner(DiagnosticEngine& DE, TextFile& File, Stream<Char>& Chars):
DE(DE), File(File), Chars(Chars) {}
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;
for (;;) {
StartLoc = getCurrentLoc();
C0 = getChar();
if (isWhiteSpace(C0)) {
continue;
}
if (C0 == '#') {
auto C1 = peekChar(0);
auto C2 = peekChar(1);
if (C1 == '!' && C2 == '!') {
getChar();
getChar();
auto Name = scanIdentifier();
std::string Value;
for (;;) { for (;;) {
C0 = getChar(); C0 = getChar();
Value.push_back(C0);
if (C0 == '\n' || C0 == EOF) { if (C0 == '\n' || C0 == EOF) {
break; break;
} }
} }
continue; continue;
} }
break; for (;;) {
C0 = getChar();
if (C0 == '\n' || C0 == EOF) {
break;
}
}
continue;
}
break;
}
switch (C0) {
case static_cast<Char>(EOF):
return new EndOfFile(StartLoc);
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
Integer I = toDigit(C0);
for (;;) {
auto C1 = peekChar();
switch (C1) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
getChar();
I = I * 10 + toDigit(C1);
break;
default:
goto digit_finish;
}
}
digit_finish:
return new IntegerLiteral(I, StartLoc);
} }
switch (C0) { case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
{
ByteString Text { static_cast<char>(C0) };
for (;;) {
auto C1 = peekChar();
if (!isIdentifierPart(C1)) {
break;
}
Text.push_back(C1);
getChar();
}
return new IdentifierAlt(Text, StartLoc);
}
case static_cast<Char>(EOF): case 'a':
return new EndOfFile(StartLoc); case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
case '_':
{
ByteString Text { static_cast<char>(C0) };
for (;;) {
auto C1 = peekChar();
if (!isIdentifierPart(C1)) {
break;
}
Text.push_back(C1);
getChar();
}
auto Match = Keywords.find(Text);
if (Match != Keywords.end()) {
switch (Match->second) {
case NodeKind::PubKeyword:
return new PubKeyword(StartLoc);
case NodeKind::LetKeyword:
return new LetKeyword(StartLoc);
case NodeKind::ForeignKeyword:
return new ForeignKeyword(StartLoc);
case NodeKind::MutKeyword:
return new MutKeyword(StartLoc);
case NodeKind::TypeKeyword:
return new TypeKeyword(StartLoc);
case NodeKind::ReturnKeyword:
return new ReturnKeyword(StartLoc);
case NodeKind::IfKeyword:
return new IfKeyword(StartLoc);
case NodeKind::ElifKeyword:
return new ElifKeyword(StartLoc);
case NodeKind::ElseKeyword:
return new ElseKeyword(StartLoc);
case NodeKind::MatchKeyword:
return new MatchKeyword(StartLoc);
case NodeKind::ClassKeyword:
return new ClassKeyword(StartLoc);
case NodeKind::InstanceKeyword:
return new InstanceKeyword(StartLoc);
case NodeKind::StructKeyword:
return new StructKeyword(StartLoc);
case NodeKind::EnumKeyword:
return new EnumKeyword(StartLoc);
default:
ZEN_UNREACHABLE
}
}
return new Identifier(Text, StartLoc);
}
case '0': case '"':
case '1': {
case '2': ByteString Text;
case '3': bool Escaping = false;
case '4': for (;;) {
case '5': auto Loc = getCurrentLoc();
case '6': auto C1 = getChar();
case '7': if (Escaping) {
case '8':
case '9':
{
Integer I = toDigit(C0);
for (;;) {
auto C1 = peekChar();
switch (C1) { switch (C1) {
case '0': case 'a': Text.push_back('\a'); break;
case '1': case 'b': Text.push_back('\b'); break;
case '2': case 'f': Text.push_back('\f'); break;
case '3': case 'n': Text.push_back('\n'); break;
case '4': case 'r': Text.push_back('\r'); break;
case '5': case 't': Text.push_back('\t'); break;
case '6': case 'v': Text.push_back('\v'); break;
case '7': case '0': Text.push_back('\0'); break;
case '8': case '\'': Text.push_back('\''); break;
case '9': case '"': Text.push_back('"'); break;
getChar(); default:
I = I * 10 + toDigit(C1); DE.add<UnexpectedStringDiagnostic>(File, Loc, String { static_cast<char>(C1) });
return nullptr;
}
Escaping = false;
} else {
switch (C1) {
case '"':
goto after_string_contents;
case '\\':
Escaping = true;
break; break;
default: default:
goto digit_finish; Text.push_back(C1);
break;
} }
} }
digit_finish:
return new IntegerLiteral(I, StartLoc);
} }
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
{
ByteString Text { static_cast<char>(C0) };
for (;;) {
auto C1 = peekChar();
if (!isIdentifierPart(C1)) {
break;
}
Text.push_back(C1);
getChar();
}
return new IdentifierAlt(Text, StartLoc);
}
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
case '_':
{
ByteString Text { static_cast<char>(C0) };
for (;;) {
auto C1 = peekChar();
if (!isIdentifierPart(C1)) {
break;
}
Text.push_back(C1);
getChar();
}
auto Match = Keywords.find(Text);
if (Match != Keywords.end()) {
switch (Match->second) {
case NodeKind::PubKeyword:
return new PubKeyword(StartLoc);
case NodeKind::LetKeyword:
return new LetKeyword(StartLoc);
case NodeKind::ForeignKeyword:
return new ForeignKeyword(StartLoc);
case NodeKind::MutKeyword:
return new MutKeyword(StartLoc);
case NodeKind::TypeKeyword:
return new TypeKeyword(StartLoc);
case NodeKind::ReturnKeyword:
return new ReturnKeyword(StartLoc);
case NodeKind::IfKeyword:
return new IfKeyword(StartLoc);
case NodeKind::ElifKeyword:
return new ElifKeyword(StartLoc);
case NodeKind::ElseKeyword:
return new ElseKeyword(StartLoc);
case NodeKind::MatchKeyword:
return new MatchKeyword(StartLoc);
case NodeKind::ClassKeyword:
return new ClassKeyword(StartLoc);
case NodeKind::InstanceKeyword:
return new InstanceKeyword(StartLoc);
case NodeKind::StructKeyword:
return new StructKeyword(StartLoc);
case NodeKind::EnumKeyword:
return new EnumKeyword(StartLoc);
default:
ZEN_UNREACHABLE
}
}
return new Identifier(Text, StartLoc);
}
case '"':
{
ByteString Text;
bool Escaping = false;
for (;;) {
auto Loc = getCurrentLoc();
auto C1 = getChar();
if (Escaping) {
switch (C1) {
case 'a': Text.push_back('\a'); break;
case 'b': Text.push_back('\b'); break;
case 'f': Text.push_back('\f'); break;
case 'n': Text.push_back('\n'); break;
case 'r': Text.push_back('\r'); break;
case 't': Text.push_back('\t'); break;
case 'v': Text.push_back('\v'); break;
case '0': Text.push_back('\0'); break;
case '\'': Text.push_back('\''); break;
case '"': Text.push_back('"'); break;
default:
DE.add<UnexpectedStringDiagnostic>(File, Loc, String { static_cast<char>(C1) });
return nullptr;
}
Escaping = false;
} else {
switch (C1) {
case '"':
goto after_string_contents;
case '\\':
Escaping = true;
break;
default:
Text.push_back(C1);
break;
}
}
}
after_string_contents: after_string_contents:
return new StringLiteral(Text, StartLoc); return new StringLiteral(Text, StartLoc);
} }
case '.': case '.':
{ {
auto C1 = peekChar();
if (C1 == '.') {
getChar();
auto C2 = peekChar();
if (C2 == '.') {
DE.add<UnexpectedStringDiagnostic>(File, getCurrentLoc(), String { static_cast<char>(C2) });
return nullptr;
}
return new DotDot(StartLoc);
}
return new Dot(StartLoc);
}
case '+':
case '-':
case '*':
case '/':
case '^':
case '&':
case '|':
case '%':
case '$':
case '!':
case '?':
case '>':
case '<':
case '=':
{
ByteString Text { static_cast<char>(C0) };
for (;;) {
auto C1 = peekChar(); auto C1 = peekChar();
if (C1 == '.') { if (!isOperatorPart(C1)) {
getChar(); break;
auto C2 = peekChar();
if (C2 == '.') {
DE.add<UnexpectedStringDiagnostic>(File, getCurrentLoc(), String { static_cast<char>(C2) });
return nullptr;
}
return new DotDot(StartLoc);
} }
return new Dot(StartLoc); Text.push_back(static_cast<char>(C1));
getChar();
} }
if (Text == "|") {
case '+': return new VBar(StartLoc);
case '-': } else if (Text == "->") {
case '*': return new RArrow(StartLoc);
case '/': } else if (Text == "=>") {
case '^': return new RArrowAlt(StartLoc);
case '&': } else if (Text == "=") {
case '|': return new Equals(StartLoc);
case '%': } else if (Text.back() == '=' && Text[Text.size()-2] != '=') {
case '$': return new Assignment(Text.substr(0, Text.size()-1), StartLoc);
case '!':
case '?':
case '>':
case '<':
case '=':
{
ByteString Text { static_cast<char>(C0) };
for (;;) {
auto C1 = peekChar();
if (!isOperatorPart(C1)) {
break;
}
Text.push_back(static_cast<char>(C1));
getChar();
}
if (Text == "|") {
return new VBar(StartLoc);
} else if (Text == "->") {
return new RArrow(StartLoc);
} else if (Text == "=>") {
return new RArrowAlt(StartLoc);
} else if (Text == "=") {
return new Equals(StartLoc);
} else if (Text.back() == '=' && Text[Text.size()-2] != '=') {
return new Assignment(Text.substr(0, Text.size()-1), StartLoc);
}
return new CustomOperator(Text, StartLoc);
} }
return new CustomOperator(Text, StartLoc);
}
#define BOLT_SIMPLE_TOKEN(ch, name) case ch: return new name(StartLoc); #define BOLT_SIMPLE_TOKEN(ch, name) case ch: return new name(StartLoc);
BOLT_SIMPLE_TOKEN(',', Comma) BOLT_SIMPLE_TOKEN(',', Comma)
BOLT_SIMPLE_TOKEN(':', Colon) BOLT_SIMPLE_TOKEN(':', Colon)
BOLT_SIMPLE_TOKEN('(', LParen) BOLT_SIMPLE_TOKEN('(', LParen)
BOLT_SIMPLE_TOKEN(')', RParen) BOLT_SIMPLE_TOKEN(')', RParen)
BOLT_SIMPLE_TOKEN('[', LBracket) BOLT_SIMPLE_TOKEN('[', LBracket)
BOLT_SIMPLE_TOKEN(']', RBracket) BOLT_SIMPLE_TOKEN(']', RBracket)
BOLT_SIMPLE_TOKEN('{', LBrace) BOLT_SIMPLE_TOKEN('{', LBrace)
BOLT_SIMPLE_TOKEN('}', RBrace) BOLT_SIMPLE_TOKEN('}', RBrace)
BOLT_SIMPLE_TOKEN('~', Tilde) BOLT_SIMPLE_TOKEN('~', Tilde)
BOLT_SIMPLE_TOKEN('@', At) BOLT_SIMPLE_TOKEN('@', At)
default: default:
DE.add<UnexpectedStringDiagnostic>(File, StartLoc, String { static_cast<char>(C0) }); DE.add<UnexpectedStringDiagnostic>(File, StartLoc, String { static_cast<char>(C0) });
return nullptr; return nullptr;
}
} }
Token* Scanner::read() { }
for (;;) {
auto T0 = readNullable(); Token* Scanner::read() {
if (T0) { for (;;) {
// EndOFFile is guaranteed to be produced, so that ends the stream. auto T0 = readNullable();
return T0; if (T0) {
} // EndOFFile is guaranteed to be produced, so that ends the stream.
return T0;
} }
} }
}
Punctuator::Punctuator(Stream<Token*>& Tokens): Punctuator::Punctuator(Stream<Token*>& Tokens):
Tokens(Tokens) { Tokens(Tokens) {
Frames.push(FrameType::Block); Frames.push(FrameType::Block);
Locations.push(TextLoc { 0, 0 }); Locations.push(TextLoc { 0, 0 });
} }
Token* Punctuator::read() { Token* Punctuator::read() {
auto T0 = Tokens.peek(); auto T0 = Tokens.peek();
switch (T0->getKind()) { switch (T0->getKind()) {
case NodeKind::LBrace: case NodeKind::LBrace:
Frames.push(FrameType::Fallthrough); Frames.push(FrameType::Fallthrough);
break; break;
case NodeKind::EndOfFile: case NodeKind::EndOfFile:
{ {
if (Frames.size() == 1) { if (Frames.size() == 1) {
return T0;
}
auto Frame = Frames.top();
Frames.pop();
switch (Frame) {
case FrameType::Fallthrough:
break;
case FrameType::Block:
return new BlockEnd(T0->getStartLoc());
case FrameType::LineFold:
return new LineFoldEnd(T0->getStartLoc());
}
}
default:
break;
}
auto RefLoc = Locations.top();
switch (Frames.top()) {
case FrameType::Fallthrough:
{
if (T0->getKind() == NodeKind::RBrace) {
Frames.pop();
}
Tokens.get();
return T0; return T0;
} }
case FrameType::LineFold: auto Frame = Frames.top();
{ Frames.pop();
if (T0->getStartLine() > RefLoc.Line switch (Frame) {
&& T0->getStartColumn() <= RefLoc.Column) { case FrameType::Fallthrough:
Frames.pop(); break;
Locations.pop(); case FrameType::Block:
return new LineFoldEnd(T0->getStartLoc());
}
if (isa<Dot>(T0)) {
auto T1 = Tokens.peek(1);
if (T1->getStartLine() > T0->getEndLine()) {
Tokens.get();
Frames.push(FrameType::Block);
return new BlockStart(T0->getStartLoc());
}
}
return Tokens.get();
}
case FrameType::Block:
{
if (T0->getStartColumn() <= RefLoc.Column) {
Frames.pop();
return new BlockEnd(T0->getStartLoc()); return new BlockEnd(T0->getStartLoc());
} case FrameType::LineFold:
return new LineFoldEnd(T0->getStartLoc());
Frames.push(FrameType::LineFold);
Locations.push(T0->getStartLoc());
return Tokens.get();
} }
} }
default:
ZEN_UNREACHABLE break;
} }
auto RefLoc = Locations.top();
switch (Frames.top()) {
case FrameType::Fallthrough:
{
if (T0->getKind() == NodeKind::RBrace) {
Frames.pop();
}
Tokens.get();
return T0;
}
case FrameType::LineFold:
{
if (T0->getStartLine() > RefLoc.Line
&& T0->getStartColumn() <= RefLoc.Column) {
Frames.pop();
Locations.pop();
return new LineFoldEnd(T0->getStartLoc());
}
if (isa<Dot>(T0)) {
auto T1 = Tokens.peek(1);
if (T1->getStartLine() > T0->getEndLine()) {
Tokens.get();
Frames.push(FrameType::Block);
return new BlockStart(T0->getStartLoc());
}
}
return Tokens.get();
}
case FrameType::Block:
{
if (T0->getStartColumn() <= RefLoc.Column) {
Frames.pop();
return new BlockEnd(T0->getStartLoc());
}
Frames.push(FrameType::LineFold);
Locations.push(T0->getStartLoc());
return Tokens.get();
}
}
ZEN_UNREACHABLE
}
} }

View file

@ -6,48 +6,48 @@
namespace bolt { namespace bolt {
TextFile::TextFile(ByteString Path, ByteString Text): TextFile::TextFile(ByteString Path, ByteString Text):
Path(Path), Text(Text) { Path(Path), Text(Text) {
LineOffsets.push_back(0); LineOffsets.push_back(0);
for (size_t I = 0; I < Text.size(); I++) { for (size_t I = 0; I < Text.size(); I++) {
auto Chr = Text[I]; auto Chr = Text[I];
if (Chr == '\n') { if (Chr == '\n') {
LineOffsets.push_back(I+1); LineOffsets.push_back(I+1);
}
}
LineOffsets.push_back(Text.size());
}
size_t TextFile::getLineCount() const {
return LineOffsets.size();
}
size_t TextFile::getStartOffset(size_t Line) const {
return LineOffsets[Line-1];
}
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) {
return I;
} }
} }
ZEN_UNREACHABLE LineOffsets.push_back(Text.size());
} }
size_t TextFile::getColumn(size_t Offset) const { size_t TextFile::getLineCount() const {
auto Line = getLine(Offset); return LineOffsets.size();
auto StartOffset = getStartOffset(Line); }
return Offset - StartOffset + 1 ;
}
ByteString TextFile::getPath() const { size_t TextFile::getStartOffset(size_t Line) const {
return Path; return LineOffsets[Line-1];
} }
ByteString TextFile::getText() const { size_t TextFile::getLine(size_t Offset) const {
return Text; ZEN_ASSERT(Offset < Text.size());
for (size_t I = 0; I < LineOffsets.size(); ++I) {
if (LineOffsets[I] > Offset) {
return I;
}
} }
ZEN_UNREACHABLE
}
size_t TextFile::getColumn(size_t Offset) const {
auto Line = getLine(Offset);
auto StartOffset = getStartOffset(Line);
return Offset - StartOffset + 1 ;
}
ByteString TextFile::getPath() const {
return Path;
}
ByteString TextFile::getText() const {
return Text;
}
} }

View file

@ -8,328 +8,328 @@
namespace bolt { namespace bolt {
bool TypeclassSignature::operator<(const TypeclassSignature& Other) const { bool TypeclassSignature::operator<(const TypeclassSignature& Other) const {
if (Id < Other.Id) { if (Id < Other.Id) {
return true;
}
ZEN_ASSERT(Params.size() == 1);
ZEN_ASSERT(Other.Params.size() == 1);
return Params[0]->asCon().Id < Other.Params[0]->asCon().Id;
}
bool TypeclassSignature::operator==(const TypeclassSignature& Other) const {
ZEN_ASSERT(Params.size() == 1);
ZEN_ASSERT(Other.Params.size() == 1);
return Id == Other.Id && Params[0]->asCon().Id == Other.Params[0]->asCon().Id;
}
bool TypeIndex::operator==(const TypeIndex& Other) const noexcept {
if (Kind != Other.Kind) {
return false;
}
switch (Kind) {
case TypeIndexKind::ArrowParamType:
case TypeIndexKind::TupleElement:
return I == Other.I;
default:
return true; return true;
}
ZEN_ASSERT(Params.size() == 1);
ZEN_ASSERT(Other.Params.size() == 1);
return Params[0]->asCon().Id < Other.Params[0]->asCon().Id;
} }
}
bool TypeclassSignature::operator==(const TypeclassSignature& Other) const { bool TCon::operator==(const TCon& Other) const {
ZEN_ASSERT(Params.size() == 1); return Id == Other.Id;
ZEN_ASSERT(Other.Params.size() == 1); }
return Id == Other.Id && Params[0]->asCon().Id == Other.Params[0]->asCon().Id;
}
bool TypeIndex::operator==(const TypeIndex& Other) const noexcept { bool TApp::operator==(const TApp& Other) const {
if (Kind != Other.Kind) { return *Op == *Other.Op && *Arg == *Other.Arg;
}
bool TVar::operator==(const TVar& Other) const {
return Id == Other.Id;
}
bool TArrow::operator==(const TArrow& Other) const {
return *ParamType == *Other.ParamType
&& *ReturnType == *Other.ReturnType;
}
bool TTuple::operator==(const TTuple& Other) const {
for (auto [T1, T2]: zen::zip(ElementTypes, Other.ElementTypes)) {
if (*T1 != *T2) {
return false; return false;
} }
switch (Kind) { }
case TypeIndexKind::ArrowParamType: return true;
case TypeIndexKind::TupleElement: }
return I == Other.I;
default: bool TNil::operator==(const TNil& Other) const {
return true; return true;
}
bool TField::operator==(const TField& Other) const {
return Name == Other.Name && *Ty == *Other.Ty && *RestTy == *Other.RestTy;
}
bool TAbsent::operator==(const TAbsent& Other) const {
return true;
}
bool TPresent::operator==(const TPresent& Other) const {
return *Ty == *Other.Ty;
}
bool Type::operator==(const Type& Other) const {
if (Kind != Other.Kind) {
return false;
}
switch (Kind) {
case TypeKind::Var:
return Var == Other.Var;
case TypeKind::Con:
return Con == Other.Con;
case TypeKind::Present:
return Present == Other.Present;
case TypeKind::Absent:
return Absent == Other.Absent;
case TypeKind::Arrow:
return Arrow == Other.Arrow;
case TypeKind::Field:
return Field == Other.Field;
case TypeKind::Nil:
return Nil == Other.Nil;
case TypeKind::Tuple:
return Tuple == Other.Tuple;
case TypeKind::App:
return App == Other.App;
}
ZEN_UNREACHABLE
}
void Type::visitEachChild(std::function<void(Type*)> Proc) {
switch (Kind) {
case TypeKind::Var:
case TypeKind::Absent:
case TypeKind::Nil:
case TypeKind::Con:
break;
case TypeKind::Arrow:
{
Proc(Arrow.ParamType);
Proc(Arrow.ReturnType);
break;
}
case TypeKind::Tuple:
{
for (auto I = 0; I < Tuple.ElementTypes.size(); ++I) {
Proc(Tuple.ElementTypes[I]);
}
break;
}
case TypeKind::App:
{
Proc(App.Op);
Proc(App.Arg);
break;
}
case TypeKind::Field:
{
Proc(Field.Ty);
Proc(Field.RestTy);
break;
}
case TypeKind::Present:
{
Proc(Present.Ty);
break;
} }
} }
}
bool TCon::operator==(const TCon& Other) const { Type* Type::rewrite(std::function<Type*(Type*)> Fn, bool Recursive) {
return Id == Other.Id; auto Ty2 = Fn(this);
} if (this != Ty2) {
if (Recursive) {
bool TApp::operator==(const TApp& Other) const { return Ty2->rewrite(Fn, Recursive);
return *Op == *Other.Op && *Arg == *Other.Arg;
}
bool TVar::operator==(const TVar& Other) const {
return Id == Other.Id;
}
bool TArrow::operator==(const TArrow& Other) const {
return *ParamType == *Other.ParamType
&& *ReturnType == *Other.ReturnType;
}
bool TTuple::operator==(const TTuple& Other) const {
for (auto [T1, T2]: zen::zip(ElementTypes, Other.ElementTypes)) {
if (*T1 != *T2) {
return false;
}
} }
return true; return Ty2;
} }
switch (Kind) {
bool TNil::operator==(const TNil& Other) const { case TypeKind::Var:
return true;
}
bool TField::operator==(const TField& Other) const {
return Name == Other.Name && *Ty == *Other.Ty && *RestTy == *Other.RestTy;
}
bool TAbsent::operator==(const TAbsent& Other) const {
return true;
}
bool TPresent::operator==(const TPresent& Other) const {
return *Ty == *Other.Ty;
}
bool Type::operator==(const Type& Other) const {
if (Kind != Other.Kind) {
return false;
}
switch (Kind) {
case TypeKind::Var:
return Var == Other.Var;
case TypeKind::Con:
return Con == Other.Con;
case TypeKind::Present:
return Present == Other.Present;
case TypeKind::Absent:
return Absent == Other.Absent;
case TypeKind::Arrow:
return Arrow == Other.Arrow;
case TypeKind::Field:
return Field == Other.Field;
case TypeKind::Nil:
return Nil == Other.Nil;
case TypeKind::Tuple:
return Tuple == Other.Tuple;
case TypeKind::App:
return App == Other.App;
}
ZEN_UNREACHABLE
}
void Type::visitEachChild(std::function<void(Type*)> Proc) {
switch (Kind) {
case TypeKind::Var:
case TypeKind::Absent:
case TypeKind::Nil:
case TypeKind::Con:
break;
case TypeKind::Arrow:
{
Proc(Arrow.ParamType);
Proc(Arrow.ReturnType);
break;
}
case TypeKind::Tuple:
{
for (auto I = 0; I < Tuple.ElementTypes.size(); ++I) {
Proc(Tuple.ElementTypes[I]);
}
break;
}
case TypeKind::App:
{
Proc(App.Op);
Proc(App.Arg);
break;
}
case TypeKind::Field:
{
Proc(Field.Ty);
Proc(Field.RestTy);
break;
}
case TypeKind::Present:
{
Proc(Present.Ty);
break;
}
}
}
Type* Type::rewrite(std::function<Type*(Type*)> Fn, bool Recursive) {
auto Ty2 = Fn(this);
if (this != Ty2) {
if (Recursive) {
return Ty2->rewrite(Fn, Recursive);
}
return Ty2; return Ty2;
case TypeKind::Arrow:
{
auto Arrow = Ty2->asArrow();
bool Changed = false;
Type* NewParamType = Arrow.ParamType->rewrite(Fn, Recursive);
if (NewParamType != Arrow.ParamType) {
Changed = true;
}
auto NewRetTy = Arrow.ReturnType->rewrite(Fn, Recursive);
if (NewRetTy != Arrow.ReturnType) {
Changed = true;
}
return Changed ? new Type(TArrow(NewParamType, NewRetTy)) : Ty2;
} }
switch (Kind) { case TypeKind::Con:
case TypeKind::Var: return Ty2;
case TypeKind::App:
{
auto App = Ty2->asApp();
auto NewOp = App.Op->rewrite(Fn, Recursive);
auto NewArg = App.Arg->rewrite(Fn, Recursive);
if (NewOp == App.Op && NewArg == App.Arg) {
return Ty2; return Ty2;
case TypeKind::Arrow:
{
auto Arrow = Ty2->asArrow();
bool Changed = false;
Type* NewParamType = Arrow.ParamType->rewrite(Fn, Recursive);
if (NewParamType != Arrow.ParamType) {
Changed = true;
}
auto NewRetTy = Arrow.ReturnType->rewrite(Fn, Recursive);
if (NewRetTy != Arrow.ReturnType) {
Changed = true;
}
return Changed ? new Type(TArrow(NewParamType, NewRetTy)) : Ty2;
}
case TypeKind::Con:
return Ty2;
case TypeKind::App:
{
auto App = Ty2->asApp();
auto NewOp = App.Op->rewrite(Fn, Recursive);
auto NewArg = App.Arg->rewrite(Fn, Recursive);
if (NewOp == App.Op && NewArg == App.Arg) {
return Ty2;
}
return new Type(TApp(NewOp, NewArg));
}
case TypeKind::Tuple:
{
auto Tuple = Ty2->asTuple();
bool Changed = false;
std::vector<Type*> NewElementTypes;
for (auto Ty: Tuple.ElementTypes) {
auto NewElementType = Ty->rewrite(Fn, Recursive);
if (NewElementType != Ty) {
Changed = true;
}
NewElementTypes.push_back(NewElementType);
}
return Changed ? new Type(TTuple(NewElementTypes)) : Ty2;
}
case TypeKind::Nil:
return Ty2;
case TypeKind::Absent:
return Ty2;
case TypeKind::Field:
{
auto Field = Ty2->asField();
bool Changed = false;
auto NewTy = Field.Ty->rewrite(Fn, Recursive);
if (NewTy != Field.Ty) {
Changed = true;
}
auto NewRestTy = Field.RestTy->rewrite(Fn, Recursive);
if (NewRestTy != Field.RestTy) {
Changed = true;
}
return Changed ? new Type(TField(Field.Name, NewTy, NewRestTy)) : Ty2;
}
case TypeKind::Present:
{
auto Present = Ty2->asPresent();
auto NewTy = Present.Ty->rewrite(Fn, Recursive);
if (NewTy == Present.Ty) {
return Ty2;
}
return new Type(TPresent(NewTy));
} }
return new Type(TApp(NewOp, NewArg));
} }
ZEN_UNREACHABLE case TypeKind::Tuple:
} {
auto Tuple = Ty2->asTuple();
Type* Type::substitute(const TVSub &Sub) { bool Changed = false;
return rewrite([&](auto Ty) { std::vector<Type*> NewElementTypes;
if (Ty->isVar()) { for (auto Ty: Tuple.ElementTypes) {
auto Match = Sub.find(Ty); auto NewElementType = Ty->rewrite(Fn, Recursive);
return Match != Sub.end() ? Match->second->substitute(Sub) : Ty; if (NewElementType != Ty) {
} Changed = true;
return Ty;
}, false);
}
Type* Type::resolve(const TypeIndex& Index) const noexcept {
switch (Index.Kind) {
case TypeIndexKind::PresentType:
return this->asPresent().Ty;
case TypeIndexKind::AppOpType:
return this->asApp().Op;
case TypeIndexKind::AppArgType:
return this->asApp().Arg;
case TypeIndexKind::TupleElement:
return this->asTuple().ElementTypes[Index.I];
case TypeIndexKind::ArrowParamType:
return this->asArrow().ParamType;
case TypeIndexKind::ArrowReturnType:
return this->asArrow().ReturnType;
case TypeIndexKind::FieldType:
return this->asField().Ty;
case TypeIndexKind::FieldRestType:
return this->asField().RestTy;
case TypeIndexKind::End:
ZEN_UNREACHABLE
}
ZEN_UNREACHABLE
}
TVSet Type::getTypeVars() {
TVSet Out;
std::function<void(Type*)> visit = [&](Type* Ty) {
if (Ty->isVar()) {
Out.emplace(Ty);
return;
}
Ty->visitEachChild(visit);
};
visit(this);
return Out;
}
TypeIterator Type::begin() {
return TypeIterator { this, getStartIndex() };
}
TypeIterator Type::end() {
return TypeIterator { this, getEndIndex() };
}
TypeIndex Type::getStartIndex() const {
switch (Kind) {
case TypeKind::Arrow:
return TypeIndex::forArrowParamType();
case TypeKind::Tuple:
{
if (asTuple().ElementTypes.empty()) {
return TypeIndex(TypeIndexKind::End);
} }
return TypeIndex::forTupleElement(0); NewElementTypes.push_back(NewElementType);
} }
case TypeKind::Field: return Changed ? new Type(TTuple(NewElementTypes)) : Ty2;
return TypeIndex::forFieldType(); }
default: case TypeKind::Nil:
return Ty2;
case TypeKind::Absent:
return Ty2;
case TypeKind::Field:
{
auto Field = Ty2->asField();
bool Changed = false;
auto NewTy = Field.Ty->rewrite(Fn, Recursive);
if (NewTy != Field.Ty) {
Changed = true;
}
auto NewRestTy = Field.RestTy->rewrite(Fn, Recursive);
if (NewRestTy != Field.RestTy) {
Changed = true;
}
return Changed ? new Type(TField(Field.Name, NewTy, NewRestTy)) : Ty2;
}
case TypeKind::Present:
{
auto Present = Ty2->asPresent();
auto NewTy = Present.Ty->rewrite(Fn, Recursive);
if (NewTy == Present.Ty) {
return Ty2;
}
return new Type(TPresent(NewTy));
}
}
ZEN_UNREACHABLE
}
Type* Type::substitute(const TVSub &Sub) {
return rewrite([&](auto Ty) {
if (Ty->isVar()) {
auto Match = Sub.find(Ty);
return Match != Sub.end() ? Match->second->substitute(Sub) : Ty;
}
return Ty;
}, false);
}
Type* Type::resolve(const TypeIndex& Index) const noexcept {
switch (Index.Kind) {
case TypeIndexKind::PresentType:
return this->asPresent().Ty;
case TypeIndexKind::AppOpType:
return this->asApp().Op;
case TypeIndexKind::AppArgType:
return this->asApp().Arg;
case TypeIndexKind::TupleElement:
return this->asTuple().ElementTypes[Index.I];
case TypeIndexKind::ArrowParamType:
return this->asArrow().ParamType;
case TypeIndexKind::ArrowReturnType:
return this->asArrow().ReturnType;
case TypeIndexKind::FieldType:
return this->asField().Ty;
case TypeIndexKind::FieldRestType:
return this->asField().RestTy;
case TypeIndexKind::End:
ZEN_UNREACHABLE
}
ZEN_UNREACHABLE
}
TVSet Type::getTypeVars() {
TVSet Out;
std::function<void(Type*)> visit = [&](Type* Ty) {
if (Ty->isVar()) {
Out.emplace(Ty);
return;
}
Ty->visitEachChild(visit);
};
visit(this);
return Out;
}
TypeIterator Type::begin() {
return TypeIterator { this, getStartIndex() };
}
TypeIterator Type::end() {
return TypeIterator { this, getEndIndex() };
}
TypeIndex Type::getStartIndex() const {
switch (Kind) {
case TypeKind::Arrow:
return TypeIndex::forArrowParamType();
case TypeKind::Tuple:
{
if (asTuple().ElementTypes.empty()) {
return TypeIndex(TypeIndexKind::End); return TypeIndex(TypeIndexKind::End);
}
return TypeIndex::forTupleElement(0);
} }
case TypeKind::Field:
return TypeIndex::forFieldType();
default:
return TypeIndex(TypeIndexKind::End);
} }
}
TypeIndex Type::getEndIndex() const { TypeIndex Type::getEndIndex() const {
return TypeIndex(TypeIndexKind::End); return TypeIndex(TypeIndexKind::End);
} }
bool Type::hasTypeVar(Type* TV) const { bool Type::hasTypeVar(Type* TV) const {
switch (Kind) { switch (Kind) {
case TypeKind::Var: case TypeKind::Var:
return Var.Id == TV->asVar().Id; return Var.Id == TV->asVar().Id;
case TypeKind::Con: case TypeKind::Con:
case TypeKind::Absent: case TypeKind::Absent:
case TypeKind::Nil: case TypeKind::Nil:
return false; return false;
case TypeKind::App: case TypeKind::App:
return App.Op->hasTypeVar(TV) || App.Arg->hasTypeVar(TV); return App.Op->hasTypeVar(TV) || App.Arg->hasTypeVar(TV);
case TypeKind::Tuple: case TypeKind::Tuple:
for (auto Ty: Tuple.ElementTypes) { for (auto Ty: Tuple.ElementTypes) {
if (Ty->hasTypeVar(TV)) { if (Ty->hasTypeVar(TV)) {
return true; return true;
}
} }
return false; }
case TypeKind::Field: return false;
return Field.Ty->hasTypeVar(TV) || Field.RestTy->hasTypeVar(TV); case TypeKind::Field:
case TypeKind::Arrow: return Field.Ty->hasTypeVar(TV) || Field.RestTy->hasTypeVar(TV);
return Arrow.ParamType->hasTypeVar(TV) || Arrow.ReturnType->hasTypeVar(TV); case TypeKind::Arrow:
case TypeKind::Present: return Arrow.ParamType->hasTypeVar(TV) || Arrow.ReturnType->hasTypeVar(TV);
return Present.Ty->hasTypeVar(TV); case TypeKind::Present:
} return Present.Ty->hasTypeVar(TV);
ZEN_UNREACHABLE
} }
ZEN_UNREACHABLE
}
} }