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 {
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 {
std::string describe(const Type* Ty); // For debugging only
std::string describe(const Type* Ty); // For debugging only
enum class SymKind {
Type,
Var,
};
enum class SymKind {
Type,
Var,
};
class DiagnosticEngine;
class DiagnosticEngine;
class Constraint;
class Constraint;
using ConstraintSet = std::vector<Constraint*>;
using ConstraintSet = std::vector<Constraint*>;
enum class SchemeKind : unsigned char {
Forall,
};
enum class SchemeKind : unsigned char {
Forall,
};
class Scheme {
class Scheme {
const SchemeKind Kind;
const SchemeKind Kind;
protected:
protected:
inline Scheme(SchemeKind Kind):
Kind(Kind) {}
inline Scheme(SchemeKind Kind):
Kind(Kind) {}
public:
public:
inline SchemeKind getKind() const noexcept {
return Kind;
inline SchemeKind getKind() const noexcept {
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;
ConstraintSet* Constraints;
class Type* Type;
enum class ConstraintKind {
Equal,
Field,
Many,
Empty,
};
inline Forall(class Type* Type):
Scheme(SchemeKind::Forall), TVs(new TVSet), Constraints(new ConstraintSet), Type(Type) {}
class Constraint {
inline Forall(
TVSet* TVs,
ConstraintSet* Constraints,
class Type* Type
): Scheme(SchemeKind::Forall),
TVs(TVs),
Constraints(Constraints),
Type(Type) {}
const ConstraintKind Kind;
static bool classof(const Scheme* Scm) {
return Scm->getKind() == SchemeKind::Forall;
}
public:
};
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) {
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 CEqual : public Constraint {
public:
};
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 {
return Kind;
}
class CMany : public Constraint {
public:
Constraint* substitute(const TVSub& Sub);
ConstraintSet& Elements;
virtual ~Constraint() {}
inline CMany(ConstraintSet& Elements):
Constraint(ConstraintKind::Many), Elements(Elements) {}
};
};
class CEqual : public Constraint {
public:
class CEmpty : public Constraint {
public:
Type* Left;
Type* Right;
Node* Source;
inline CEmpty():
Constraint(ConstraintKind::Empty) {}
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 {
public:
class InferContext {
public:
Type* TupleTy;
size_t I;
Type* FieldTy;
Node* Source;
/**
* A heap-allocated list of type variables that eventually will become part of a Forall scheme.
*/
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 {
public:
Type* ReturnType = nullptr;
ConstraintSet& Elements;
InferContext* Parent = nullptr;
inline CMany(ConstraintSet& Elements):
Constraint(ConstraintKind::Many), Elements(Elements) {}
};
};
class Checker {
class CEmpty : public Constraint {
public:
friend class Unifier;
friend class UnificationFrame;
inline CEmpty():
Constraint(ConstraintKind::Empty) {}
const LanguageConfig& Config;
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 {
public:
Graph<Node*> RefGraph;
/**
* A heap-allocated list of type variables that eventually will become part of a Forall scheme.
*/
TVSet* TVs;
std::unordered_map<ByteString, std::vector<InstanceDeclaration*>> InstanceMap;
/**
* A heap-allocated list of constraints that eventually will become part of a Forall scheme.
*/
ConstraintSet* Constraints;
/// Inference context management
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;
friend class UnificationFrame;
/// Type inference
const LanguageConfig& Config;
DiagnosticEngine& DE;
void forwardDeclare(Node* Node);
void forwardDeclareFunctionDeclaration(LetDeclaration* N, TVSet* TVs, ConstraintSet* Constraints);
size_t NextConTypeId = 0;
size_t NextTypeVarId = 0;
Type* inferExpression(Expression* Expression);
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;
Type* ListType;
Type* IntType;
Type* StringType;
Type* UnitType;
void infer(Node* node);
void inferFunctionDeclaration(LetDeclaration* N);
void inferConstraintExpression(ConstraintExpression* C);
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);
void popContext();
/**
* 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 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
* program will abort.
*/
Type* getReturnType();
/**
* The queue that is used during solving to store any unsolved constraints.
*/
std::deque<class Constraint*> Queue;
/// 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 forwardDeclareFunctionDeclaration(LetDeclaration* N, TVSet* TVs, ConstraintSet* Constraints);
void solve(Constraint* Constraint);
Type* inferExpression(Expression* Expression);
Type* inferTypeExpression(TypeExpression* TE, bool AutoVars = true);
Type* inferLiteral(Literal* Lit);
Type* inferPattern(Pattern* Pattern, ConstraintSet* Constraints = new ConstraintSet, TVSet* TVs = new TVSet);
/// Helpers
void infer(Node* node);
void inferFunctionDeclaration(LetDeclaration* N);
void inferConstraintExpression(ConstraintExpression* C);
void populate(SourceFile* SF);
/// 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* createTypeVar();
Type* createRigidVar(ByteString Name);
InferContext* createInferContext(
InferContext* Parent = nullptr,
TVSet* TVs = new TVSet,
ConstraintSet* Constraints = new ConstraintSet
);
Type* instantiate(Scheme* S, Node* Source);
/// Environment manipulation
void initialize(Node* N);
Scheme* lookup(ByteString Name, SymKind Kind);
public:
/**
* 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);
Checker(const LanguageConfig& Config, DiagnosticEngine& DE);
void addBinding(ByteString Name, Scheme* Scm, SymKind Kind);
/**
* \internal
*/
Type* solveType(Type* Ty);
/// Constraint solving
void check(SourceFile* SF);
/**
* The queue that is used during solving to store any unsolved constraints.
*/
std::deque<class Constraint*> Queue;
inline Type* getBoolType() const {
return BoolType;
}
/**
* 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);
inline Type* getStringType() const {
return StringType;
}
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 {
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;
}
class LanguageConfig {
enum ConfigFlags {
ConfigFlags_TypeVarsRequireForall = 1 << 0,
};
template<typename D, typename B>
D* cast(B* base) {
ZEN_ASSERT(D::classof(base));
return static_cast<D*>(base);
unsigned Flags = 0;
public:
void setTypeVarsRequireForall(bool Enable) {
if (Enable) {
Flags |= ConfigFlags_TypeVarsRequireForall;
} else {
Flags |= ~ConfigFlags_TypeVarsRequireForall;
}
}
template<typename D, typename B>
const D* cast(const B* base) {
ZEN_ASSERT(D::classof(base));
return static_cast<const D*>(base);
bool typeVarsRequireForall() const noexcept {
return Flags & ConfigFlags_TypeVarsRequireForall;
}
template<typename D, typename T>
bool isa(const T* value) {
return D::classof(value);
bool hasImmediateDiagnostics() const noexcept {
// TODO make this a configuration flag
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 {
class Node;
class Type;
class TypeclassSignature;
class Diagnostic;
class Node;
class Type;
class TypeclassSignature;
class Diagnostic;
enum class Color {
None,
Black,
White,
Red,
Yellow,
Green,
Blue,
Cyan,
Magenta,
};
enum class Color {
None,
Black,
White,
Red,
Yellow,
Green,
Blue,
Cyan,
Magenta,
};
enum StyleFlags : unsigned {
StyleFlags_None = 0,
StyleFlags_Bold = 1 << 0,
StyleFlags_Underline = 1 << 1,
StyleFlags_Italic = 1 << 2,
};
enum StyleFlags : unsigned {
StyleFlags_None = 0,
StyleFlags_Bold = 1 << 0,
StyleFlags_Underline = 1 << 1,
StyleFlags_Italic = 1 << 2,
};
class Style {
class Style {
unsigned Flags = StyleFlags_None;
unsigned Flags = StyleFlags_None;
Color FgColor = Color::None;
Color BgColor = Color::None;
Color FgColor = Color::None;
Color BgColor = Color::None;
public:
public:
Color getForegroundColor() const noexcept {
return FgColor;
Color getForegroundColor() const noexcept {
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 {
return BgColor;
void setItalic(bool Enable) noexcept {
if (Enable) {
Flags |= StyleFlags_Italic;
} else {
Flags &= ~StyleFlags_Italic;
}
}
void setForegroundColor(Color NewColor) noexcept {
FgColor = NewColor;
void setBold(bool Enable) noexcept {
if (Enable) {
Flags |= StyleFlags_Bold;
} else {
Flags &= ~StyleFlags_Bold;
}
}
void setBackgroundColor(Color NewColor) noexcept {
BgColor = NewColor;
}
void reset() noexcept {
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 {
FgColor = Color::None;
}
std::ostream& Out;
void clearBackgroundColor() noexcept {
BgColor = Color::None;
}
Style ActiveStyle;
bool isUnderline() const noexcept {
return Flags & StyleFlags_Underline;
}
void setForegroundColor(Color C);
void setBackgroundColor(Color C);
void applyStyles();
bool isItalic() const noexcept {
return Flags & StyleFlags_Italic;
}
void setBold(bool Enable);
void setItalic(bool Enable);
void setUnderline(bool Enable);
void resetStyles();
bool isBold() const noexcept {
return Flags & StyleFlags_Bold;
}
void writeGutter(
std::size_t GutterWidth,
std::string Text
);
void setUnderline(bool Enable) noexcept {
if (Enable) {
Flags |= StyleFlags_Underline;
} else {
Flags &= ~StyleFlags_Underline;
}
}
void writeHighlight(
std::size_t GutterWidth,
TextRange Range,
Color HighlightColor,
std::size_t Line,
std::size_t LineLength
);
void setItalic(bool Enable) noexcept {
if (Enable) {
Flags |= StyleFlags_Italic;
} else {
Flags &= ~StyleFlags_Italic;
}
}
void writeExcerpt(
const TextFile& File,
TextRange ToPrint,
TextRange ToHighlight,
Color HighlightColor
);
void setBold(bool Enable) noexcept {
if (Enable) {
Flags |= StyleFlags_Bold;
} else {
Flags &= ~StyleFlags_Bold;
}
}
void writeNode(const Node* N);
void reset() noexcept {
FgColor = Color::None;
BgColor = Color::None;
Flags = 0;
}
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);
/**
* Prints any diagnostic message that was added to it to the console.
*/
class ConsolePrinter {
public:
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 setBackgroundColor(Color C);
void applyStyles();
void writeDiagnostic(const Diagnostic& D);
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 {
class ConsolePrinter;
class Diagnostic;
class TypeclassSignature;
class Type;
class Node;
class ConsolePrinter;
class Diagnostic;
class TypeclassSignature;
class Type;
class Node;
class DiagnosticEngine {
protected:
class DiagnosticEngine {
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 {
return HasError;
}
inline bool hasError() const noexcept {
return HasError;
}
template<typename D, typename ...Ts>
void add(Ts&&... Args) {
// if (FailOnError) {
// ZEN_PANIC("An error diagnostic caused the program to abort.");
// }
HasError = true;
addDiagnostic(new D { std::forward<Ts>(Args)... });
}
template<typename D, typename ...Ts>
void add(Ts&&... Args) {
// if (FailOnError) {
// ZEN_PANIC("An error diagnostic caused the program to abort.");
// }
HasError = true;
addDiagnostic(new D { std::forward<Ts>(Args)... });
}
virtual ~DiagnosticEngine() {}
virtual ~DiagnosticEngine() {}
};
};
/**
* Keeps diagnostics alive in-memory until a seperate procedure processes them.
*/
class DiagnosticStore : public DiagnosticEngine {
public:
/**
* Keeps diagnostics alive in-memory until a seperate procedure processes them.
*/
class DiagnosticStore : public DiagnosticEngine {
public:
std::vector<Diagnostic*> Diagnostics;
std::vector<Diagnostic*> Diagnostics;
void addDiagnostic(Diagnostic* Diagnostic) {
Diagnostics.push_back(Diagnostic);
}
void addDiagnostic(Diagnostic* Diagnostic) {
Diagnostics.push_back(Diagnostic);
}
void clear() {
Diagnostics.clear();
}
void clear() {
Diagnostics.clear();
}
void sort();
void sort();
std::size_t countDiagnostics() const noexcept {
return Diagnostics.size();
}
std::size_t countDiagnostics() const noexcept {
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 {
enum class DiagnosticKind : unsigned char {
BindingNotFound,
FieldNotFound,
InstanceNotFound,
InvalidTypeToTypeclass,
NotATuple,
TupleIndexOutOfRange,
TypeclassMissing,
UnexpectedString,
UnexpectedToken,
UnificationError,
};
enum class DiagnosticKind : unsigned char {
BindingNotFound,
FieldNotFound,
InstanceNotFound,
InvalidTypeToTypeclass,
NotATuple,
TupleIndexOutOfRange,
TypeclassMissing,
UnexpectedString,
UnexpectedToken,
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 {
return Kind;
}
inline DiagnosticKind getKind() const noexcept {
return Kind;
}
virtual Node* getNode() const {
return nullptr;
}
virtual Node* getNode() const {
return nullptr;
}
virtual unsigned getCode() const noexcept = 0;
virtual unsigned getCode() const noexcept = 0;
virtual ~Diagnostic() {}
virtual ~Diagnostic() {}
};
};
class UnexpectedStringDiagnostic : public Diagnostic {
public:
class UnexpectedStringDiagnostic : public Diagnostic {
public:
TextFile& File;
TextLoc Location;
String Actual;
TextFile& File;
TextLoc Location;
String Actual;
inline UnexpectedStringDiagnostic(TextFile& File, TextLoc Location, String Actual):
Diagnostic(DiagnosticKind::UnexpectedString), File(File), Location(Location), Actual(Actual) {}
inline UnexpectedStringDiagnostic(TextFile& File, TextLoc Location, String Actual):
Diagnostic(DiagnosticKind::UnexpectedString), File(File), Location(Location), Actual(Actual) {}
unsigned getCode() const noexcept override {
return 1001;
}
unsigned getCode() const noexcept override {
return 1001;
}
};
};
class UnexpectedTokenDiagnostic : public Diagnostic {
public:
class UnexpectedTokenDiagnostic : public Diagnostic {
public:
TextFile& File;
Token* Actual;
std::vector<NodeKind> Expected;
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) {}
inline UnexpectedTokenDiagnostic(TextFile& File, Token* Actual, std::vector<NodeKind> Expected):
Diagnostic(DiagnosticKind::UnexpectedToken), File(File), Actual(Actual), Expected(Expected) {}
unsigned getCode() const noexcept override {
return 1101;
}
unsigned getCode() const noexcept override {
return 1101;
}
};
};
class BindingNotFoundDiagnostic : public Diagnostic {
public:
class BindingNotFoundDiagnostic : public Diagnostic {
public:
ByteString Name;
Node* Initiator;
ByteString Name;
Node* Initiator;
inline BindingNotFoundDiagnostic(ByteString Name, Node* Initiator):
Diagnostic(DiagnosticKind::BindingNotFound), Name(Name), Initiator(Initiator) {}
inline BindingNotFoundDiagnostic(ByteString Name, Node* Initiator):
Diagnostic(DiagnosticKind::BindingNotFound), Name(Name), Initiator(Initiator) {}
inline Node* getNode() const override {
return Initiator;
}
inline Node* getNode() const override {
return Initiator;
}
unsigned getCode() const noexcept override {
return 2005;
}
unsigned getCode() const noexcept override {
return 2005;
}
};
};
class UnificationErrorDiagnostic : public Diagnostic {
public:
class UnificationErrorDiagnostic : public Diagnostic {
public:
Type* OrigLeft;
Type* OrigRight;
TypePath LeftPath;
TypePath RightPath;
Node* Source;
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) {}
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) {}
inline Type* getLeft() const {
return OrigLeft->resolve(LeftPath);
}
inline Type* getLeft() const {
return OrigLeft->resolve(LeftPath);
}
inline Type* getRight() const {
return OrigRight->resolve(RightPath);
}
inline Type* getRight() const {
return OrigRight->resolve(RightPath);
}
inline Node* getNode() const override {
return Source;
}
inline Node* getNode() const override {
return Source;
}
unsigned getCode() const noexcept override {
return 2010;
}
unsigned getCode() const noexcept override {
return 2010;
}
};
};
class TypeclassMissingDiagnostic : public Diagnostic {
public:
class TypeclassMissingDiagnostic : public Diagnostic {
public:
TypeclassSignature Sig;
Node* Decl;
TypeclassSignature Sig;
Node* Decl;
inline TypeclassMissingDiagnostic(TypeclassSignature Sig, Node* Decl):
Diagnostic(DiagnosticKind::TypeclassMissing), Sig(Sig), Decl(Decl) {}
inline TypeclassMissingDiagnostic(TypeclassSignature Sig, Node* Decl):
Diagnostic(DiagnosticKind::TypeclassMissing), Sig(Sig), Decl(Decl) {}
inline Node* getNode() const override {
return Decl;
}
inline Node* getNode() const override {
return Decl;
}
unsigned getCode() const noexcept override {
return 2201;
}
unsigned getCode() const noexcept override {
return 2201;
}
};
};
class InstanceNotFoundDiagnostic : public Diagnostic {
public:
class InstanceNotFoundDiagnostic : public Diagnostic {
public:
ByteString TypeclassName;
Type* Ty;
Node* Source;
ByteString TypeclassName;
Type* Ty;
Node* Source;
inline InstanceNotFoundDiagnostic(ByteString TypeclassName, Type* Ty, Node* Source):
Diagnostic(DiagnosticKind::InstanceNotFound), TypeclassName(TypeclassName), Ty(Ty), Source(Source) {}
inline InstanceNotFoundDiagnostic(ByteString TypeclassName, Type* Ty, Node* Source):
Diagnostic(DiagnosticKind::InstanceNotFound), TypeclassName(TypeclassName), Ty(Ty), Source(Source) {}
inline Node* getNode() const override {
return Source;
}
inline Node* getNode() const override {
return Source;
}
unsigned getCode() const noexcept override {
return 2251;
}
unsigned getCode() const noexcept override {
return 2251;
}
};
};
class TupleIndexOutOfRangeDiagnostic : public Diagnostic {
public:
class TupleIndexOutOfRangeDiagnostic : public Diagnostic {
public:
Type* Tuple;
std::size_t I;
Node* Source;
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) {}
inline TupleIndexOutOfRangeDiagnostic(Type* Tuple, std::size_t I, Node* Source):
Diagnostic(DiagnosticKind::TupleIndexOutOfRange), Tuple(Tuple), I(I), Source(Source) {}
inline Node * getNode() const override {
return Source;
}
inline Node * getNode() const override {
return Source;
}
unsigned getCode() const noexcept override {
return 2015;
}
unsigned getCode() const noexcept override {
return 2015;
}
};
};
class InvalidTypeToTypeclassDiagnostic : public Diagnostic {
public:
class InvalidTypeToTypeclassDiagnostic : public Diagnostic {
public:
Type* Actual;
std::vector<TypeclassId> Classes;
Node* Source;
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) {}
inline InvalidTypeToTypeclassDiagnostic(Type* Actual, std::vector<TypeclassId> Classes, Node* Source):
Diagnostic(DiagnosticKind::InvalidTypeToTypeclass), Actual(Actual), Classes(Classes), Source(Source) {}
inline Node* getNode() const override {
return Source;
}
inline Node* getNode() const override {
return Source;
}
unsigned getCode() const noexcept override {
return 2060;
}
unsigned getCode() const noexcept override {
return 2060;
}
};
};
class FieldNotFoundDiagnostic : public Diagnostic {
public:
class FieldNotFoundDiagnostic : public Diagnostic {
public:
ByteString Name;
Type* Ty;
TypePath Path;
Node* Source;
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) {}
inline FieldNotFoundDiagnostic(ByteString Name, Type* Ty, TypePath Path, Node* Source):
Diagnostic(DiagnosticKind::FieldNotFound), Name(Name), Ty(Ty), Path(Path), Source(Source) {}
unsigned getCode() const noexcept override {
return 2017;
}
unsigned getCode() const noexcept override {
return 2017;
}
};
};
class NotATupleDiagnostic : public Diagnostic {
public:
class NotATupleDiagnostic : public Diagnostic {
public:
Type* Ty;
Node* Source;
Type* Ty;
Node* Source;
inline NotATupleDiagnostic(Type* Ty, Node* Source):
Diagnostic(DiagnosticKind::NotATuple), Ty(Ty), Source(Source) {}
inline NotATupleDiagnostic(Type* Ty, Node* Source):
Diagnostic(DiagnosticKind::NotATuple), Ty(Ty), Source(Source) {}
inline Node * getNode() const override {
return Source;
}
inline Node * getNode() const override {
return Source;
}
unsigned getCode() const noexcept override {
return 2016;
}
unsigned getCode() const noexcept override {
return 2016;
}
};
};
}

View file

@ -9,179 +9,180 @@
namespace bolt {
enum class ValueKind {
Empty,
String,
Integer,
Tuple,
SourceFunction,
NativeFunction,
enum class ValueKind {
Empty,
String,
Integer,
Tuple,
SourceFunction,
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 {
ByteString S;
Integer I;
LetDeclaration* D;
NativeFunction F;
Tuple T;
};
Value(LetDeclaration* D):
Kind(ValueKind::SourceFunction), D(D) {}
public:
Value(NativeFunction F):
Kind(ValueKind::NativeFunction), F(F) {}
Value():
Kind(ValueKind::Empty) {}
Value(std::vector<Value> T):
Kind(ValueKind::Tuple), T(T) {}
Value(ByteString S):
Kind(ValueKind::String), S(S) {}
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;
Value(const Value& V):
Kind(V.Kind) {
switch (Kind) {
case ValueKind::String:
new (&S) ByteString(Other.S);
new (&S) ByteString(V.S);
break;
case ValueKind::Integer:
new (&I) Integer(Other.I);
new (&I) Integer(V.I);
break;
case ValueKind::Tuple:
new (&I) Tuple(Other.T);
new (&I) Tuple(V.T);
break;
case ValueKind::SourceFunction:
new (&D) LetDeclaration*(Other.D);
new (&D) LetDeclaration*(V.D);
break;
case ValueKind::NativeFunction:
new (&F) NativeFunction(Other.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();
new (&F) NativeFunction(V.F);
break;
case ValueKind::Empty:
break;
}
}
};
class Env {
std::unordered_map<ByteString, Value> Bindings;
public:
void add(const ByteString& Name, Value V) {
Bindings.emplace(Name, V);
Value& operator=(const Value& Other) noexcept {
Kind = Other.Kind;
switch (Kind) {
case ValueKind::String:
new (&S) ByteString(Other.S);
break;
case ValueKind::Integer:
new (&I) Integer(Other.I);
break;
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) {
auto Match = Bindings.find(Name);
ZEN_ASSERT(Match != Bindings.end());
return Match->second;
// 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;
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 {
using Integer = long long;
using Integer = long long;
}

View file

@ -9,144 +9,144 @@
namespace bolt {
class DiagnosticEngine;
class Scanner;
class DiagnosticEngine;
class Scanner;
enum OperatorFlags {
OperatorFlags_Prefix = 1,
OperatorFlags_Suffix = 2,
OperatorFlags_InfixL = 4,
OperatorFlags_InfixR = 8,
};
enum OperatorFlags {
OperatorFlags_Prefix = 1,
OperatorFlags_Suffix = 2,
OperatorFlags_InfixL = 4,
OperatorFlags_InfixR = 8,
};
struct OperatorInfo {
struct OperatorInfo {
int Precedence;
unsigned Flags;
int Precedence;
unsigned Flags;
inline bool isPrefix() const noexcept {
return Flags & OperatorFlags_Prefix;
}
inline bool isPrefix() const noexcept {
return Flags & OperatorFlags_Prefix;
}
inline bool isSuffix() const noexcept {
return Flags & OperatorFlags_Suffix;
}
inline bool isSuffix() const noexcept {
return Flags & OperatorFlags_Suffix;
}
inline bool isInfix() const noexcept {
return Flags & (OperatorFlags_InfixL | OperatorFlags_InfixR);
}
inline bool isInfix() const noexcept {
return Flags & (OperatorFlags_InfixL | OperatorFlags_InfixR);
}
inline bool isRightAssoc() const noexcept {
return Flags & OperatorFlags_InfixR;
}
inline bool isRightAssoc() const noexcept {
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 isPrefix(Token* T);
bool isSuffix(Token* T);
bool isInfix(Token* T);
bool isPrefix(Token* T);
bool isSuffix(Token* T);
};
};
class Parser {
class Parser {
TextFile& File;
DiagnosticEngine& DE;
TextFile& File;
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::optional<std::vector<std::tuple<RecordPatternField*, Comma*>>> parseRecordPatternFields();
std::vector<RecordDeclarationField*> parseRecordDeclarationFields();
std::optional<std::vector<std::tuple<RecordPatternField*, Comma*>>> parseRecordPatternFields();
template<typename T>
T* expectToken() {
return static_cast<T*>(expectToken(getNodeType<T>()));
}
template<typename T>
T* expectToken() {
return static_cast<T*>(expectToken(getNodeType<T>()));
}
Expression* parseInfixOperatorAfterExpression(Expression* LHS, int MinPrecedence);
Expression* parseInfixOperatorAfterExpression(Expression* LHS, int MinPrecedence);
MatchExpression* parseMatchExpression();
Expression* parseMemberExpression();
RecordExpression* parseRecordExpression();
Expression* parsePrimitiveExpression();
MatchExpression* parseMatchExpression();
Expression* parseMemberExpression();
RecordExpression* parseRecordExpression();
Expression* parsePrimitiveExpression();
ConstraintExpression* parseConstraintExpression();
ConstraintExpression* parseConstraintExpression();
TypeExpression* parseAppTypeExpression();
TypeExpression* parsePrimitiveTypeExpression();
TypeExpression* parseQualifiedTypeExpression();
TypeExpression* parseArrowTypeExpression();
VarTypeExpression* parseVarTypeExpression();
ReferenceTypeExpression* parseReferenceTypeExpression();
TypeExpression* parseAppTypeExpression();
TypeExpression* parsePrimitiveTypeExpression();
TypeExpression* parseQualifiedTypeExpression();
TypeExpression* parseArrowTypeExpression();
VarTypeExpression* parseVarTypeExpression();
ReferenceTypeExpression* parseReferenceTypeExpression();
std::vector<Annotation*> parseAnnotations();
std::vector<Annotation*> parseAnnotations();
void checkLineFoldEnd();
void skipPastLineFoldEnd();
void skipToRBrace();
void checkLineFoldEnd();
void skipPastLineFoldEnd();
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();
Pattern* parsePrimitivePattern(bool IsNarrow);
Pattern* parseWidePattern();
Pattern* parseNarrowPattern();
ListPattern* parseListPattern();
Pattern* parsePrimitivePattern(bool IsNarrow);
Pattern* parseWidePattern();
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 {
class Token;
class DiagnosticEngine;
class Token;
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 {
return CurrLoc;
inline TextLoc getCurrentLoc() const {
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() {
auto Chr = Chars.get();
if (Chr == '\n') {
CurrLoc.Line += 1;
CurrLoc.Column = 1;
} else {
CurrLoc.Column += 1;
}
return Chr;
}
inline Char peekChar(std::size_t Offset = 0) {
return Chars.peek(Offset);
}
inline Char peekChar(std::size_t Offset = 0) {
return Chars.peek(Offset);
}
std::string scanIdentifier();
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 {
Block,
LineFold,
Fallthrough,
};
class Punctuator : public BufferedStream<Token*> {
class Punctuator : public BufferedStream<Token*> {
Stream<Token*>& Tokens;
Stream<Token*>& Tokens;
std::stack<FrameType> Frames;
std::stack<TextLoc> Locations;
std::stack<FrameType> Frames;
std::stack<TextLoc> Locations;
protected:
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 {
template<typename T>
class Stream {
public:
template<typename T>
class Stream {
public:
virtual T get() = 0;
virtual T peek(std::size_t Offset = 0) = 0;
virtual T get() = 0;
virtual T peek(std::size_t Offset = 0) = 0;
virtual ~Stream() {}
virtual ~Stream() {}
};
};
template<typename ContainerT, typename T = typename ContainerT::value_type>
class VectorStream : public Stream<T> {
public:
template<typename ContainerT, typename T = typename ContainerT::value_type>
class VectorStream : public Stream<T> {
public:
using value_type = T;
using value_type = T;
ContainerT& Data;
value_type Sentry;
std::size_t Offset;
ContainerT& Data;
value_type Sentry;
std::size_t Offset;
VectorStream(ContainerT& Data, value_type Sentry, std::size_t Offset = 0):
Data(Data), Sentry(Sentry), Offset(Offset) {}
VectorStream(ContainerT& Data, value_type Sentry, std::size_t Offset = 0):
Data(Data), Sentry(Sentry), Offset(Offset) {}
value_type get() override {
return Offset < Data.size() ? Data[Offset++] : Sentry;
value_type get() override {
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 {
auto I = Offset + Offset2;
return I < Data.size() ? Data[I] : Sentry;
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];
}
};
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 {
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 {
template<typename V>
class Graph {
template<typename V>
class Graph {
std::unordered_set<V> Vertices;
std::unordered_multimap<V, V> Edges;
std::unordered_set<V> Vertices;
std::unordered_multimap<V, V> Edges;
public:
public:
void addVertex(V Vert) {
Vertices.emplace(Vert);
}
void addVertex(V Vert) {
Vertices.emplace(Vert);
}
void addEdge(V A, V B) {
Vertices.emplace(A);
Vertices.emplace(B);
Edges.emplace(A, B);
}
void addEdge(V A, V B) {
Vertices.emplace(A);
Vertices.emplace(B);
Edges.emplace(A, B);
}
std::size_t countVertices() const {
return Vertices.size();
}
std::size_t countVertices() const {
return Vertices.size();
}
bool hasVertex(const V& Vert) const {
return Vertices.count(Vert);
}
bool hasVertex(const V& Vert) const {
return Vertices.count(Vert);
}
bool hasEdge(const V& From) const {
return Edges.count(From);
}
bool hasEdge(const V& From) const {
return Edges.count(From);
}
bool hasEdge(const V& From, const V& To) const {
for (auto X: Edges.equal_range(From)) {
if (X == To) {
return true;
}
bool hasEdge(const V& From, const V& To) const {
for (auto X: Edges.equal_range(From)) {
if (X == To) {
return true;
}
}
}
auto getTargetVertices(const V& From) const {
return zen::make_iterator_range(Edges.equal_range(From)).map_second();
}
auto getTargetVertices(const V& From) const {
return zen::make_iterator_range(Edges.equal_range(From)).map_second();
}
auto getVertices() const {
return zen::make_iterator_range(Vertices);
}
auto getVertices() const {
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:
struct TarjanVertexData {
std::optional<std::size_t> Index;
std::size_t LowLink;
bool OnStack = false;
};
const Graph& G;
std::unordered_map<V, TarjanVertexData> Map;
std::size_t Index = 0;
std::stack<V> Stack;
class TarjanSolver {
public:
TarjanVertexData& getData(V From) {
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;
std::unordered_map<V, TarjanVertexData> Map;
std::size_t Index = 0;
std::stack<V> Stack;
TarjanVertexData& getData(V From) {
return Map.emplace(From, TarjanVertexData {}).first->second;
}
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);
}
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:
}
std::vector<std::vector<V>> strongconnect() const {
TarjanSolver S { *this };
S.solve();
return S.SCCs;
public:
TarjanSolver(const Graph& G):
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 {
Diagnostic::Diagnostic(DiagnosticKind Kind):
Kind(Kind) {}
Diagnostic::Diagnostic(DiagnosticKind Kind):
Kind(Kind) {}
bool sourceLocLessThan(const Diagnostic* L, const Diagnostic* R) {
auto N1 = L->getNode();
auto N2 = R->getNode();
if (N1 == nullptr && N2 == nullptr) {
return false;
}
if (N1 == nullptr) {
return true;
}
if (N2 == nullptr) {
return false;
}
return N1->getStartLine() < N2->getStartLine() || N1->getStartColumn() < N2->getStartColumn();
};
void DiagnosticStore::sort() {
std::sort(Diagnostics.begin(), Diagnostics.end(), sourceLocLessThan);
bool sourceLocLessThan(const Diagnostic* L, const Diagnostic* R) {
auto N1 = L->getNode();
auto N2 = R->getNode();
if (N1 == nullptr && N2 == nullptr) {
return false;
}
DiagnosticStore::~DiagnosticStore() {
for (auto D: Diagnostics) {
delete D;
}
if (N1 == nullptr) {
return true;
}
if (N2 == nullptr) {
return false;
}
return N1->getStartLine() < N2->getStartLine() || N1->getStartColumn() < N2->getStartColumn();
};
ConsoleDiagnostics::ConsoleDiagnostics(ConsolePrinter& P):
ThePrinter(P) {}
void DiagnosticStore::sort() {
std::sort(Diagnostics.begin(), Diagnostics.end(), sourceLocLessThan);
}
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.
DiagnosticStore::~DiagnosticStore() {
for (auto D: Diagnostics) {
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 {
Value Evaluator::evaluateExpression(Expression* X, Env& Env) {
switch (X->getKind()) {
case NodeKind::ReferenceExpression:
{
auto RE = static_cast<ReferenceExpression*>(X);
return Env.lookup(getCanonicalText(RE->Name));
// auto Decl = RE->getScope()->lookup(RE->getSymbolPath());
// ZEN_ASSERT(Decl && Decl->getKind() == NodeKind::FunctionDeclaration);
// 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
Value Evaluator::evaluateExpression(Expression* X, Env& Env) {
switch (X->getKind()) {
case NodeKind::ReferenceExpression:
{
auto RE = static_cast<ReferenceExpression*>(X);
return Env.lookup(getCanonicalText(RE->Name));
// auto Decl = RE->getScope()->lookup(RE->getSymbolPath());
// ZEN_ASSERT(Decl && Decl->getKind() == NodeKind::FunctionDeclaration);
// return static_cast<FunctionDeclaration*>(Decl);
}
}
void Evaluator::assignPattern(Pattern* P, Value& V, Env& E) {
switch (P->getKind()) {
case NodeKind::BindPattern:
{
auto BP = static_cast<BindPattern*>(P);
E.add(getCanonicalText(BP->Name), V);
break;
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
}
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);
}
switch (Fn->Body->getKind()) {
case NodeKind::LetExprBody:
return evaluateExpression(static_cast<LetExprBody*>(Fn->Body)->Expression, NewEnv);
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));
}
case ValueKind::NativeFunction:
{
auto Fn = Op.getBinding();
return Fn(Args);
}
default:
ZEN_UNREACHABLE
return apply(Op, Args);
}
default:
ZEN_UNREACHABLE
}
}
void Evaluator::evaluate(Node* N, Env& E) {
switch (N->getKind()) {
case NodeKind::SourceFile:
{
auto SF = static_cast<SourceFile*>(N);
for (auto Element: SF->Elements) {
evaluate(Element, E);
}
break;
void Evaluator::assignPattern(Pattern* P, Value& V, Env& E) {
switch (P->getKind()) {
case NodeKind::BindPattern:
{
auto BP = static_cast<BindPattern*>(P);
E.add(getCanonicalText(BP->Name), V);
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:
{
auto ES = static_cast<ExpressionStatement*>(N);
evaluateExpression(ES->Expression, E);
break;
switch (Fn->Body->getKind()) {
case NodeKind::LetExprBody:
return evaluateExpression(static_cast<LetExprBody*>(Fn->Body)->Expression, NewEnv);
default:
ZEN_UNREACHABLE
}
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
}
case ValueKind::NativeFunction:
{
auto Fn = Op.getBinding();
return Fn(Args);
}
default:
ZEN_UNREACHABLE
}
}
void Evaluator::evaluate(Node* N, Env& E) {
switch (N->getKind()) {
case NodeKind::SourceFile:
{
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:
ZEN_UNREACHABLE
break;
}
default:
ZEN_UNREACHABLE
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -13,495 +13,495 @@
namespace bolt {
static inline bool isWhiteSpace(Char Chr) {
switch (Chr) {
case ' ':
case '\n':
case '\r':
case '\t':
return true;
default:
return false;
}
static inline bool isWhiteSpace(Char Chr) {
switch (Chr) {
case ' ':
case '\n':
case '\r':
case '\t':
return true;
default:
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;
Char C0;
static bool isDirectiveIdentifierStart(Char Chr) {
return (Chr >= 65 && Chr <= 90) // Uppercase letter
|| (Chr >= 96 && Chr <= 122) // Lowercase letter
|| Chr == '_';
}
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 (;;) {
C0 = getChar();
Value.push_back(C0);
if (C0 == '\n' || C0 == EOF) {
break;
}
}
continue;
}
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() {
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 (;;) {
C0 = getChar();
Value.push_back(C0);
if (C0 == '\n' || C0 == EOF) {
break;
}
}
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):
return new EndOfFile(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 '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();
case '"':
{
ByteString Text;
bool Escaping = false;
for (;;) {
auto Loc = getCurrentLoc();
auto C1 = getChar();
if (Escaping) {
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);
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:
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:
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();
if (C1 == '.') {
getChar();
auto C2 = peekChar();
if (C2 == '.') {
DE.add<UnexpectedStringDiagnostic>(File, getCurrentLoc(), String { static_cast<char>(C2) });
return nullptr;
}
return new DotDot(StartLoc);
if (!isOperatorPart(C1)) {
break;
}
return new Dot(StartLoc);
Text.push_back(static_cast<char>(C1));
getChar();
}
case '+':
case '-':
case '*':
case '/':
case '^':
case '&':
case '|':
case '%':
case '$':
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);
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);
}
#define BOLT_SIMPLE_TOKEN(ch, name) case ch: return new name(StartLoc);
BOLT_SIMPLE_TOKEN(',', Comma)
BOLT_SIMPLE_TOKEN(':', Colon)
BOLT_SIMPLE_TOKEN('(', LParen)
BOLT_SIMPLE_TOKEN(')', RParen)
BOLT_SIMPLE_TOKEN('[', LBracket)
BOLT_SIMPLE_TOKEN(']', RBracket)
BOLT_SIMPLE_TOKEN('{', LBrace)
BOLT_SIMPLE_TOKEN('}', RBrace)
BOLT_SIMPLE_TOKEN('~', Tilde)
BOLT_SIMPLE_TOKEN('@', At)
BOLT_SIMPLE_TOKEN(',', Comma)
BOLT_SIMPLE_TOKEN(':', Colon)
BOLT_SIMPLE_TOKEN('(', LParen)
BOLT_SIMPLE_TOKEN(')', RParen)
BOLT_SIMPLE_TOKEN('[', LBracket)
BOLT_SIMPLE_TOKEN(']', RBracket)
BOLT_SIMPLE_TOKEN('{', LBrace)
BOLT_SIMPLE_TOKEN('}', RBrace)
BOLT_SIMPLE_TOKEN('~', Tilde)
BOLT_SIMPLE_TOKEN('@', At)
default:
DE.add<UnexpectedStringDiagnostic>(File, StartLoc, String { static_cast<char>(C0) });
return nullptr;
}
default:
DE.add<UnexpectedStringDiagnostic>(File, StartLoc, String { static_cast<char>(C0) });
return nullptr;
}
Token* Scanner::read() {
for (;;) {
auto T0 = readNullable();
if (T0) {
// EndOFFile is guaranteed to be produced, so that ends the stream.
return T0;
}
}
Token* Scanner::read() {
for (;;) {
auto T0 = readNullable();
if (T0) {
// EndOFFile is guaranteed to be produced, so that ends the stream.
return T0;
}
}
}
Punctuator::Punctuator(Stream<Token*>& Tokens):
Tokens(Tokens) {
Frames.push(FrameType::Block);
Locations.push(TextLoc { 0, 0 });
}
Punctuator::Punctuator(Stream<Token*>& Tokens):
Tokens(Tokens) {
Frames.push(FrameType::Block);
Locations.push(TextLoc { 0, 0 });
}
Token* Punctuator::read() {
Token* Punctuator::read() {
auto T0 = Tokens.peek();
auto T0 = Tokens.peek();
switch (T0->getKind()) {
case NodeKind::LBrace:
Frames.push(FrameType::Fallthrough);
break;
case NodeKind::EndOfFile:
{
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();
switch (T0->getKind()) {
case NodeKind::LBrace:
Frames.push(FrameType::Fallthrough);
break;
case NodeKind::EndOfFile:
{
if (Frames.size() == 1) {
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();
auto Frame = Frames.top();
Frames.pop();
switch (Frame) {
case FrameType::Fallthrough:
break;
case FrameType::Block:
return new BlockEnd(T0->getStartLoc());
}
Frames.push(FrameType::LineFold);
Locations.push(T0->getStartLoc());
return Tokens.get();
case FrameType::LineFold:
return new LineFoldEnd(T0->getStartLoc());
}
}
ZEN_UNREACHABLE
default:
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 {
TextFile::TextFile(ByteString Path, ByteString Text):
Path(Path), Text(Text) {
LineOffsets.push_back(0);
for (size_t I = 0; I < Text.size(); I++) {
auto Chr = Text[I];
if (Chr == '\n') {
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;
TextFile::TextFile(ByteString Path, ByteString Text):
Path(Path), Text(Text) {
LineOffsets.push_back(0);
for (size_t I = 0; I < Text.size(); I++) {
auto Chr = Text[I];
if (Chr == '\n') {
LineOffsets.push_back(I+1);
}
}
ZEN_UNREACHABLE
LineOffsets.push_back(Text.size());
}
size_t TextFile::getColumn(size_t Offset) const {
auto Line = getLine(Offset);
auto StartOffset = getStartOffset(Line);
return Offset - StartOffset + 1 ;
}
size_t TextFile::getLineCount() const {
return LineOffsets.size();
}
ByteString TextFile::getPath() const {
return Path;
}
size_t TextFile::getStartOffset(size_t Line) const {
return LineOffsets[Line-1];
}
ByteString TextFile::getText() const {
return Text;
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
}
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 {
bool TypeclassSignature::operator<(const TypeclassSignature& Other) const {
if (Id < Other.Id) {
bool TypeclassSignature::operator<(const TypeclassSignature& Other) const {
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;
}
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 TCon::operator==(const TCon& Other) const {
return Id == Other.Id;
}
bool TypeIndex::operator==(const TypeIndex& Other) const noexcept {
if (Kind != Other.Kind) {
bool TApp::operator==(const TApp& Other) const {
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;
}
switch (Kind) {
case TypeIndexKind::ArrowParamType:
case TypeIndexKind::TupleElement:
return I == Other.I;
default:
return true;
}
return true;
}
bool TNil::operator==(const TNil& Other) const {
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 {
return Id == Other.Id;
}
bool TApp::operator==(const TApp& Other) const {
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;
}
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 true;
return Ty2;
}
bool TNil::operator==(const TNil& Other) const {
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);
}
switch (Kind) {
case TypeKind::Var:
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::Var:
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;
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
}
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);
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;
}
return TypeIndex::forTupleElement(0);
NewElementTypes.push_back(NewElementType);
}
case TypeKind::Field:
return TypeIndex::forFieldType();
default:
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));
}
}
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::forTupleElement(0);
}
case TypeKind::Field:
return TypeIndex::forFieldType();
default:
return TypeIndex(TypeIndexKind::End);
}
}
TypeIndex Type::getEndIndex() const {
return TypeIndex(TypeIndexKind::End);
}
TypeIndex Type::getEndIndex() const {
return TypeIndex(TypeIndexKind::End);
}
bool Type::hasTypeVar(Type* TV) const {
switch (Kind) {
case TypeKind::Var:
return Var.Id == TV->asVar().Id;
case TypeKind::Con:
case TypeKind::Absent:
case TypeKind::Nil:
return false;
case TypeKind::App:
return App.Op->hasTypeVar(TV) || App.Arg->hasTypeVar(TV);
case TypeKind::Tuple:
for (auto Ty: Tuple.ElementTypes) {
if (Ty->hasTypeVar(TV)) {
return true;
}
bool Type::hasTypeVar(Type* TV) const {
switch (Kind) {
case TypeKind::Var:
return Var.Id == TV->asVar().Id;
case TypeKind::Con:
case TypeKind::Absent:
case TypeKind::Nil:
return false;
case TypeKind::App:
return App.Op->hasTypeVar(TV) || App.Arg->hasTypeVar(TV);
case TypeKind::Tuple:
for (auto Ty: Tuple.ElementTypes) {
if (Ty->hasTypeVar(TV)) {
return true;
}
return false;
case TypeKind::Field:
return Field.Ty->hasTypeVar(TV) || Field.RestTy->hasTypeVar(TV);
case TypeKind::Arrow:
return Arrow.ParamType->hasTypeVar(TV) || Arrow.ReturnType->hasTypeVar(TV);
case TypeKind::Present:
return Present.Ty->hasTypeVar(TV);
}
ZEN_UNREACHABLE
}
return false;
case TypeKind::Field:
return Field.Ty->hasTypeVar(TV) || Field.RestTy->hasTypeVar(TV);
case TypeKind::Arrow:
return Arrow.ParamType->hasTypeVar(TV) || Arrow.ReturnType->hasTypeVar(TV);
case TypeKind::Present:
return Present.Ty->hasTypeVar(TV);
}
ZEN_UNREACHABLE
}
}