From 75f93cc0be5bbd554f08c59b57c166d3f1e6a80c Mon Sep 17 00:00:00 2001 From: Peter Matta <mattapet@fit.cvut.cz> Date: Wed, 23 May 2018 20:54:08 +0200 Subject: [PATCH] Added constat expression solving --- examples/globExpr.dusk | 5 +- include/dusk/AST/ASTNode.h | 2 +- include/dusk/AST/ASTVisitor.h | 140 ++------ include/dusk/AST/Decl.h | 9 +- include/dusk/AST/DiagnosticsParse.h | 12 + include/dusk/AST/Expr.h | 21 +- include/dusk/AST/Pattern.h | 15 +- include/dusk/AST/Scope.h | 22 ++ include/dusk/AST/Stmt.h | 27 +- include/dusk/AST/Type.h | 25 +- include/dusk/AST/TypeRepr.h | 35 +- lib/AST/ASTContext.cpp | 3 +- lib/AST/ASTNode.cpp | 2 +- lib/AST/ASTPrinter.cpp | 88 ++--- lib/AST/ASTWalker.cpp | 429 ++++-------------------- lib/AST/Decl.cpp | 20 ++ lib/AST/Expr.cpp | 42 ++- lib/AST/Pattern.cpp | 10 + lib/AST/Scope.cpp | 18 + lib/AST/Stmt.cpp | 50 +++ lib/AST/Type.cpp | 8 + lib/AST/TypeRepr.cpp | 10 + lib/IRGen/GenFunc.cpp | 81 +++-- lib/Parser/ParseType.cpp | 82 ++--- lib/Sema/CMakeLists.txt | 1 + lib/Sema/Sema.cpp | 4 +- lib/Sema/TypeCheckDecl.cpp | 273 ++++++++++----- lib/Sema/TypeCheckExpr.cpp | 501 +++++++++++++++++++++++----- lib/Sema/TypeCheckPattern.cpp | 98 ++++-- lib/Sema/TypeCheckStmt.cpp | 346 ++++++++++++------- lib/Sema/TypeCheckType.cpp | 86 +++++ lib/Sema/TypeChecker.cpp | 238 ++++++------- lib/Sema/TypeChecker.h | 138 ++++---- lib/Sema/TypeResolver.cpp | 18 +- tools/duskc/main.cpp | 4 +- 35 files changed, 1721 insertions(+), 1142 deletions(-) create mode 100644 lib/Sema/TypeCheckType.cpp diff --git a/examples/globExpr.dusk b/examples/globExpr.dusk index 6510eb5..4ad8c89 100644 --- a/examples/globExpr.dusk +++ b/examples/globExpr.dusk @@ -1,4 +1,7 @@ -var a: Int; +let a = 4; +var arr: Int[a]; + +// var a: Int; func main() { println(a = 14); diff --git a/include/dusk/AST/ASTNode.h b/include/dusk/AST/ASTNode.h index ca4bd08..480230e 100644 --- a/include/dusk/AST/ASTNode.h +++ b/include/dusk/AST/ASTNode.h @@ -45,7 +45,7 @@ public: /// /// \return \c true if the node was walked properly and may continue /// traversing the AST, \c false if should terminate. - virtual bool walk(ASTWalker &Walker); + bool walk(ASTWalker &Walker); public: /// Only allow allocation using \c ASTContext diff --git a/include/dusk/AST/ASTVisitor.h b/include/dusk/AST/ASTVisitor.h index 7d28973..ea1172d 100644 --- a/include/dusk/AST/ASTVisitor.h +++ b/include/dusk/AST/ASTVisitor.h @@ -34,110 +34,19 @@ namespace dusk { /// traversal. \c true indicates valid traversal of given node/subtree and /// visitor may continue traversing. \c false means failure, upon which visitor /// must immedietly terminate traversal of the AST. -template <typename Derived> class ASTVisitor { +template <typename Derived, + typename DeclRetTy = void, + typename ExprRetTy = void, + typename StmtRetTy = void, + typename PatternRetTy = void, + typename TypeReprRetTy = void> +class ASTVisitor { public: /// Returns a reference to the derived class. Derived &getDerived() { return *static_cast<Derived *>(this); } - bool visit_(ASTNode *N) { - if (auto *D = dynamic_cast<Decl *>(N)) - return visit_(D); - if (auto *E = dynamic_cast<Expr *>(N)) - return visit_(E); - if (auto *S = dynamic_cast<Stmt *>(N)) - return visit_(S); - - llvm_unreachable("Unexpected node"); - } - - /// Visit a concrete declaration node. - bool visit_(Decl *D) { - switch (D->getKind()) { - case DeclKind::Let: - return getDerived().visit(static_cast<LetDecl *>(D)); - case DeclKind::Func: - return getDerived().visit(static_cast<FuncDecl *>(D)); - case DeclKind::Module: - return getDerived().visit(static_cast<ModuleDecl *>(D)); - case DeclKind::Param: - return getDerived().visit(static_cast<ParamDecl *>(D)); - case DeclKind::Var: - return getDerived().visit(static_cast<VarDecl *>(D)); - } - } - - /// Visit a conrete expression node. - bool visit_(Expr *E) { - switch (E->getKind()) { - case ExprKind::NumberLiteral: - return getDerived().visit(static_cast<NumberLiteralExpr *>(E)); - case ExprKind::ArrayLiteral: - return getDerived().visit(static_cast<ArrayLiteralExpr *>(E)); - case ExprKind::Identifier: - return getDerived().visit(static_cast<IdentifierExpr *>(E)); - case ExprKind::Paren: - return getDerived().visit(static_cast<ParenExpr *>(E)); - case ExprKind::Assign: - return getDerived().visit(static_cast<AssignExpr *>(E)); - case ExprKind::Infix: - return getDerived().visit(static_cast<InfixExpr *>(E)); - case ExprKind::Prefix: - return getDerived().visit(static_cast<PrefixExpr *>(E)); - case ExprKind::Call: - return getDerived().visit(static_cast<CallExpr *>(E)); - case ExprKind::Subscript: - return getDerived().visit(static_cast<SubscriptExpr *>(E)); - } - } - - /// Visit a concrete statement node. - bool visit_(Stmt *S) { - switch (S->getKind()) { - case StmtKind::Break: - return getDerived().visit(static_cast<BreakStmt *>(S)); - case StmtKind::Return: - return getDerived().visit(static_cast<ReturnStmt *>(S)); - case StmtKind::Range: - return getDerived().visit(static_cast<RangeStmt *>(S)); - case StmtKind::Subscript: - return getDerived().visit(static_cast<SubscriptStmt *>(S)); - case StmtKind::Block: - return getDerived().visit(static_cast<BlockStmt *>(S)); - case StmtKind::Extern: - return getDerived().visit(static_cast<ExternStmt *>(S)); - case StmtKind::For: - return getDerived().visit(static_cast<ForStmt *>(S)); - case StmtKind::Func: - return getDerived().visit(static_cast<FuncStmt *>(S)); - case StmtKind::If: - return getDerived().visit(static_cast<IfStmt *>(S)); - case StmtKind::While: - return getDerived().visit(static_cast<WhileStmt *>(S)); - } - } - - /// Visit a concrete pattern node. - bool visit_(Pattern *P) { - switch (P->getKind()) { - case PatternKind::Expr: - return getDerived().visit(static_cast<ExprPattern *>(P)); - case PatternKind::Variable: - return getDerived().visit(static_cast<VarPattern *>(P)); - } - } - - /// Visits concrete TypeRepr - bool visit_(TypeRepr *T) { - switch (T->getKind()) { - case TypeReprKind::Ident: - return getDerived().visit(static_cast<IdentTypeRepr *>(T)); - case TypeReprKind::Array: - return getDerived().visit(static_cast<ArrayTypeRepr *>(T)); - } - } - /// Visit a concrete declaration node. - bool visit(Decl *D) { + DeclRetTy visit(Decl *D) { switch (D->getKind()) { case DeclKind::Let: return getDerived().visitLetDecl(static_cast<LetDecl *>(D)); @@ -151,9 +60,9 @@ public: return getDerived().visitParamDecl(static_cast<ParamDecl *>(D)); } } - + /// Visit a concrete expression node. - Expr *visit(Expr *E) { + ExprRetTy visit(Expr *E) { switch (E->getKind()) { case ExprKind::NumberLiteral: return getDerived().visitNumberLiteralExpr( @@ -177,9 +86,9 @@ public: return getDerived().visitSubscriptExpr(static_cast<SubscriptExpr *>(E)); } } - + /// Visit a concrete statement node. - bool visit(Stmt *S) { + StmtRetTy visit(Stmt *S) { switch (S->getKind()) { case StmtKind::Break: return getDerived().visitBreakStmt(static_cast<BreakStmt *>(S)); @@ -203,9 +112,9 @@ public: return getDerived().visitWhileStmt(static_cast<WhileStmt *>(S)); } } - + /// Visit a concrete pattern node. - bool visit(Pattern *P) { + PatternRetTy visit(Pattern *P) { switch (P->getKind()) { case PatternKind::Expr: return getDerived().visitExprPattern(static_cast<ExprPattern *>(P)); @@ -213,9 +122,9 @@ public: return getDerived().visitVarPattern(static_cast<VarPattern *>(P)); } } - + /// Visits concrete TypeRepr - bool visit(TypeRepr *T) { + TypeReprRetTy visit(TypeRepr *T) { switch (T->getKind()) { case TypeReprKind::Ident: return getDerived().visitIdentTypeRepr(static_cast<IdentTypeRepr *>(T)); @@ -225,6 +134,23 @@ public: } }; +template <typename Derived, typename DeclRetTy = void> +using DeclVisitor = ASTVisitor<Derived, DeclRetTy, void, void, void, void>; + +template <typename Derived, typename ExprRetTy = void> +using ExprVisitor = ASTVisitor<Derived, void, ExprRetTy, void, void, void>; + +template <typename Derived, typename StmtRetTy = void> +using StmtVisitor = ASTVisitor<Derived, void, void, StmtRetTy, void, void>; + +template <typename Derived, typename PatternRetTy = void> +using PatternVisitor = + ASTVisitor<Derived, void, void, void, PatternRetTy, void>; + +template <typename Derived, typename TypeReprRetTy = void> +using TypeReprVisitor = + ASTVisitor<Derived, void, void, void, void, TypeReprRetTy>; + } // namespace dusk #endif /* DUSK_AST_VISITOR_H */ diff --git a/include/dusk/AST/Decl.h b/include/dusk/AST/Decl.h index 85226d6..41f0b9c 100644 --- a/include/dusk/AST/Decl.h +++ b/include/dusk/AST/Decl.h @@ -87,7 +87,12 @@ public: SMRange getSourceRange() const override; - bool walk(ASTWalker &Walker) override; + bool walk(ASTWalker &Walker); + + VarDecl *getVarDecl(); + LetDecl *getLetDecl(); + ParamDecl *getParamDecl(); + FuncDecl *getFuncDecl(); }; /// Declaration of value-holdable node @@ -106,6 +111,8 @@ public: bool hasValue() const { return Value != nullptr; } Expr *getValue() const { return Value; } void setValue(Expr *V) { Value = V; } + + bool isLet() const { return isKind(DeclKind::Let); } }; /// Declaration of a variable diff --git a/include/dusk/AST/DiagnosticsParse.h b/include/dusk/AST/DiagnosticsParse.h index c6e86d6..a6fe376 100644 --- a/include/dusk/AST/DiagnosticsParse.h +++ b/include/dusk/AST/DiagnosticsParse.h @@ -44,11 +44,13 @@ enum DiagID : unsigned { // Semantic diagnostics + unexpected_expresssion, unexpected_break_stmt, unexpected_return_stmt, expression_not_assignable, redefinition_of_identifier, return_missing_value, + array_index_out_of_bounds, // Types expected_type_annotation, @@ -59,6 +61,8 @@ enum DiagID : unsigned { subscripted_value_not_array, invalid_array_size, expected_array_size, + variable_array_size, + invalid_operand_type, ambigous_types, type_missmatch, @@ -112,6 +116,8 @@ static StringRef getTextForID(DiagID ID) { case DiagID::expected_func_kw: return "Expected 'func' keyword to at start of function delaration."; + case DiagID::unexpected_expresssion: + return "Unexpected expression outside of a function scope."; case DiagID::unexpected_break_stmt: return "Unexpected 'break' statement."; case DiagID::unexpected_return_stmt: @@ -120,6 +126,8 @@ static StringRef getTextForID(DiagID ID) { return "Expression is not assignable."; case DiagID::return_missing_value: return "Non-void function must return a value."; + case DiagID::array_index_out_of_bounds: + return "Indexing array out of array bounds."; case DiagID::expected_type_annotation: return "Expected type annocation ': Type'."; @@ -139,6 +147,10 @@ static StringRef getTextForID(DiagID ID) { return "Array size must be specified as a number literal."; case DiagID::expected_array_size: return "Every array type must define size of the array."; + case DiagID::invalid_operand_type: + return "Invalid operand type."; + case DiagID::variable_array_size: + return "Size of the array must be specified as a constant expression."; case DiagID::ambigous_types: return "Ambigous type resolution."; diff --git a/include/dusk/AST/Expr.h b/include/dusk/AST/Expr.h index 0b5c9c9..745ccbc 100644 --- a/include/dusk/AST/Expr.h +++ b/include/dusk/AST/Expr.h @@ -53,6 +53,9 @@ class Expr : public ASTNode { /// Type of declaration Type *Ty; + + /// Bool indicating if the expression was solved. + bool Solved; public: Expr(ExprKind K); @@ -66,7 +69,22 @@ public: /// Sets declaration type void setType(Type *T) { Ty = T; } - bool walk(ASTWalker &Walker) override; + /// Return \c true if the expression was solved, \c false otherwise. + bool getSolved() const { return Solved; } + + /// Sets the \c Solved state of the expression. + void setSolved(bool S) { Solved = S; } + + virtual Expr *walk(ASTWalker &Walker); + + NumberLiteralExpr *getNumberLiteralExpr(); + ArrayLiteralExpr *getArrayLiteralExpr(); + IdentifierExpr *getIdentifierExpr(); + ParenExpr *getParenExpr(); + InfixExpr *getInfixExpr(); + PrefixExpr *getPrefixExpr(); + CallExpr *getCallExpr(); + SubscriptExpr *getSubscriptExpr(); }; /// Number literal expression encalsulation. @@ -80,6 +98,7 @@ public: SMRange getValLoc() const { return ValueLoc; } int64_t getValue() const { return Value; } + void setValue(int64_t Val) { Value = Val; } SMRange getSourceRange() const override; }; diff --git a/include/dusk/AST/Pattern.h b/include/dusk/AST/Pattern.h index e433ef2..7ae4166 100644 --- a/include/dusk/AST/Pattern.h +++ b/include/dusk/AST/Pattern.h @@ -22,6 +22,8 @@ class Expr; class Stmt; class Type; class ParamDecl; +class ExprPattern; +class VarPattern; class ASTWalker; /// Pattern description. @@ -30,25 +32,28 @@ enum struct PatternKind { Expr, Variable }; class Pattern { /// Pattern type. PatternKind Kind; - + /// Pattern type Type *Ty; public: Pattern(PatternKind K); PatternKind getKind() const { return Kind; } - + virtual size_t count() const = 0; virtual SMRange getSourceRange() const = 0; - + void setType(Type *T) { Ty = T; } Type *getType() const { return Ty; } - + SMLoc getLocStart() { return getSourceRange().Start; } SMLoc getLocEnd() { return getSourceRange().End; } - + bool walk(ASTWalker &Walker); + ExprPattern *getExprPattern(); + VarPattern *getVarPattern(); + public: /// Only allow allocation using \c ASTContext void *operator new(size_t Bytes, ASTContext &Context); diff --git a/include/dusk/AST/Scope.h b/include/dusk/AST/Scope.h index 6abc5ab..3fa83b2 100644 --- a/include/dusk/AST/Scope.h +++ b/include/dusk/AST/Scope.h @@ -100,6 +100,28 @@ public: /// Returns statement owning the current scope. Stmt *getStmt() const { return S; } }; + +/// A RAII class representing a push scope change. +class PushScopeRAII { + bool Popped; + +public: + /// Previous parent scope. + Scope Parent; + + /// Current scope reference. + Scope &Self; + + PushScopeRAII(Scope &Scp, unsigned Flags, Stmt *S = nullptr); + + ~PushScopeRAII(); + + /// Returns \c true if scope change has not been popped, \c false otherwise. + bool isValid() const { return !Popped; } + + /// Explicitely pop the scope change. + void pop(); +}; } // namespace dusk diff --git a/include/dusk/AST/Stmt.h b/include/dusk/AST/Stmt.h index 692afee..ed04535 100644 --- a/include/dusk/AST/Stmt.h +++ b/include/dusk/AST/Stmt.h @@ -22,6 +22,16 @@ namespace dusk { class Decl; class Expr; class Stmt; +class BreakStmt; +class ReturnStmt; +class SubscriptStmt; +class RangeStmt; +class ExternStmt; +class BlockStmt; +class FuncStmt; +class ForStmt; +class WhileStmt; +class IfStmt; class IdentifierExpr; class ASTWalker; class ASTContext; @@ -30,14 +40,14 @@ class ASTContext; enum struct StmtKind { Break, Return, + Subscript, Range, Extern, Block, Func, For, While, - If, - Subscript + If }; class Stmt : public ASTNode { @@ -49,7 +59,18 @@ public: StmtKind getKind() const { return Kind; } - bool walk(ASTWalker &Walker) override; + bool walk(ASTWalker &Walker); + + BreakStmt *getBreakStmt(); + ReturnStmt *getReturnStmt(); + SubscriptStmt *getSubscripStmt(); + RangeStmt *getRangeStmt(); + ExternStmt *getExternStmt(); + BlockStmt *getBlockStmt(); + FuncStmt *getFuncStmt(); + ForStmt *getForStmt(); + WhileStmt *getWhileStmt(); + IfStmt *getIfStmt(); }; /// Represents a \c break statement in a loop. diff --git a/include/dusk/AST/Type.h b/include/dusk/AST/Type.h index ec4c237..fb731df 100644 --- a/include/dusk/AST/Type.h +++ b/include/dusk/AST/Type.h @@ -26,7 +26,7 @@ class FunctionType; class PatternType; class ArrayType; class ASTContext; - + enum struct TypeKind; enum struct TypeKind { Void, Int, Value, Pattern, Array, Function }; @@ -43,16 +43,17 @@ public: virtual bool isValueType() const { return false; } virtual bool isVoidType() const { return false; } virtual bool isClassOf(const Type *T) const { return this == T; } - + VoidType *getVoidType(); IntType *getIntType(); + PatternType *getPatternType(); FunctionType *getFuncType(); ArrayType *getArrayType(); - + private: void *operator new(size_t Bytes) throw() = delete; void operator delete(void *Data) throw() = delete; - + public: /// Only allow allocation using \c ASTContext void *operator new(size_t Bytes, ASTContext &Context); @@ -87,18 +88,18 @@ public: return T->getKind() == TypeKind::Int; } }; - + /// Representing array type class ArrayType : public ValueType { Type *BaseTy; size_t Size; - + public: ArrayType(Type *Ty, size_t S); - + Type *getBaseType() const { return BaseTy; } size_t getSize() const { return Size; } - + bool isClassOf(const Type *T) const override { if (Type::isClassOf(T)) return true; @@ -106,7 +107,7 @@ public: return isClassOf(Ty); return false; } - + bool isClassOf(const ArrayType *T) const; }; @@ -119,7 +120,7 @@ public: FunctionType(Type *AT, Type *RT); Type *getArgsType() const { return ArgsTy; } Type *getRetType() const { return RetTy; } - + bool isClassOf(const Type *T) const override { if (Type::isClassOf(T)) return true; @@ -127,7 +128,7 @@ public: return isClassOf(Ty); return false; } - + bool isClassOf(const FunctionType *T) const; }; @@ -138,7 +139,7 @@ public: PatternType(SmallVector<Type *, 128> &&I); ArrayRef<Type *> getItems() const { return Items; } - + bool isClassOf(const Type *T) const override { if (Type::isClassOf(T)) return true; diff --git a/include/dusk/AST/TypeRepr.h b/include/dusk/AST/TypeRepr.h index 9529f34..a365632 100644 --- a/include/dusk/AST/TypeRepr.h +++ b/include/dusk/AST/TypeRepr.h @@ -19,6 +19,8 @@ namespace dusk { class Expr; class Stmt; class Type; +class IdentTypeRepr; +class ArrayTypeRepr; class ASTWalker; class ASTContext; @@ -26,25 +28,28 @@ enum struct TypeReprKind { Ident, Array }; - + class TypeRepr { TypeReprKind Kind; - + Type *Ty; - + public: TypeRepr(TypeReprKind K); - + TypeReprKind getKind() const { return Kind; } SMLoc getLocStart() const { return getSourceRange().Start; } SMLoc getLocEnd() const { return getSourceRange().End; } virtual SMRange getSourceRange() const = 0; - + Type *getType() const { return Ty; } void setType(Type *T) { Ty = T; } - + bool walk(ASTWalker &Walker); - + + IdentTypeRepr *getIdentTypeRepr(); + ArrayTypeRepr *getArrayTypeRepr(); + public: /// Only allow allocation using \c ASTContext void *operator new(size_t Bytes, ASTContext &Context); @@ -55,12 +60,12 @@ public: class IdentTypeRepr : public TypeRepr { /// Type identifier StringRef Ident; - + public: IdentTypeRepr(StringRef ID); - + StringRef getIdent() const { return Ident; } - + SMRange getSourceRange() const override; }; @@ -68,19 +73,19 @@ public: class ArrayTypeRepr : public TypeRepr { /// Base type of array. TypeRepr *BaseTyRepr; - + /// Array size specifier. Stmt *Size; - + public: ArrayTypeRepr(TypeRepr *B, Stmt *S); - + TypeRepr *getBaseTyRepr() const { return BaseTyRepr; } Stmt *getSize() const { return Size; } - + SMRange getSourceRange() const override; }; - + } // namespace dusk #endif /* DUSK_TYPE_REPR_H */ diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 7ada432..e46062a 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1,4 +1,3 @@ - //===--- ASTContext.cpp ---------------------------------------------------===// // // dusk-lang @@ -26,7 +25,7 @@ void *ASTContext::Allocate(size_t Bytes) { if (Bytes == 0) return nullptr; - auto Res = new size_t[Bytes]; + auto Res = new uint8_t[Bytes]; Cleanups.push_back([Res] { delete[] Res; }); return static_cast<void *>(Res); diff --git a/lib/AST/ASTNode.cpp b/lib/AST/ASTNode.cpp index 2c3174a..65db039 100644 --- a/lib/AST/ASTNode.cpp +++ b/lib/AST/ASTNode.cpp @@ -26,7 +26,7 @@ bool ASTNode::walk(ASTWalker &Walker) { return D->walk(Walker); else if (auto E = dynamic_cast<Expr *>(this)) - return E->walk(Walker); + return E->walk(Walker) != nullptr; else if (auto S = dynamic_cast<Stmt *>(this)) return S->walk(Walker); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 99a4793..23180da 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -38,7 +38,7 @@ public: // MARK: - Declaration nodes - bool visitModuleDecl(ModuleDecl *D) { + void visitModuleDecl(ModuleDecl *D) { Printer.printText(D->getName()); Printer.printNewline(); @@ -60,10 +60,9 @@ public: Printer.printText(";"); } Printer.printNewline(); - return true; } - bool visitLetDecl(LetDecl *D) { + void visitLetDecl(LetDecl *D) { Printer.printDeclPre(D); Printer << D->getName(); @@ -77,10 +76,9 @@ public: super::visit(D->getValue()); } Printer.printDeclPost(D); - return true; } - bool visitVarDecl(VarDecl *D) { + void visitVarDecl(VarDecl *D) { Printer.printDeclPre(D); Printer << D->getName(); @@ -94,10 +92,9 @@ public: super::visit(D->getValue()); } Printer.printDeclPost(D); - return true; } - bool visitFuncDecl(FuncDecl *D) { + void visitFuncDecl(FuncDecl *D) { Printer.printDeclPre(D); Printer << D->getName() << "("; super::visit(D->getArgs()); @@ -109,108 +106,94 @@ public: } Printer.printDeclPost(D); - return true; } - bool visitParamDecl(ParamDecl *D) { + void visitParamDecl(ParamDecl *D) { Printer.printDeclPost(D); Printer << D->getName() << ": "; if (D->hasTypeRepr()) super::visit(D->getTypeRepr()); Printer.printDeclPost(D); - return true; } // MARK: - Expression nodes - Expr *visitNumberLiteralExpr(NumberLiteralExpr *E) { + void visitNumberLiteralExpr(NumberLiteralExpr *E) { auto St = E->getLocStart().getPointer(); auto En = E->getLocEnd().getPointer(); StringRef Str = {St, (size_t)(En - St)}; Printer << Str; - return E; } - Expr *visitArrayLiteralExpr(ArrayLiteralExpr *E) { + void visitArrayLiteralExpr(ArrayLiteralExpr *E) { Printer << "["; super::visit(E->getValues()); Printer << "]"; - return E; } - Expr *visitIdentifierExpr(IdentifierExpr *E) { + void visitIdentifierExpr(IdentifierExpr *E) { Printer << E->getName(); - return E; } - Expr *visitParenExpr(ParenExpr *E) { + void visitParenExpr(ParenExpr *E) { Printer << "("; super::visit(E->getExpr()); Printer << ")"; - return E; } - Expr *visitAssignExpr(AssignExpr *E) { + void visitAssignExpr(AssignExpr *E) { super::visit(E->getDest()); Printer << " " << tok::assign << " "; super::visit(E->getSource()); - return E; } - Expr *visitCallExpr(CallExpr *E) { + void visitCallExpr(CallExpr *E) { super::visit(E->getCallee()); Printer << "("; super::visit(E->getArgs()); Printer << ")"; - return E; } - Expr *visitInfixExpr(InfixExpr *E) { + void visitInfixExpr(InfixExpr *E) { super::visit(E->getLHS()); Printer << " " << E->getOp().getKind() << " "; super::visit(E->getRHS()); - return E; } - Expr *visitPrefixExpr(PrefixExpr *E) { + void visitPrefixExpr(PrefixExpr *E) { Printer << E->getOp().getKind(); super::visit(E->getDest()); - return E; } - Expr *visitSubscriptExpr(SubscriptExpr *E) { + void visitSubscriptExpr(SubscriptExpr *E) { super::visit(E->getBase()); super::visit(E->getSubscript()); - return E; } // MARK: - Statement nodes - bool visitBreakStmt(BreakStmt *S) { + void visitBreakStmt(BreakStmt *S) { Printer.printStmtPre(S); Printer << tok::kwBreak; Printer.printStmtPost(S); - return true; } - bool visitReturnStmt(ReturnStmt *S) { + void visitReturnStmt(ReturnStmt *S) { Printer.printStmtPre(S); Printer << tok::kwReturn << " "; super::visit(S->getValue()); Printer.printStmtPost(S); - return true; } - bool visitSubscriptStmt(SubscriptStmt *S) { + void visitSubscriptStmt(SubscriptStmt *S) { Printer.printStmtPre(S); super::visit(S->getValue()); Printer.printStmtPost(S); - return true; } - bool visitRangeStmt(RangeStmt *S) { + void visitRangeStmt(RangeStmt *S) { Printer.printStmtPre(S); super::visit(S->getStart()); @@ -218,10 +201,9 @@ public: super::visit(S->getEnd()); Printer.printStmtPost(S); - return true; } - bool visitBlockStmt(BlockStmt *S) { + void visitBlockStmt(BlockStmt *S) { Printer.printStmtPre(S); bool IsFirst = true; for (auto N : S->getNodes()) { @@ -245,53 +227,48 @@ public: Printer.printText(";"); } Printer.printStmtPost(S); - return true; } - bool visitExternStmt(ExternStmt *S) { + void visitExternStmt(ExternStmt *S) { Printer.printStmtPre(S); Printer << tok::kwExtern << " "; super::visit(S->getPrototype()); Printer.printStmtPost(S); - return true; } - bool visitFuncStmt(FuncStmt *S) { + void visitFuncStmt(FuncStmt *S) { Printer.printStmtPre(S); super::visit(S->getPrototype()); Printer << " "; super::visit(S->getBody()); Printer.printStmtPost(S); - return true; } - bool visitForStmt(ForStmt *S) { + void visitForStmt(ForStmt *S) { Printer.printStmtPre(S); Printer << tok::kwFor << " "; super::visit(S->getIter()); Printer << " " << tok::kwIn << " "; - super::visit_(S->getRange()); + super::visit(S->getRange()); Printer << " "; super::visit(S->getBody()); Printer.printStmtPost(S); - return true; } - bool visitWhileStmt(WhileStmt *S) { + void visitWhileStmt(WhileStmt *S) { Printer.printStmtPre(S); Printer << tok::kwWhile << " "; - super::visit_(S->getCond()); + super::visit(S->getCond()); Printer << " "; super::visit(S->getBody()); Printer.printStmtPost(S); - return true; } - bool visitIfStmt(IfStmt *S) { + void visitIfStmt(IfStmt *S) { Printer.printStmtPre(S); Printer << tok::kwIf << " "; @@ -305,40 +282,35 @@ public: } Printer.printStmtPost(S); - return true; } // MARK: - Pattern nodes - bool visitExprPattern(ExprPattern *P) { + void visitExprPattern(ExprPattern *P) { bool isFirst = true; for (auto V : P->getValues()) { Printer.printSeparator(isFirst, ", "); super::visit(V); } - return true; } - bool visitVarPattern(VarPattern *P) { + void visitVarPattern(VarPattern *P) { bool isFirst = true; for (auto V : P->getVars()) { Printer.printSeparator(isFirst, ", "); super::visit(V); } - return true; } // MARK: - Type representations - bool visitIdentTypeRepr(IdentTypeRepr *T) { + void visitIdentTypeRepr(IdentTypeRepr *T) { Printer << T->getIdent(); - return true; } - bool visitArrayTypeRepr(ArrayTypeRepr *T) { + void visitArrayTypeRepr(ArrayTypeRepr *T) { super::visit(T->getBaseTyRepr()); super::visit(T->getSize()); - return true; } }; diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index c5b3686..3b1ba47 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -34,22 +34,27 @@ namespace { /// This class implements recursive AST node traversal. It uses user-provided /// instance of \c ASTWalker of any class derived from it to actually walk /// each and every node of the AST. -class Traversal : public ASTVisitor<Traversal> { +class Traversal : public ASTVisitor<Traversal, + /* Decl */ bool, + /* Expr */ Expr *, + /* Stmt */ bool, + /* Pattern */ bool, + /* TypeRepr */ bool> { /// Walker to be used to walk the tree. ASTWalker &Walker; /// Convenience type alias. typedef ASTVisitor super; - + friend super; - + // MARK: - Declarations - + bool visitLetDecl(LetDecl *D) { if (D->hasTypeRepr()) if (!traverse(D->getTypeRepr())) return false; - + if (D->hasValue()) { auto E = traverse(D->getValue()); if (!E) @@ -58,12 +63,12 @@ class Traversal : public ASTVisitor<Traversal> { } return true; } - + bool visitVarDecl(VarDecl *D) { if (D->hasTypeRepr()) if (!traverse(D->getTypeRepr())) return false; - + if (D->hasValue()) { auto E = traverse(D->getValue()); if (!E) @@ -72,51 +77,47 @@ class Traversal : public ASTVisitor<Traversal> { } return true; } - + bool visitParamDecl(ParamDecl *D) { return !D->hasTypeRepr() || traverse(D->getTypeRepr()); } - + bool visitFuncDecl(FuncDecl *D) { if (!traverse(D->getArgs())) return false; return !D->hasTypeRepr() || traverse(D->getTypeRepr()); } - + bool visitModuleDecl(ModuleDecl *D) { for (auto &N : D->getContents()) { if (auto D = dynamic_cast<Decl *>(N)) if (!traverse(D)) return false; - + if (auto E = dynamic_cast<Expr *>(N)) if ((N = traverse(E)) == nullptr) return false; - + if (auto S = dynamic_cast<Stmt *>(N)) if (!traverse(S)) return false; } return true; } - + // MARK: - Expressions - - Expr *visitNumberLiteralExpr(NumberLiteralExpr *E) { - return E; - } - + + Expr *visitNumberLiteralExpr(NumberLiteralExpr *E) { return E; } + Expr *visitArrayLiteralExpr(ArrayLiteralExpr *E) { if (E->getValues()) return E; else return nullptr; } - - Expr *visitIdentifierExpr(IdentifierExpr *E) { - return E; - } - + + Expr *visitIdentifierExpr(IdentifierExpr *E) { return E; } + Expr *visitParenExpr(ParenExpr *E) { if (auto Ex = traverse(E->getExpr())) E->setExpr(Ex); @@ -124,7 +125,7 @@ class Traversal : public ASTVisitor<Traversal> { return nullptr; return E; } - + Expr *visitInfixExpr(InfixExpr *E) { auto Ex = traverse(E->getLHS()); if (!Ex) @@ -136,7 +137,7 @@ class Traversal : public ASTVisitor<Traversal> { E->setRHS(Ex); return E; } - + Expr *visitAssignExpr(AssignExpr *E) { auto Ex = traverse(E->getDest()); if (!Ex) @@ -148,7 +149,7 @@ class Traversal : public ASTVisitor<Traversal> { E->setSource(Ex); return E; } - + Expr *visitPrefixExpr(PrefixExpr *E) { if (auto Ex = traverse(E->getDest())) E->setDest(Ex); @@ -156,35 +157,33 @@ class Traversal : public ASTVisitor<Traversal> { return nullptr; return E; } - + Expr *visitCallExpr(CallExpr *E) { if (auto Ex = traverse(E->getCallee())) E->setCallee(Ex); else return nullptr; - + if (!traverse(E->getArgs())) return nullptr; return E; } - + Expr *visitSubscriptExpr(SubscriptExpr *E) { if (auto Ex = traverse(E->getBase())) E->setBase(Ex); else return nullptr; - + if (!traverse(E->getSubscript())) return nullptr; return E; } - + // MAKR: - Statements - - bool visitBreakStmt(BreakStmt *S) { - return true; - } - + + bool visitBreakStmt(BreakStmt *S) { return true; } + bool visitReturnStmt(ReturnStmt *S) { if (S->hasValue()) { if (auto Val = traverse(S->getValue())) @@ -194,7 +193,7 @@ class Traversal : public ASTVisitor<Traversal> { } return true; } - + bool visitSubscriptStmt(SubscriptStmt *S) { if (auto Val = traverse(S->getValue())) S->setValue(Val); @@ -202,51 +201,49 @@ class Traversal : public ASTVisitor<Traversal> { return false; return true; } - + bool visitRangeStmt(RangeStmt *S) { auto Val = traverse(S->getStart()); if (!Val) return false; S->setStart(Val); - + Val = traverse(S->getEnd()); if (!Val) return false; S->setEnd(Val); return true; } - + bool visitBlockStmt(BlockStmt *S) { for (auto &N : S->getNodes()) { if (auto D = dynamic_cast<Decl *>(N)) { if (!traverse(D)) return false; - + } else if (auto E = dynamic_cast<Expr *>(N)) { if ((N = traverse(E)) == nullptr) return false; - + } else if (auto S = dynamic_cast<Stmt *>(N)) { if (!traverse(S)) return false; - + } else { llvm_unreachable("Unexpected AST node."); } } return true; } - - bool visitExternStmt(ExternStmt *S) { - return traverse(S->getPrototype()); - } - + + bool visitExternStmt(ExternStmt *S) { return traverse(S->getPrototype()); } + bool visitFuncStmt(FuncStmt *S) { if (!traverse(S->getPrototype())) return false; return traverse(S->getBody()); } - + bool visitForStmt(ForStmt *S) { if (!traverse(S->getIter())) return false; @@ -254,7 +251,7 @@ class Traversal : public ASTVisitor<Traversal> { return false; return traverse(S->getBody()); } - + bool visitWhileStmt(WhileStmt *S) { if (auto C = traverse(S->getCond())) S->setCond(C); @@ -262,7 +259,7 @@ class Traversal : public ASTVisitor<Traversal> { return false; return traverse(S->getBody()); } - + bool visitIfStmt(IfStmt *S) { if (auto C = traverse(S->getCond())) S->setCond(C); @@ -272,9 +269,9 @@ class Traversal : public ASTVisitor<Traversal> { return false; return !S->hasElseBlock() || traverse(S->getElse()); } - + // MARK: - Patterns - + bool visitExprPattern(ExprPattern *P) { for (auto &E : P->getValues()) { if (auto Val = traverse(E)) @@ -284,63 +281,61 @@ class Traversal : public ASTVisitor<Traversal> { } return true; } - + bool visitVarPattern(VarPattern *P) { for (auto Var : P->getVars()) if (!traverse(Var)) return false; return false; } - + // MARK: - Type representations - - bool visitIdentTypeRepr(IdentTypeRepr *TR) { - return true; - } - + + bool visitIdentTypeRepr(IdentTypeRepr *TR) { return true; } + bool visitArrayTypeRepr(ArrayTypeRepr *TR) { if (!traverse(TR->getBaseTyRepr())) return false; return traverse(TR->getSize()); } - + public: /// Constructs a basic traversal object. Traversal(ASTWalker &W) : Walker(W) {} - + bool traverse(Decl *D) { // Skip current subtree if (!Walker.preWalkDecl(D)) return true; if (!super::visit(D)) return false; - + return Walker.postWalkDecl(D); } - + Expr *traverse(Expr *E) { auto Pre = Walker.preWalkExpr(E); // Skip current subtree if (!Pre.first || !Pre.second) return Pre.second; - + E = super::visit(E); - + if (E) E = Walker.postWalkExpr(E); return E; } - + bool traverse(Stmt *S) { // Skip current subtree if (!Walker.preWalkStmt(S)) return true; if (!super::visit(S)) return false; - + return Walker.postWalkStmt(S); } - + bool traverse(Pattern *P) { // Skip current subtree if (!Walker.preWalkPattern(P)) @@ -349,295 +344,15 @@ public: return false; return Walker.postWalkPattern(P); } - + bool traverse(TypeRepr *TR) { // Skip current subtree if (!Walker.preWalkTypeRepr(TR)) return true; if (!super::visit(TR)) return false; - - return Walker.postWalkTypeRepr(TR); - } - - // MARK: - Declaration nodes - - bool visit(LetDecl *D) { - // Skip current subtree - if (!Walker.preWalk(D)) - return true; - - if (!super::visit_(D->getValue())) - return false; - return Walker.postWalk(D); - } - - bool visit(FuncDecl *D) { - // Skip subtree - if (!Walker.preWalk(D)) - return true; - - if (!super::visit_(D->getArgs())) - return false; - return Walker.postWalk(D); - } - - bool visit(ModuleDecl *D) { - if (!Walker.preWalk(D)) - return true; - - for (auto C : D->getContents()) - if (!super::visit_(C)) - return false; - return Walker.postWalk(D); - } - - bool visit(ParamDecl *D) { - // Skip subtree - if (!Walker.preWalk(D)) - return true; - - return Walker.postWalk(D); - } - - bool visit(VarDecl *D) { - // Skip subtree - if (!Walker.preWalk(D)) - return true; - - if (D->hasValue() && !super::visit_(D->getValue())) - return false; - return Walker.postWalk(D); - } - - // MARK: - Expression nodes - - bool visit(NumberLiteralExpr *E) { - // Skip subtree - if (!Walker.preWalk(E)) - return true; - return Walker.postWalk(E); - } - - bool visit(ArrayLiteralExpr *E) { - // Skip subtree - if (!Walker.preWalk(E)) - return true; - if (!super::visit_(E->getValues())) - return false; - return Walker.postWalk(E); - } - - bool visit(IdentifierExpr *E) { - // Skip subtree - if (!Walker.preWalk(E)) - return true; - - return Walker.postWalk(E); - } - - bool visit(ParenExpr *E) { - // Skip subtree - if (!Walker.preWalk(E)) - return true; - - if (!super::visit_(E->getExpr())) - return false; - return Walker.postWalk(E); - } - - bool visit(AssignExpr *E) { - // Skip subtree - if (!Walker.preWalk(E)) - return true; - - if (!super::visit_(E->getDest())) - return false; - if (!super::visit_(E->getSource())) - return false; - return Walker.postWalk(E); - } - - bool visit(InfixExpr *E) { - // Skip subtree - if (!Walker.preWalk(E)) - return true; - - if (!super::visit_(E->getLHS())) - return false; - if (!super::visit_(E->getRHS())) - return false; - return Walker.postWalk(E); - } - - bool visit(PrefixExpr *E) { - // Skip subtree - if (!Walker.preWalk(E)) - return true; - - if (!super::visit_(E->getDest())) - return false; - return Walker.postWalk(E); - } - - bool visit(CallExpr *E) { - // Skip subtree - if (!Walker.preWalk(E)) - return true; - - if (!super::visit_(E->getCallee())) - return false; - if (!super::visit_(E->getArgs())) - return false; - return Walker.postWalk(E); - } - bool visit(SubscriptExpr *E) { - // Skip subtree - if (!Walker.preWalk(E)) - return true; - - if (!super::visit_(E->getBase())) - return false; - if (!super::visit_(E->getSubscript())) - return false; - return Walker.postWalk(E); - } - - // MARK: - Statement nodes - - bool visit(BreakStmt *S) { - // Skip subtree - if (!Walker.preWalk(S)) - return true; - return Walker.postWalk(S); - } - - bool visit(ReturnStmt *S) { - // Skip subtree - if (!Walker.preWalk(S)) - return true; - - if (S->hasValue() && !super::visit_(S->getValue())) - return false; - return Walker.postWalk(S); - } - - bool visit(RangeStmt *S) { - // Skip subtree - if (!Walker.preWalk(S)) - return false; - - if (!super::visit_(S->getStart())) - return false; - if (!super::visit_(S->getEnd())) - return false; - return Walker.postWalk(S); - } - - bool visit(SubscriptStmt *S) { - // Skip subtree - if (!Walker.preWalk(S)) - return true; - - if (!super::visit_(S->getValue())) - return false; - return Walker.postWalk(S); - } - - bool visit(BlockStmt *S) { - // Skip subtree - if (!Walker.preWalk(S)) - return true; - - for (auto N : S->getNodes()) - if (!super::visit_(N)) - return false; - return Walker.postWalk(S); - } - - bool visit(ExternStmt *S) { - // Skip subtree - if (!Walker.preWalk(S)) - return true; - - if (!super::visit_(S->getPrototype())) - return false; - return Walker.postWalk(S); - } - - bool visit(FuncStmt *S) { - // Skip subtree - if (!Walker.preWalk(S)) - return true; - - if (!super::visit_(S->getPrototype())) - return false; - if (!super::visit_(S->getBody())) - return false; - return Walker.postWalk(S); - } - - bool visit(ForStmt *S) { - // Skip subtree - if (!Walker.preWalk(S)) - return false; - - if (!super::visit_(S->getRange())) - return false; - if (!super::visit_(S->getBody())) - return false; - return Walker.postWalk(S); - } - - bool visit(IfStmt *S) { - // Skip subtree - if (!Walker.preWalk(S)) - return true; - - if (!super::visit_(S->getCond())) - return false; - if (!super::visit_(S->getThen())) - return false; - if (S->hasElseBlock() && !super::visit_(S->getElse())) - return false; - return Walker.postWalk(S); - } - - bool visit(WhileStmt *S) { - // Skip subtree - if (!Walker.preWalk(S)) - return true; - - if (!super::visit_(S->getCond())) - return false; - if (!super::visit_(S->getBody())) - return false; - return Walker.postWalk(S); - } - - // MARK: - Patterns - - bool visit(ExprPattern *P) { - // Skip subtree - if (!Walker.preWalk(P)) - return true; - - for (auto V : P->getValues()) - if (!super::visit_(V)) - return false; - return Walker.postWalk(P); - } - - bool visit(VarPattern *P) { - // Skip subtree - if (!Walker.preWalk(P)) - return true; - - for (auto V : P->getVars()) - if (!super::visit_(V)) - return false; - return Walker.postWalk(P); + return Walker.postWalkTypeRepr(TR); } }; @@ -645,17 +360,13 @@ public: // MARK: - Basic ASTNodes implementations -bool Decl::walk(ASTWalker &Walker) { - return Traversal(Walker).traverse(this); -} +bool Decl::walk(ASTWalker &Walker) { return Traversal(Walker).traverse(this); } -bool Expr::walk(ASTWalker &Walker) { - return Traversal(Walker).traverse(this) != nullptr; +Expr *Expr::walk(ASTWalker &Walker) { + return Traversal(Walker).traverse(this); } -bool Stmt::walk(ASTWalker &Walker) { - return Traversal(Walker).traverse(this); -} +bool Stmt::walk(ASTWalker &Walker) { return Traversal(Walker).traverse(this); } bool Pattern::walk(ASTWalker &Walker) { return Traversal(Walker).traverse(this); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 7c68718..60a1854 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -20,6 +20,26 @@ using namespace dusk; Decl::Decl(DeclKind K, StringRef N, SMLoc NL) : Kind(K), Name(N), NameLoc(NL), Ty(nullptr), TyRepr(nullptr) {} +VarDecl *Decl::getVarDecl() { + assert(Kind == DeclKind::Var && "Invalid Decl convertion"); + return static_cast<VarDecl *>(this); +} + +LetDecl *Decl::getLetDecl() { + assert(Kind == DeclKind::Let && "Invalid Decl convertion"); + return static_cast<LetDecl *>(this); +} + +ParamDecl *Decl::getParamDecl() { + assert(Kind == DeclKind::Param && "Invalid Decl convertion"); + return static_cast<ParamDecl *>(this); +} + +FuncDecl *Decl::getFuncDecl() { + assert(Kind == DeclKind::Func && "Invalid Decl convertion"); + return static_cast<FuncDecl *>(this); +} + Decl::Decl(DeclKind K, StringRef N, SMLoc NL, TypeRepr *TR) : Decl(K, N, NL) { TyRepr = TR; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 1fd4432..24b06f8 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -16,7 +16,47 @@ using namespace dusk; -Expr::Expr(ExprKind K) : Kind(K), Ty(nullptr) {} +Expr::Expr(ExprKind K) : Kind(K), Ty(nullptr), Solved(false) {} + +NumberLiteralExpr *Expr::getNumberLiteralExpr() { + assert(Kind == ExprKind::NumberLiteral && "Invalid Expr convertion"); + return static_cast<NumberLiteralExpr *>(this); +} + +ArrayLiteralExpr *Expr::getArrayLiteralExpr() { + assert(Kind == ExprKind::ArrayLiteral && "Invalid Expr convertion"); + return static_cast<ArrayLiteralExpr *>(this); +} + +IdentifierExpr *Expr::getIdentifierExpr() { + assert(Kind == ExprKind::Identifier && "Invalid Expr convertion"); + return static_cast<IdentifierExpr *>(this); +} + +ParenExpr *Expr::getParenExpr() { + assert(Kind == ExprKind::Paren && "Invalid Expr convertion"); + return static_cast<ParenExpr *>(this); +} + +InfixExpr *Expr::getInfixExpr() { + assert(Kind == ExprKind::Infix && "Invalid Expr convertion"); + return static_cast<InfixExpr *>(this); +} + +PrefixExpr *Expr::getPrefixExpr() { + assert(Kind == ExprKind::Prefix && "Invalid Expr convertion"); + return static_cast<PrefixExpr *>(this); +} + +CallExpr *Expr::getCallExpr() { + assert(Kind == ExprKind::Call && "Invalid Expr convertion"); + return static_cast<CallExpr *>(this); +} + +SubscriptExpr *Expr::getSubscriptExpr() { + assert(Kind == ExprKind::Subscript && "Invalid Expr convertion"); + return static_cast<SubscriptExpr *>(this); +} // MARK: - Number literal expresssion diff --git a/lib/AST/Pattern.cpp b/lib/AST/Pattern.cpp index 8f230a1..d7e68c0 100644 --- a/lib/AST/Pattern.cpp +++ b/lib/AST/Pattern.cpp @@ -18,6 +18,16 @@ using namespace dusk; Pattern::Pattern(PatternKind K) : Kind(K), Ty(nullptr) {} +ExprPattern *Pattern::getExprPattern() { + assert(Kind == PatternKind::Expr && "Invalid Pattern convertion"); + return static_cast<ExprPattern *>(this); +} + +VarPattern *Pattern::getVarPattern() { + assert(Kind == PatternKind::Variable && "Invalid Pattern convertion"); + return static_cast<VarPattern *>(this); +} + void *Pattern::operator new(size_t Bytes, ASTContext &Context) { return Context.Allocate(Bytes); } diff --git a/lib/AST/Scope.cpp b/lib/AST/Scope.cpp index 74b420e..c7ad2d5 100644 --- a/lib/AST/Scope.cpp +++ b/lib/AST/Scope.cpp @@ -24,3 +24,21 @@ Scope::Scope(Scope *P, unsigned SF, Stmt *S) ControlParent = Parent->isControlScope() ? Parent : Parent->getControlParent(); } + +// MARK: - Scope change + +PushScopeRAII::PushScopeRAII(Scope &Scp, unsigned Flags, Stmt *S) + : Popped(false), Parent(Scp), Self(Scp) { + Self = Scope(&Parent, Flags, S); +} + +PushScopeRAII::~PushScopeRAII() { + if (!Popped) + Self = Parent; +} + +void PushScopeRAII::pop() { + assert(isValid() && "Popping already popped scope."); + Self = Parent; + Popped = true; +} diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index d0e8562..93a5f47 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -16,6 +16,56 @@ using namespace dusk; Stmt::Stmt(StmtKind K) : Kind(K) {} +BreakStmt *Stmt::getBreakStmt() { + assert(Kind == StmtKind::Break && "Invalid Stmt conversion"); + return static_cast<BreakStmt *>(this); +} + +ReturnStmt *Stmt::getReturnStmt() { + assert(Kind == StmtKind::Return && "Invalid Stmt conversion"); + return static_cast<ReturnStmt *>(this); +} + +SubscriptStmt *Stmt::getSubscripStmt() { + assert(Kind == StmtKind::Subscript && "Invalid Stmt conversion"); + return static_cast<SubscriptStmt *>(this); +} + +RangeStmt *Stmt::getRangeStmt() { + assert(Kind == StmtKind::Range && "Invalid Stmt conversion"); + return static_cast<RangeStmt *>(this); +} + +ExternStmt *Stmt::getExternStmt() { + assert(Kind == StmtKind::Extern && "Invalid Stmt conversion"); + return static_cast<ExternStmt *>(this); +} + +BlockStmt *Stmt::getBlockStmt() { + assert(Kind == StmtKind::Block && "Invalid Stmt conversion"); + return static_cast<BlockStmt *>(this); +} + +FuncStmt *Stmt::getFuncStmt() { + assert(Kind == StmtKind::Func && "Invalid Stmt conversion"); + return static_cast<FuncStmt *>(this); +} + +ForStmt *Stmt::getForStmt() { + assert(Kind == StmtKind::For && "Invalid Stmt conversion"); + return static_cast<ForStmt *>(this); +} + +WhileStmt *Stmt::getWhileStmt() { + assert(Kind == StmtKind::While && "Invalid Stmt conversion"); + return static_cast<WhileStmt *>(this); +} + +IfStmt *Stmt::getIfStmt() { + assert(Kind == StmtKind::If && "Invalid Stmt conversion"); + return static_cast<IfStmt *>(this); +} + // MARK: - Break statement BreakStmt::BreakStmt(SMRange BL) : Stmt(StmtKind::Break), BreakLoc(BL) {} diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index fe382a6..a5a6274 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -22,14 +22,22 @@ VoidType *Type::getVoidType() { assert(Kind == TypeKind::Void && "Accessing invalid type."); return static_cast<VoidType *>(this); } + IntType *Type::getIntType() { assert(Kind == TypeKind::Int && "Accessing invalid type."); return static_cast<IntType *>(this); } + +PatternType *Type::getPatternType() { + assert(Kind == TypeKind::Pattern && "Accessing invalid type."); + return static_cast<PatternType *>(this); +} + FunctionType *Type::getFuncType() { assert(Kind == TypeKind::Function && "Accessing invalid type."); return static_cast<FunctionType *>(this); } + ArrayType *Type::getArrayType() { assert(Kind == TypeKind::Array && "Accessing invalid type."); return static_cast<ArrayType *>(this); diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index df2af22..e14eda2 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -15,6 +15,16 @@ using namespace dusk; TypeRepr::TypeRepr(TypeReprKind K) : Kind(K) {} +IdentTypeRepr *TypeRepr::getIdentTypeRepr() { + assert(Kind == TypeReprKind::Ident && "Invalid TypeRepr convertion"); + return static_cast<IdentTypeRepr *>(this); +} + +ArrayTypeRepr *TypeRepr::getArrayTypeRepr() { + assert(Kind == TypeReprKind::Array && "Invalid TypeRepr convertion"); + return static_cast<ArrayTypeRepr *>(this); +} + void *TypeRepr::operator new(size_t Bytes, ASTContext &Context) { return Context.Allocate(Bytes); } diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp index 71f4e5e..545a042 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -36,7 +36,12 @@ static llvm::Value *emitCond(IRGenFunc &IRGF, Expr *E) { namespace { -class GenFunc: public ASTVisitor<GenFunc> { + class GenFunc: public ASTVisitor<GenFunc, + /* Decl */ bool, + /* Expr */ bool, + /* Stmt */ bool, + /* Pattern */ bool, + /* TypeRepr */ bool> { typedef ASTVisitor super; IRGenFunc &IRGF; @@ -44,24 +49,38 @@ class GenFunc: public ASTVisitor<GenFunc> { public: GenFunc(IRGenFunc &IRGF) : IRGF(IRGF) {} - bool visit(ValDecl *D) { + bool visitLetDecl(ValDecl *D) { + return IRGF.declare(D).isValid(); + } + + bool visitVarDecl(ValDecl *D) { return IRGF.declare(D).isValid(); } - bool visit(BlockStmt *S) { + bool visitBlockStmt(BlockStmt *S) { for (auto N : S->getNodes()) - if (!super::visit_(N)) - return false; + if (auto D = dynamic_cast<Decl *>(N)) { + if (!super::visit(D)) + return false; + } else if (auto E = dynamic_cast<Expr *>(N)) { + if (!super::visit(E)) + return false; + } else if (auto S = dynamic_cast<Stmt *>(N)) { + if (!super::visit(S)) + return false; + } else { + llvm_unreachable("Unexpected node."); + } return true; } - bool visit(BreakStmt *S) { + bool visitBreakStmt(BreakStmt *S) { // Get end block of top level loop auto EndBB = IRGF.LoopStack.getInfo().getEndBlock(); return IRGF.Builder.CreateBr(EndBB) != nullptr; } - bool visit(ReturnStmt *S) { + bool visitReturnStmt(ReturnStmt *S) { if (!IRGF.Fn->getReturnType()->isVoidTy()) { auto RetVal = codegenExpr(IRGF.IRGM, S->getValue()); IRGF.setRetVal(RetVal); @@ -70,7 +89,7 @@ public: return true; } - bool visit(IfStmt *S) { + bool visitIfStmt(IfStmt *S) { // Create basic blocks auto ThenBB = llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "if.then", IRGF.Fn); @@ -90,7 +109,7 @@ public: // Emit Then branch IRGF.Builder.SetInsertPoint(ThenBB); IRGF.IRGM.Lookup.push(); - if (!super::visit_(S->getThen())) + if (!super::visit(S->getThen())) return false; IRGF.IRGM.Lookup.pop(); if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr) @@ -100,7 +119,7 @@ public: if (S->hasElseBlock()) { IRGF.Builder.SetInsertPoint(ElseBB); IRGF.IRGM.Lookup.push(); - if (!super::visit_(S->getElse())) + if (!super::visit(S->getElse())) return false; IRGF.IRGM.Lookup.pop(); if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr) @@ -114,7 +133,7 @@ public: return true; } - bool visit(WhileStmt *S) { + bool visitWhileStmt(WhileStmt *S) { // Create loop blocks auto HeaderBlock = llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.header", IRGF.Fn); @@ -136,7 +155,7 @@ public: // Emit loop body IRGF.Builder.SetInsertPoint(BodyBlock); - if (!super::visit_(S->getBody())) + if (!super::visit(S->getBody())) return false; // Jump back to the condition if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr) @@ -148,7 +167,7 @@ public: return true; } - bool visit(ForStmt *S) { + bool visitForStmt(ForStmt *S) { // Create loop blocks auto HeaderBlock = llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.header", IRGF.Fn); @@ -178,7 +197,7 @@ public: // Emit loop body IRGF.Builder.SetInsertPoint(BodyBlock); - if (!super::visit_(S->getBody())) + if (!super::visit(S->getBody())) return false; // Jump back to the condition auto Ty = llvm::Type::getInt64Ty(IRGF.IRGM.LLVMContext); @@ -195,38 +214,38 @@ public: } - bool visit(FuncStmt *S) { return true; } - bool visit(RangeStmt *S) { return true; } - bool visit(SubscriptStmt *S) { return true; } - bool visit(ExternStmt *S) { return true; } - bool visit(FuncDecl *S) { return true; } - bool visit(ModuleDecl *D) { return true; } - bool visit(ParamDecl *D) { return true; } - bool visit(NumberLiteralExpr *E) { + bool visitFuncStmt(FuncStmt *S) { return true; } + bool visitRangeStmt(RangeStmt *S) { return true; } + bool visitSubscriptStmt(SubscriptStmt *S) { return true; } + bool visitExternStmt(ExternStmt *S) { return true; } + bool visitFuncDecl(FuncDecl *S) { return true; } + bool visitModuleDecl(ModuleDecl *D) { return true; } + bool visitParamDecl(ParamDecl *D) { return true; } + bool visitNumberLiteralExpr(NumberLiteralExpr *E) { return codegenExpr(IRGF.IRGM, E) != nullptr; } - bool visit(ArrayLiteralExpr *E) { + bool visitArrayLiteralExpr(ArrayLiteralExpr *E) { return codegenExpr(IRGF.IRGM, E) != nullptr; } - bool visit(IdentifierExpr *E) { + bool visitIdentifierExpr(IdentifierExpr *E) { return codegenExpr(IRGF.IRGM, E) != nullptr; } - bool visit(ParenExpr *E) { + bool visitParenExpr(ParenExpr *E) { return codegenExpr(IRGF.IRGM, E) != nullptr; } - bool visit(AssignExpr *E) { + bool visitAssignExpr(AssignExpr *E) { return codegenExpr(IRGF.IRGM, E) != nullptr; } - bool visit(InfixExpr *E) { + bool visitInfixExpr(InfixExpr *E) { return codegenExpr(IRGF.IRGM, E) != nullptr; } - bool visit(PrefixExpr *E) { + bool visitPrefixExpr(PrefixExpr *E) { return codegenExpr(IRGF.IRGM, E) != nullptr; } - bool visit(CallExpr *E) { + bool visitCallExpr(CallExpr *E) { return codegenExpr(IRGF.IRGM, E) != nullptr; } - bool visit(SubscriptExpr *E) { + bool visitSubscriptExpr(SubscriptExpr *E) { return codegenExpr(IRGF.IRGM, E) != nullptr; } }; @@ -235,6 +254,6 @@ public: bool irgen::genFunc(IRGenFunc &IRGF, FuncStmt *F) { GenFunc GF(IRGF); - return GF.ASTVisitor::visit_(F->getBody()); + return GF.ASTVisitor::visit(F->getBody()); } diff --git a/lib/Parser/ParseType.cpp b/lib/Parser/ParseType.cpp index 752dd95..852b527 100644 --- a/lib/Parser/ParseType.cpp +++ b/lib/Parser/ParseType.cpp @@ -12,36 +12,34 @@ using namespace dusk; - /// TypeRepr ::= /// IdentTypeRepr /// ArrayTypeRepr TypeRepr *Parser::parseTypeRepr() { switch (Tok.getKind()) { - case tok::kwInt: - case tok::kwVoid: - return parseIdentType(); - - default: - // Unexpected token - diagnose(Tok.getLoc()); - return nullptr; + case tok::kwInt: + case tok::kwVoid: + return parseIdentType(); + + default: + // Unexpected token + diagnose(Tok.getLoc()); + return nullptr; } } - /// IdentType ::= /// ':' identifier TypeRepr *Parser::parseIdentType() { auto Ty = Tok; switch (Tok.getKind()) { - case tok::kwInt: - case tok::kwVoid: - consumeToken(); - return parseArrayType(new(Context) IdentTypeRepr(Ty.getText())); - - default: - llvm_unreachable("Invalid parse method"); + case tok::kwInt: + case tok::kwVoid: + consumeToken(); + return parseArrayType(new (Context) IdentTypeRepr(Ty.getText())); + + default: + llvm_unreachable("Invalid parse method"); } } @@ -50,38 +48,26 @@ TypeRepr *Parser::parseIdentType() { /// '[' Expr ']' ArrayType TypeRepr *Parser::parseArrayType(TypeRepr *Base) { switch (Tok.getKind()) { - case tok::comma: - case tok::assign: - case tok::r_paren: - case tok::semicolon: - return Base; - - case tok::l_bracket: { - auto L = consumeToken(); - Expr *E = nullptr; - if (Tok.isNot(tok::number_literal)) { - if (Tok.is(tok::r_bracket)) { - diagnose(Tok.getLoc(), diag::invalid_array_size); - consumeToken(); - } else { - diagnose(Tok.getLoc(), diag::expected_array_size); - } - - } else { - E = parseNumberLiteralExpr(); - } - - if (!consumeIf(tok::r_bracket)) { - diagnose(Tok.getLoc(), diag::expected_r_bracket) - .fixIt("]", Tok.getLoc()); - return nullptr; - } - auto S = new(Context) SubscriptStmt(E, L, PreviousLoc); - return parseArrayType(new(Context) ArrayTypeRepr(Base, S)); + case tok::comma: + case tok::assign: + case tok::r_paren: + case tok::semicolon: + return Base; + + case tok::l_bracket: { + auto L = consumeToken(); + Expr *E = parseExpr(); + + if (!consumeIf(tok::r_bracket)) { + diagnose(Tok.getLoc(), diag::expected_r_bracket).fixIt("]", Tok.getLoc()); + return nullptr; } - - default: - llvm_unreachable("Unexpected token."); + auto S = new (Context) SubscriptStmt(E, L, PreviousLoc); + return parseArrayType(new (Context) ArrayTypeRepr(Base, S)); + } + + default: + llvm_unreachable("Unexpected token."); } } diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 6604f16..3272d7b 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -6,6 +6,7 @@ set(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/TypeCheckExpr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TypeCheckPattern.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TypeCheckStmt.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TypeCheckType.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TypeResolver.cpp ${SOURCE} PARENT_SCOPE diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 69c741c..cc7e7f5 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -17,6 +17,7 @@ #include "dusk/AST/TypeRepr.h" #include "dusk/AST/Diagnostics.h" #include "dusk/AST/NameLookup.h" +#include "dusk/Runtime/RuntimeFuncs.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallVector.h" @@ -85,8 +86,7 @@ void Sema::declareFuncs() { } void Sema::typeCheck() { - TypeChecker TC(*this, DeclCtx, Ctx, Diag); - Ctx.getRootModule()->walk(TC); + TypeChecker(*this, DeclCtx, Ctx, Diag).typeCheckDecl(Ctx.getRootModule()); } static Type *typeReprResolve(Sema &S, ASTContext &C, IdentTypeRepr *TyRepr) { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index ada8459..c6a54e6 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -12,107 +12,206 @@ #include "dusk/AST/Diagnostics.h" #include "dusk/AST/Scope.h" #include "dusk/AST/NameLookup.h" +#include "dusk/AST/ASTVisitor.h" #include "dusk/Sema/Sema.h" +#include "dusk/Sema/TypeResolver.h" using namespace dusk; using namespace sema; -bool TypeChecker::preWalkLetDecl(LetDecl *D) { - // Check for initialization value - if (!D->hasValue()) { - diagnose(D->getLocStart(), diag::expected_default_initialization); - return false; - } - - if (D->hasTypeRepr()) - D->setType(S.typeReprResolve(D->getTypeRepr())); - return true; -} +namespace { -bool TypeChecker::preWalkVarDecl(VarDecl *D) { - if (!D->hasValue() && !D->hasTypeRepr()) { - diagnose(D->getLocEnd(), diag::expected_type_specifier); - return false; +class DeclChecker : public DeclVisitor<DeclChecker> { + TypeChecker &TC; + + typedef ASTVisitor super; + + friend super; + +public: + DeclChecker(TypeChecker &TC) : TC(TC) {} + +private: + + void visitLetDecl(LetDecl *D) { + TC.Lookup.declareLet(D); + if (!D->hasValue()) { + TC.diagnose(D->getLocEnd(), diag::expected_default_initialization); + return; + } + + if (D->hasTypeRepr()) + TC.typeCheckType(D->getTypeRepr()); + + auto Val = TC.typeCheckExpr(D->getValue()); + + if (D->hasTypeRepr()) + TC.typeCheckEquals(D->getTypeRepr()->getType(), Val->getType()); + D->setValue(Val); + D->setType(Val->getType()); } - - if (D->hasTypeRepr()) - D->setType(S.typeReprResolve(D->getTypeRepr())); - return true; -} - -bool TypeChecker::preWalkParamDecl(ParamDecl *D) { - if (D->hasTypeRepr()) - D->setType(S.typeReprResolve(D->getTypeRepr())); - return false; -} - -bool TypeChecker::preWalkFuncDecl(FuncDecl *D) { - D->setType(S.typeReprResolve(D)); - return true; -} - -bool TypeChecker::preWalkModuleDecl(ModuleDecl *D) { return true; } - -bool TypeChecker::postWalkLetDecl(LetDecl *D) { - // Infer type - if (!D->getType()) - D->setType(D->getValue()->getType()); - - // Check if resolved both types - if (!D->getType() || !D->getValue()->getType()) - return false; - - if (!D->getType()->isValueType()) { - diagnose(D->getValue()->getLocStart(), - diag::expected_value_type_expression); - return false; + + void visitVarDecl(VarDecl *D) { + TC.Lookup.declareVar(D); + if (D->hasTypeRepr()) + TC.typeCheckType(D->getTypeRepr()); + + if (!D->hasValue()) { + if (!D->hasTypeRepr()) + TC.diagnose(D->getLocEnd(), diag::expected_type_annotation); + else + D->setType(D->getTypeRepr()->getType()); + return; + } + + auto Val = TC.typeCheckExpr(D->getValue()); + if (D->hasTypeRepr()) + TC.typeCheckEquals(D->getTypeRepr()->getType(), Val->getType()); + + D->setValue(Val); + D->setType(Val->getType()); } - // Validate types - if (D->getType()->isClassOf(D->getValue()->getType())) { - // If types match, declare - if (DeclCtx.declareLet(D)) { - return true; - } else { - diagnose(D->getLocStart(), diag::redefinition_of_identifier); - return false; + void visitParamDecl(ParamDecl *D) { + if (D->hasTypeRepr()) { + TC.typeCheckType(D->getTypeRepr()); + D->setType(D->getTypeRepr()->getType()); + return; } } - - diagnose(D->getValue()->getLocStart(), diag::type_missmatch); - return false; -} - -bool TypeChecker::postWalkVarDecl(VarDecl *D) { - // Infer type - if (!D->getType() && D->hasValue()) - D->setType(D->getValue()->getType()); - - // Check if resolved both types - if (!D->getType() || (D->hasValue() && !D->getValue()->getType())) - return false; - - if (!D->getType()->isValueType()) { - diagnose(D->getValue()->getLocStart(), - diag::expected_value_type_expression); - return false; + + void visitFuncDecl(FuncDecl *D) { + PushScopeRAII Push(TC.ASTScope, Scope::FnProtoScope); + TC.Lookup.declareFunc(D); + TC.typeCheckPattern(D->getArgs()); + if (D->hasTypeRepr()) + TC.typeCheckType(D->getTypeRepr()); } - // Validate types - if (!D->hasValue() || D->getType()->isClassOf(D->getValue()->getType())) - // If types match, declare - return DeclCtx.declareVar(D); - - diagnose(D->getValue()->getLocStart(), diag::type_missmatch); - return false; -} + void visitModuleDecl(ModuleDecl *D) { + for (auto N : D->getContents()) { + if (auto D = dynamic_cast<Decl *>(N)) + typeCheckDecl(D); + else if (auto E = dynamic_cast<Expr *>(N)) + TC.diagnose(E->getLocStart(), diag::unexpected_expresssion); + else if (auto S = dynamic_cast<Stmt *>(N)) + TC.typeCheckStmt(S); + else + llvm_unreachable("Unexpected node type."); + } + } + +public: + void typeCheckDecl(Decl *D) { + if (TC.Lookup.contains(D->getName())) + TC.diagnose(D->getLocStart(), diag::redefinition_of_identifier); + + super::visit(D); + } +}; -bool TypeChecker::postWalkParamDecl(ParamDecl *D) { - return D->getType() != nullptr; -} +} // anonymous namespace -bool TypeChecker::postWalkFuncDecl(FuncDecl *D) { - return (D->getType()) != nullptr; +void TypeChecker::typeCheckDecl(Decl *D) { + DeclChecker(*this).typeCheckDecl(D); } -bool TypeChecker::postWalkModuleDecl(ModuleDecl *D) { return true; } +//bool TypeChecker::preWalkLetDecl(LetDecl *D) { +// // Check for initialization value +// if (!D->hasValue()) { +// diagnose(D->getLocStart(), diag::expected_default_initialization); +// return false; +// } +// +// if (D->hasTypeRepr()) +// D->setType(S.typeReprResolve(D->getTypeRepr())); +// return true; +//} +// +//bool TypeChecker::preWalkVarDecl(VarDecl *D) { +// if (!D->hasValue() && !D->hasTypeRepr()) { +// diagnose(D->getLocEnd(), diag::expected_type_specifier); +// return false; +// } +// +// if (D->hasTypeRepr()) +// D->setType(S.typeReprResolve(D->getTypeRepr())); +// return true; +//} +// +//bool TypeChecker::preWalkParamDecl(ParamDecl *D) { +// if (D->hasTypeRepr()) +// D->setType(S.typeReprResolve(D->getTypeRepr())); +// return false; +//} +// +//bool TypeChecker::preWalkFuncDecl(FuncDecl *D) { +// D->setType(S.typeReprResolve(D)); +// return true; +//} +// +//bool TypeChecker::preWalkModuleDecl(ModuleDecl *D) { return true; } +// +//bool TypeChecker::postWalkLetDecl(LetDecl *D) { +// // Infer type +// if (!D->getType()) +// D->setType(D->getValue()->getType()); +// +// // Check if resolved both types +// if (!D->getType() || !D->getValue()->getType()) +// return false; +// +// if (!D->getType()->isValueType()) { +// diagnose(D->getValue()->getLocStart(), +// diag::expected_value_type_expression); +// return false; +// } +// +// // Validate types +// if (D->getType()->isClassOf(D->getValue()->getType())) { +// // If types match, declare +// if (Lookup.declareLet(D)) { +// return true; +// } else { +// diagnose(D->getLocStart(), diag::redefinition_of_identifier); +// return false; +// } +// } +// +// diagnose(D->getValue()->getLocStart(), diag::type_missmatch); +// return false; +//} +// +//bool TypeChecker::postWalkVarDecl(VarDecl *D) { +// // Infer type +// if (!D->getType() && D->hasValue()) +// D->setType(D->getValue()->getType()); +// +// // Check if resolved both types +// if (!D->getType() || (D->hasValue() && !D->getValue()->getType())) +// return false; +// +// if (!D->getType()->isValueType()) { +// diagnose(D->getValue()->getLocStart(), +// diag::expected_value_type_expression); +// return false; +// } +// +// // Validate types +// if (!D->hasValue() || D->getType()->isClassOf(D->getValue()->getType())) +// // If types match, declare +// return Lookup.declareVar(D); +// +// diagnose(D->getValue()->getLocStart(), diag::type_missmatch); +// return false; +//} +// +//bool TypeChecker::postWalkParamDecl(ParamDecl *D) { +// return D->getType() != nullptr; +//} +// +//bool TypeChecker::postWalkFuncDecl(FuncDecl *D) { +// return (D->getType()) != nullptr; +//} +// +//bool TypeChecker::postWalkModuleDecl(ModuleDecl *D) { return true; } diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index 7f5f8f8..b78c326 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -12,104 +12,451 @@ #include "dusk/AST/Diagnostics.h" #include "dusk/AST/NameLookup.h" #include "dusk/Sema/Sema.h" +#include "dusk/AST/ASTVisitor.h" +#include "dusk/AST/ASTWalker.h" +#include "dusk/AST/NameLookup.h" +#include "dusk/AST/ASTWalker.h" using namespace dusk; using namespace sema; -bool TypeChecker::postWalkNumberLiteralExpr(NumberLiteralExpr *E) { - return true; -} +namespace { -bool TypeChecker::postWalkArrayLiteralExpr(ArrayLiteralExpr *E) { - E->setType(S.typeReprResolve(E)); - return true; -} - -bool TypeChecker::postWalkIdentifierExpr(IdentifierExpr *E) { - // Check if it's a value type - if (auto D = DeclCtx.getVal(E->getName())) { - E->setType(D->getType()); - return true; +/// Perform expression solution. +/// +/// Operates on a single expression tree and tries to simplify is as much +/// as it can. Most of simplification operations include value substitutions +/// (e.g. substitute indexed element in array with the element itself) and/or +/// an identifier with a value it refers to. +/// +/// \note Only constants can be substituted. +class ExprSolver : public ASTWalker { + TypeChecker &TC; + +public: + ExprSolver(TypeChecker &TC) : TC(TC) {} + + std::pair<bool, Expr *> preWalkExpr(Expr *E) { + // Skip all solved expressions + return {!E->getSolved(), E}; } - // Check if it's a function reference - if (auto Fn = DeclCtx.getFunc(E->getName())) { - E->setType(Fn->getType()); - return true; + + Expr *postWalkExpr(Expr *E) { + switch (E->getKind()) { + // Literals can't be solved anymore + case ExprKind::NumberLiteral: + case ExprKind::ArrayLiteral: + + // Assignements and calls must be executed during runtime + case ExprKind::Assign: + case ExprKind::Call: + break; + + case ExprKind::Identifier: + E = solveIdentifierExpr(static_cast<IdentifierExpr *>(E)); + break; + + case ExprKind::Paren: + // Simply extract paranthesized expression. + E = static_cast<ParenExpr *>(E)->getExpr(); + break; + + case ExprKind::Infix: + E = solveInfixExpr(static_cast<InfixExpr *>(E)); + break; + + case ExprKind::Prefix: + E = solvePrefixExpr(static_cast<PrefixExpr *>(E)); + break; + + case ExprKind::Subscript: + E = solveSubscriptExpr(static_cast<SubscriptExpr *>(E)); + break; + } + // Set each expression to solved at the end of traversal. + E->setSolved(true); + return E; + } + +private: + + // MARK: - Solvers + + Expr *solveIdentifierExpr(IdentifierExpr *E) { + // Check if we have a variable with the name. + if (auto D = dynamic_cast<ValDecl *>(TC.Lookup.getVal(E->getName()))) { + // We can only substitute immutable values. + if (!D->isLet()) + return E; + + else if (auto Val = dynamic_cast<NumberLiteralExpr *>(D->getValue())) + return Val; + else if (auto Val = dynamic_cast<ArrayLiteralExpr *>(D->getValue())) + return Val; + } + return E; + } + + Expr *solveInfixExpr(InfixExpr *E) { + auto L = dynamic_cast<NumberLiteralExpr *>(E); + auto R = dynamic_cast<NumberLiteralExpr *>(E); + // Check if both sides are number literals + // + // NOTE: we can perform arithmetics only with a signle type being integer. + // In future this resolution will need fix for other types, that might + // also be applied to these operands. + if (!L || !R) + return E; + + int64_t Value = 0; + switch (E->getOp().getKind()) { + case tok::land: + Value = L->getValue() && R->getValue(); + break; + + case tok::lor: + Value = L->getValue() || R->getValue(); + break; + + case tok::plus: + Value = L->getValue() + R->getValue(); + break; + + case tok::minus: + Value = L->getValue() - R->getValue(); + break; + + case tok::multipy: + Value = L->getValue() * R->getValue(); + break; + + case tok::divide: + Value = L->getValue() / R->getValue(); + break; + + case tok::mod: + Value = L->getValue() % R->getValue(); + break; + + default: + llvm_unreachable("Unexpected infix operator."); + } + return new (TC.Ctx) NumberLiteralExpr(Value, SMRange{}); + } + + Expr *solvePrefixExpr(PrefixExpr *E) { + // Check if destination value is number literal + // + // NOTE: we can perform arithmetics only with a signle type being integer. + // In future this resolution will need fix for other types, that might + // also be applied to these operands. + auto Dest = dynamic_cast<NumberLiteralExpr *>(E); + if (!Dest) + return E; + + int64_t Value = 0; + switch (E->getOp().getKind()) { + case tok::lnot: + Value = !Dest->getValue(); + break; + + case tok::minus: + Value = -Dest->getValue(); + break; + + default: + llvm_unreachable("Unexpectd prefixoperator."); + } + return new (TC.Ctx) NumberLiteralExpr(Value, SMRange{}); + } + + Expr *solveSubscriptExpr(SubscriptExpr *E) { + // Check if both destination is an array and index a number literal. + // + // NOTE: we can perform subscript only with a arrays. In future this will + // need update to support subscript operand on other types as well. + auto Arr = dynamic_cast<ArrayLiteralExpr *>(E->getBase()); + auto Idx = dynamic_cast<NumberLiteralExpr *>( + E->getSubscript()->getSubscripStmt()->getValue()); + if (!Arr || !Idx) + return E; + + auto Values = Arr->getValues()->getExprPattern(); + if (Values->count() < Idx->getValue() || Idx->getValue() < 0) { + TC.diagnose(Idx->getLocStart(), diag::array_index_out_of_bounds); + return E; + } + + return Values->getValues()[Idx->getValue()]; + } +}; + +/// Performs type checking and resolution of expressions. +class ExprChecker : public ExprVisitor<ExprChecker, Expr *> { + TypeChecker &TC; + + typedef ASTVisitor super; + + friend super; + +public: + ExprChecker(TypeChecker &TC) : TC(TC) {} + +private: + + // MARK: - Visitors + + Expr *visitNumberLiteralExpr(NumberLiteralExpr *E) { + // Number literal is always an integer type. + E->setType(TC.Ctx.getIntType()); + return E; } - diagnose(E->getLocStart(), diag::undefined_identifier); - return false; -} -bool TypeChecker::postWalkParenExpr(ParenExpr *E) { - E->setType(E->getExpr()->getType()); - return true; -} + Expr *visitArrayLiteralExpr(ArrayLiteralExpr *E) { + if (!E->getValues()->count()) { + TC.diagnose(E->getLocStart(), diag::invalid_array_size); + return E; + } + + TC.typeCheckPattern(E->getValues()); + auto Ty = E->getValues()->getType()->getPatternType(); + if (!Ty) + return E; + + auto BaseTy = Ty->getItems().front(); + // All items al the array must be of the same type + for (auto T : Ty->getItems()) + if (!TC.typeCheckEquals(BaseTy, T)) + return E; -bool TypeChecker::postWalkAssignExpr(AssignExpr *E) { - auto Ident = dynamic_cast<IdentifierExpr *>(E->getDest()); - // Check if its an assignable expression - if (!Ident || DeclCtx.getFunc(Ident->getName())) { - diagnose(E->getDest()->getLocStart(), diag::expression_not_assignable); - return false; + auto ArrTy = new (TC.Ctx) ArrayType(BaseTy, E->getValues()->count()); + E->setType(ArrTy); + return E; } - // Check if it is a variable - if (DeclCtx.getVal(Ident->getName()) && !DeclCtx.getVar(Ident->getName())) { - diagnose(E->getDest()->getLocStart(), diag::cannot_reassign_let_value); + + Expr *visitIdentifierExpr(IdentifierExpr *E) { + if (auto D = TC.Lookup.getVal(E->getName())) { + if (D->getType()) + E->setType(D->getType()); + + } else if (auto Fn = TC.Lookup.getFunc(E->getName())) { + if (Fn->getType()) + E->setType(Fn->getType()); + + } else { + TC.diagnose(E->getLocStart(), diag::undefined_identifier); + } + + return E; } - // Check type match. - if (E->getDest()->getType()->isClassOf(E->getSource()->getType())) { - E->setType(E->getDest()->getType()); - return true; + Expr *visitParenExpr(ParenExpr *E) { + // Simplt extract paranthesizes expression. + return E->getExpr(); } - diagnose(E->getDest()->getLocEnd(), diag::type_missmatch); - return false; -} - -bool TypeChecker::postWalkInfixExpr(InfixExpr *E) { - if (!E->getLHS()->getType() || !E->getRHS()->getType()) - return false; - // Check type match. - if (E->getLHS()->getType()->isClassOf(E->getRHS()->getType())) { - E->setType(E->getLHS()->getType()); - return true; + Expr *visitAssignExpr(AssignExpr *E) { + E->setDest(typeCheckExpr(E->getDest(), /* Solve */false)); + E->setSource(typeCheckExpr(E->getSource())); + + auto DTy = E->getDest()->getType(); + auto STy = E->getSource()->getType(); + if (!DTy || !STy) + return E; + + // Check if we have valid destination node. + if (auto Dest = dynamic_cast<IdentifierExpr *>(E->getDest())) { + if (auto D = dynamic_cast<ValDecl *>(TC.Lookup.getVal(Dest->getName()))) + if (D->isLet()) { + TC.diagnose(E->getLocStart(), diag::cannot_reassign_let_value); + return E; + } + } else if (dynamic_cast<SubscriptExpr *>(E->getDest()) == nullptr) { + TC.diagnose(E->getLocStart(), diag::unexpected_expresssion); + return E; + } + + if (!TC.typeCheckEquals(DTy, STy)) { + TC.diagnose(E->getLocStart(), diag::type_missmatch); + return E; + } + + E->setType(DTy); + return E; } - diagnose(E->getOp().getLoc(), diag::type_missmatch); - return false; -} -bool TypeChecker::postWalkPrefixExpr(PrefixExpr *E) { - E->setType(E->getDest()->getType()); - return true; -} + Expr *visitInfixExpr(InfixExpr *E) { + E->setLHS(typeCheckExpr(E->getLHS())); + E->setRHS(typeCheckExpr(E->getRHS())); + + auto LTy = E->getLHS()->getType(); + auto RTy = E->getRHS()->getType(); + if (!LTy || !RTy) + return E; -bool TypeChecker::postWalkCallExpr(CallExpr *E) { - auto FTy = dynamic_cast<FunctionType *>(E->getCallee()->getType()); + // We only support arithmetics with integer types + if (!LTy->isClassOf(TC.Ctx.getIntType()) || + !RTy->isClassOf(TC.Ctx.getIntType())) { + TC.diagnose(E->getLocStart(), diag::invalid_operand_type); + return E; + } + + E->setType(LTy); + return E; + } - // Check if references a function - if (!FTy) { - diagnose(E->getCallee()->getLocStart(), diag::func_call_non_func_type); - return false; + Expr *visitPrefixExpr(PrefixExpr *E) { + E->setDest(typeCheckExpr(E->getDest())); + // We only support integer types with any and all prefix operations. + if (auto Ty = dynamic_cast<IntType *>(E->getDest()->getType())) + E->setType(Ty); + return E; } - // Check is arguments are the same as in proto - if (E->getArgs()->getType()->isClassOf(FTy->getArgsType())) { - E->setType(FTy->getRetType()); - return true; - } else { - diagnose(E->getArgs()->getLocStart(), diag::arguments_mismatch); - return false; + Expr *visitCallExpr(CallExpr *E) { + E->setCallee(typeCheckExpr(E->getCallee())); + TC.typeCheckPattern(E->getArgs()); + + // Calle must be function type. + auto FnTy = dynamic_cast<FunctionType *>(E->getCallee()->getType()); + auto ArgsTy = E->getArgs()->getType(); + if (!FnTy || !ArgsTy) + return E; + + if (!TC.typeCheckEquals(FnTy->getFuncType()->getArgsType(), ArgsTy)) + return E; + + E->setType(FnTy->getFuncType()->getRetType()); + return E; } -} -bool TypeChecker::postWalkSubscriptExpr(SubscriptExpr *E) { - if (E->getBase()->getType()->getKind() != TypeKind::Array) { - diagnose(E->getBase()->getLocStart(), diag::subscripted_value_not_array); - return false; - } else { - auto ArrTy = static_cast<ArrayType *>(E->getBase()->getType()); - E->setType(ArrTy->getBaseType()); - return true; + Expr *visitSubscriptExpr(SubscriptExpr *E) { + E->setBase(TC.typeCheckExpr(E->getBase())); + TC.typeCheckStmt(E->getSubscript()); + + // Destination must be array type. + auto ArrTy = dynamic_cast<ArrayType *>(E->getBase()->getType()); + if (!ArrTy) + return E; + + E->setType(ArrTy->getArrayType()->getBaseType()); + return E; } + +public: + Expr *typeCheckExpr(Expr *E, bool Solve = true) { + E = super::visit(E); + + // Solve expression if type resolution succeeded. + if (E->getType() && Solve) { + ExprSolver Solver(TC); + E = E->walk(Solver); + } + + return E; + } +}; + +} // anonymous namesapce + +Expr *TypeChecker::typeCheckExpr(Expr *E) { + return ExprChecker(*this).typeCheckExpr(E); } + +//bool TypeChecker::postWalkNumberLiteralExpr(NumberLiteralExpr *E) { +// return true; +//} +// +//bool TypeChecker::postWalkArrayLiteralExpr(ArrayLiteralExpr *E) { +// E->setType(S.typeReprResolve(E)); +// return true; +//} +// +//bool TypeChecker::postWalkIdentifierExpr(IdentifierExpr *E) { +// // Check if it's a value type +// if (auto D = Lookup.getVal(E->getName())) { +// E->setType(D->getType()); +// return true; +// } +// // Check if it's a function reference +// if (auto Fn = Lookup.getFunc(E->getName())) { +// E->setType(Fn->getType()); +// return true; +// } +// diagnose(E->getLocStart(), diag::undefined_identifier); +// return false; +//} +// +//bool TypeChecker::postWalkParenExpr(ParenExpr *E) { +// E->setType(E->getExpr()->getType()); +// return true; +//} +// +//bool TypeChecker::postWalkAssignExpr(AssignExpr *E) { +// auto Ident = dynamic_cast<IdentifierExpr *>(E->getDest()); +// // Check if its an assignable expression +// if (!Ident || Lookup.getFunc(Ident->getName())) { +// diagnose(E->getDest()->getLocStart(), diag::expression_not_assignable); +// return false; +// } +// // Check if it is a variable +// if (Lookup.getVal(Ident->getName()) && !Lookup.getVar(Ident->getName())) { +// diagnose(E->getDest()->getLocStart(), diag::cannot_reassign_let_value); +// } +// +// // Check type match. +// if (E->getDest()->getType()->isClassOf(E->getSource()->getType())) { +// E->setType(E->getDest()->getType()); +// return true; +// } +// diagnose(E->getDest()->getLocEnd(), diag::type_missmatch); +// return false; +//} +// +//bool TypeChecker::postWalkInfixExpr(InfixExpr *E) { +// if (!E->getLHS()->getType() || !E->getRHS()->getType()) +// return false; +// +// // Check type match. +// if (E->getLHS()->getType()->isClassOf(E->getRHS()->getType())) { +// E->setType(E->getLHS()->getType()); +// return true; +// } +// diagnose(E->getOp().getLoc(), diag::type_missmatch); +// return false; +//} +// +//bool TypeChecker::postWalkPrefixExpr(PrefixExpr *E) { +// E->setType(E->getDest()->getType()); +// return true; +//} +// +//bool TypeChecker::postWalkCallExpr(CallExpr *E) { +// auto FTy = dynamic_cast<FunctionType *>(E->getCallee()->getType()); +// +// // Check if references a function +// if (!FTy) { +// diagnose(E->getCallee()->getLocStart(), diag::func_call_non_func_type); +// return false; +// } +// +// // Check is arguments are the same as in proto +// if (E->getArgs()->getType()->isClassOf(FTy->getArgsType())) { +// E->setType(FTy->getRetType()); +// return true; +// } else { +// diagnose(E->getArgs()->getLocStart(), diag::arguments_mismatch); +// return false; +// } +//} +// +//bool TypeChecker::postWalkSubscriptExpr(SubscriptExpr *E) { +// if (E->getBase()->getType()->getKind() != TypeKind::Array) { +// diagnose(E->getBase()->getLocStart(), diag::subscripted_value_not_array); +// return false; +// } else { +// auto ArrTy = static_cast<ArrayType *>(E->getBase()->getType()); +// E->setType(ArrTy->getBaseType()); +// return true; +// } +//} diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 58a1106..3b9d88a 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -12,6 +12,7 @@ #include "dusk/AST/Diagnostics.h" #include "dusk/AST/Scope.h" #include "dusk/AST/NameLookup.h" +#include "dusk/AST/ASTVisitor.h" #include "dusk/Sema/Sema.h" #include "llvm/ADT/SmallVector.h" #include <memory> @@ -19,35 +20,82 @@ using namespace dusk; using namespace sema; -bool TypeChecker::preWalkVarPattern(VarPattern *P) { - return P->getType() == nullptr; -} +namespace { -bool TypeChecker::preWalkExprPattern(ExprPattern *P) { - return P->getType() == nullptr; -} +/// Pattern type checker. +class PatternChecker : public PatternVisitor<PatternChecker> { + TypeChecker &TC; + + typedef ASTVisitor super; + + friend super; -bool TypeChecker::postWalkVarPattern(VarPattern *P) { - llvm::SmallVector<Type *, 128> Ty; - for (auto V : P->getVars()) { - if (!V->getType()) - return false; - Ty.push_back(V->getType()); +public: + PatternChecker(TypeChecker &TC) : TC(TC) {} + +private: + void visitExprPattern(ExprPattern *P) { + llvm::SmallVector<Type *, 128> Tys; + for (auto &E : P->getValues()) { + E = TC.typeCheckExpr(E); + Tys.push_back(E->getType()); + if (!Tys.back()) + return; + } + P->setType(new (TC.Ctx) PatternType(std::move(Tys))); } - - P->setType(new(Ctx) PatternType(std::move(Ty))); - return true; -} -bool TypeChecker::postWalkExprPattern(ExprPattern *P) { - llvm::SmallVector<Type *, 128> Ty; - for (auto V : P->getValues()) { - if (!V->getType()) - return false; - Ty.push_back(V->getType()); + void visitVarPattern(VarPattern *P) { + llvm::SmallVector<Type *, 128> Tys; + for (auto D : P->getVars()) { + TC.typeCheckDecl(D); + Tys.push_back(D->getType()); + if (!Tys.back()) + return; + } + P->setType(new (TC.Ctx) PatternType(std::move(Tys))); } - - P->setType(new(Ctx) PatternType(std::move(Ty))); - return true; + +public: + void typeCheckPattern(Pattern *P) { super::visit(P); } +}; + +} // anonymous namespace + +void TypeChecker::typeCheckPattern(Pattern *P) { + PatternChecker(*this).typeCheckPattern(P); } +// bool TypeChecker::preWalkVarPattern(VarPattern *P) { +// return P->getType() == nullptr; +//} +// +// bool TypeChecker::preWalkExprPattern(ExprPattern *P) { +// return P->getType() == nullptr; +//} +// +// bool TypeChecker::postWalkVarPattern(VarPattern *P) { +// llvm::SmallVector<Type *, 128> Ty; +// for (auto V : P->getVars()) { +// if (!V->getType()) +// return false; +// Ty.push_back(V->getType()); +// } +// +// P->setType(new(Ctx) PatternType(std::move(Ty))); +// return true; +//} +// +// bool TypeChecker::postWalkExprPattern(ExprPattern *P) { +// llvm::SmallVector<Type *, 128> Ty; +// for (auto V : P->getValues()) { +// if (!V->getType()) +// return false; +// Ty.push_back(V->getType()); +// } +// +// P->setType(new(Ctx) PatternType(std::move(Ty))); +// return true; +//} +// + diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 82a7b51..8b1322d 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -12,143 +12,265 @@ #include "dusk/AST/Diagnostics.h" #include "dusk/AST/Scope.h" #include "dusk/AST/NameLookup.h" +#include "dusk/AST/ASTVisitor.h" + +#include "TypeChecker.h" using namespace dusk; using namespace sema; -bool TypeChecker::preWalkBlockStmt(BlockStmt *S) { - DeclCtx.push(); - if (auto Fn = dynamic_cast<FuncStmt *>(Scp.top().getStmt())) { - auto Proto = static_cast<FuncDecl *>(Fn->getPrototype()); - auto Args = static_cast<VarPattern *>(Proto->getArgs()); - for (auto Arg : Args->getVars()) - if (!DeclCtx.declareVar(Arg)) { - diagnose(Args->getLocStart(), diag::redefinition_of_identifier); - return false; - } - } +class StmtChecker : public StmtVisitor<StmtChecker> { + typedef ASTVisitor super; + friend super; - if (auto For = dynamic_cast<ForStmt *>(Scp.top().getStmt())) { - if (!For->getRange()->walk(*this)) - return false; - auto Rng = static_cast<RangeStmt *>(For->getRange()); - auto Iter = static_cast<ParamDecl *>(For->getIter()); - Iter->setType(Rng->getStart()->getType()); - DeclCtx.declareLet(Iter); - } - Scp.push(Scope(&Scp.top(), Scope::BlockScope, S)); - return true; -} + TypeChecker &TC; -bool TypeChecker::preWalkExternStmt(ExternStmt *S) { - Scp.push(Scope(&Scp.top(), Scope::FnScope, S)); - DeclCtx.push(); - return true; -} +public: + StmtChecker(TypeChecker &TC) : TC(TC) {} -bool TypeChecker::preWalkForStmt(ForStmt *S) { - Scp.push(Scope(&Scp.top(), Scope::ControlScope | Scope::BreakScope, S)); - return true; -} - -bool TypeChecker::preWalkFuncStmt(FuncStmt *S) { - Scp.push(Scope(&Scp.top(), Scope::FnScope, S)); - return true; -} +private: + void visitBreakStmt(BreakStmt *S) { + if (!TC.ASTScope.isBreakScope()) + TC.diagnose(S->getLocStart(), diag::unexpected_break_stmt); + } -bool TypeChecker::preWalkIfStmt(IfStmt *S) { - Scp.push(Scope(&Scp.top(), Scope::ControlScope, S)); - return true; -} + void visitReturnStmt(ReturnStmt *S) { + // Return cannot occur outside of function scope + if (!TC.ASTScope.isFnScope()) + TC.diagnose(S->getLocStart(), diag::unexpected_return_stmt); -bool TypeChecker::preWalkWhileStmt(WhileStmt *S) { - Scp.push(Scope(&Scp.top(), Scope::ControlScope | Scope::BreakScope, S)); - return true; -} + // Extract function type + auto Fn = TC.ASTScope.getFnParent()->getStmt()->getFuncStmt(); + auto FnTy = Fn->getPrototype()->getType()->getFuncType(); -bool TypeChecker::postWalkBreakStmt(BreakStmt *S) { - if (Scp.top().isBreakScope() || Scp.top().getBreakParent() != nullptr) - return true; - diagnose(S->getLocStart(), diag::unexpected_break_stmt); - return false; -} + // Check if valid void type + if (!S->hasValue()) { + if (!FnTy->getRetType()->isVoidType()) + TC.diagnose(S->getLocStart(), diag::return_missing_value); + return; + } -bool TypeChecker::postWalkReturnStmt(ReturnStmt *S) { - if (!Scp.top().isFnScope() && Scp.top().getFnParent() == nullptr) { - diagnose(S->getLocStart(), diag::unexpected_return_stmt); - return false; + // Resolve return value and type + auto E = TC.typeCheckExpr(S->getValue()); + TC.typeCheckEquals(FnTy->getRetType(), E->getType()); + S->setValue(E); } - auto &FnScp = Scp.top().isFnScope() ? Scp.top() : *Scp.top().getFnParent(); - auto F = static_cast<FuncStmt *>(FnScp.getStmt()); - auto FD = static_cast<FuncDecl *>(F->getPrototype()); - auto FTy = static_cast<FunctionType *>(FD->getType()); + void visitSubscriptStmt(SubscriptStmt *S) { + auto Val = TC.typeCheckExpr(S->getValue()); + S->setValue(Val); + } - if (!S->hasValue()) { - if (FTy->getRetType()->isVoidType()) - return true; - diagnose(S->getLocStart(), diag::return_missing_value); - return false; + void visitRangeStmt(RangeStmt *S) { + auto Start = TC.typeCheckExpr(S->getStart()); + auto End = TC.typeCheckExpr(S->getStart()); + + // Both range value must be of same type + TC.typeCheckEquals(Start->getType(), End->getType()); + S->setStart(Start); + S->setEnd(End); } - if (FTy->getRetType()->isClassOf(S->getValue()->getType())) - return true; + void visitBlockStmt(BlockStmt *S) { + PushScopeRAII Push(TC.ASTScope, Scope::BlockScope, S); + for (auto &N : S->getNodes()) { + if (auto D = dynamic_cast<Decl *>(N)) + TC.typeCheckDecl(D); - diagnose(S->getLocStart(), diag::type_missmatch); - return false; -} + else if (auto E = dynamic_cast<Expr *>(N)) + N = TC.typeCheckExpr(E); + + else if (auto S = dynamic_cast<Stmt *>(N)) + typeCheckStmt(S); -bool TypeChecker::postWalkRangeStmt(RangeStmt *S) { - if (!S->getStart()->getType()->isValueType()) { - diagnose(S->getStart()->getLocStart(), - diag::expected_value_type_expression); - return false; + else + llvm_unreachable("Unexpected node type."); + } } - if (!S->getEnd()->getType()->isValueType()) { - diagnose(S->getEnd()->getLocStart(), diag::expected_value_type_expression); - return false; + + void visitExternStmt(ExternStmt *S) { + PushScopeRAII Push(TC.ASTScope, Scope::FnScope, S); + TC.typeCheckDecl(S->getPrototype()); } - return true; -} -bool TypeChecker::postWalkSubscriptStmt(SubscriptStmt *S) { - return S->getValue()->getType()->isValueType(); -} + void visitFuncStmt(FuncStmt *S) { + PushScopeRAII Push(TC.ASTScope, Scope::FnScope, S); + TC.typeCheckDecl(S->getPrototype()); + typeCheckStmt(S->getBody()); + } -bool TypeChecker::postWalkBlockStmt(BlockStmt *S) { - DeclCtx.pop(); - Scp.pop(); - return true; -} + void visitForStmt(ForStmt *S) { + PushScopeRAII Push(TC.ASTScope, Scope::BreakScope | Scope::ControlScope, S); + TC.typeCheckDecl(S->getIter()); + typeCheckStmt(S->getRange()); + + // Set iterator type BEFORE type checking the body. + auto Ty = S->getRange()->getRangeStmt()->getStart()->getType(); + S->getIter()->setType(Ty); + + typeCheckStmt(S->getBody()); + } -bool TypeChecker::postWalkExternStmt(ExternStmt *S) { - DeclCtx.pop(); - Scp.pop(); - return true; -} + void visitWhileStmt(WhileStmt *S) { + PushScopeRAII Push(TC.ASTScope, Scope::BreakScope | Scope::ControlScope, S); + auto Cond = TC.typeCheckExpr(S->getCond()); + TC.typeCheckStmt(S->getBody()); + S->setCond(Cond); + } -bool TypeChecker::postWalkForStmt(ForStmt *S) { - Scp.pop(); - return true; -} + void visitIfStmt(IfStmt *S) { + PushScopeRAII Push(TC.ASTScope, Scope::ControlScope, S); + auto Cond = TC.typeCheckExpr(S->getCond()); + typeCheckStmt(S->getThen()); + if (S->hasElseBlock()) + typeCheckStmt(S->getElse()); + S->setCond(Cond); + } -bool TypeChecker::postWalkFuncStmt(FuncStmt *S) { - Scp.pop(); - return true; -} +public: + void typeCheckStmt(Stmt *S) { + super::visit(S); + } +}; -bool TypeChecker::postWalkIfStmt(IfStmt *S) { - Scp.pop(); - if (S->getCond()->getType()->isValueType()) - return true; - diagnose(S->getCond()->getLocStart(), diag::expected_value_type_expression); - return false; +void TypeChecker::typeCheckStmt(Stmt *S) { + StmtChecker(*this).typeCheckStmt(S); } -bool TypeChecker::postWalkWhileStmt(WhileStmt *S) { - Scp.pop(); - if (S->getCond()->getType()->isValueType()) - return true; - diagnose(S->getCond()->getLocStart(), diag::expected_value_type_expression); - return false; -} +// bool TypeChecker::preWalkBlockStmt(BlockStmt *S) { +// Lookup.push(); +// if (auto Fn = dynamic_cast<FuncStmt *>(Scp.top().getStmt())) { +// auto Proto = static_cast<FuncDecl *>(Fn->getPrototype()); +// auto Args = static_cast<VarPattern *>(Proto->getArgs()); +// for (auto Arg : Args->getVars()) +// if (!Lookup.declareVar(Arg)) { +// diagnose(Args->getLocStart(), diag::redefinition_of_identifier); +// return false; +// } +// } +// +// if (auto For = dynamic_cast<ForStmt *>(Scp.top().getStmt())) { +// if (!For->getRange()->walk(*this)) +// return false; +// auto Rng = static_cast<RangeStmt *>(For->getRange()); +// auto Iter = static_cast<ParamDecl *>(For->getIter()); +// Iter->setType(Rng->getStart()->getType()); +// Lookup.declareLet(Iter); +// } +// Scp.push(Scope(&Scp.top(), Scope::BlockScope, S)); +// return true; +//} +// +// bool TypeChecker::preWalkExternStmt(ExternStmt *S) { +// Scp.push(Scope(&Scp.top(), Scope::FnScope, S)); +// Lookup.push(); +// return true; +//} +// +// bool TypeChecker::preWalkForStmt(ForStmt *S) { +// Scp.push(Scope(&Scp.top(), Scope::ControlScope | Scope::BreakScope, S)); +// return true; +//} +// +// bool TypeChecker::preWalkFuncStmt(FuncStmt *S) { +// Scp.push(Scope(&Scp.top(), Scope::FnScope, S)); +// return true; +//} +// +// bool TypeChecker::preWalkIfStmt(IfStmt *S) { +// Scp.push(Scope(&Scp.top(), Scope::ControlScope, S)); +// return true; +//} +// +// bool TypeChecker::preWalkWhileStmt(WhileStmt *S) { +// Scp.push(Scope(&Scp.top(), Scope::ControlScope | Scope::BreakScope, S)); +// return true; +//} +// +// bool TypeChecker::postWalkBreakStmt(BreakStmt *S) { +// if (Scp.top().isBreakScope() || Scp.top().getBreakParent() != nullptr) +// return true; +// diagnose(S->getLocStart(), diag::unexpected_break_stmt); +// return false; +//} +// +// bool TypeChecker::postWalkReturnStmt(ReturnStmt *S) { +// if (!Scp.top().isFnScope() && Scp.top().getFnParent() == nullptr) { +// diagnose(S->getLocStart(), diag::unexpected_return_stmt); +// return false; +// } +// auto &FnScp = Scp.top().isFnScope() ? Scp.top() : *Scp.top().getFnParent(); +// +// auto F = static_cast<FuncStmt *>(FnScp.getStmt()); +// auto FD = static_cast<FuncDecl *>(F->getPrototype()); +// auto FTy = static_cast<FunctionType *>(FD->getType()); +// +// if (!S->hasValue()) { +// if (FTy->getRetType()->isVoidType()) +// return true; +// diagnose(S->getLocStart(), diag::return_missing_value); +// return false; +// } +// +// if (FTy->getRetType()->isClassOf(S->getValue()->getType())) +// return true; +// +// diagnose(S->getLocStart(), diag::type_missmatch); +// return false; +//} +// +// bool TypeChecker::postWalkRangeStmt(RangeStmt *S) { +// if (!S->getStart()->getType()->isValueType()) { +// diagnose(S->getStart()->getLocStart(), +// diag::expected_value_type_expression); +// return false; +// } +// if (!S->getEnd()->getType()->isValueType()) { +// diagnose(S->getEnd()->getLocStart(), +// diag::expected_value_type_expression); +// return false; +// } +// return true; +//} +// +// bool TypeChecker::postWalkSubscriptStmt(SubscriptStmt *S) { +// return S->getValue()->getType()->isValueType(); +//} +// +// bool TypeChecker::postWalkBlockStmt(BlockStmt *S) { +// Lookup.pop(); +// Scp.pop(); +// return true; +//} +// +// bool TypeChecker::postWalkExternStmt(ExternStmt *S) { +// Lookup.pop(); +// Scp.pop(); +// return true; +//} +// +// bool TypeChecker::postWalkForStmt(ForStmt *S) { +// Scp.pop(); +// return true; +//} +// +// bool TypeChecker::postWalkFuncStmt(FuncStmt *S) { +// Scp.pop(); +// return true; +//} +// +// bool TypeChecker::postWalkIfStmt(IfStmt *S) { +// Scp.pop(); +// if (S->getCond()->getType()->isValueType()) +// return true; +// diagnose(S->getCond()->getLocStart(), diag::expected_value_type_expression); +// return false; +//} +// +// bool TypeChecker::postWalkWhileStmt(WhileStmt *S) { +// Scp.pop(); +// if (S->getCond()->getType()->isValueType()) +// return true; +// diagnose(S->getCond()->getLocStart(), diag::expected_value_type_expression); +// return false; +//} diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp new file mode 100644 index 0000000..4ded976 --- /dev/null +++ b/lib/Sema/TypeCheckType.cpp @@ -0,0 +1,86 @@ +//===--- TypeCheckStmt.cpp ------------------------------------------------===// +// +// dusk-lang +// This source file is part of a dusk-lang project, which is a semestral +// assignement for BI-PJP course at Czech Technical University in Prague. +// The software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND. +// +//===----------------------------------------------------------------------===// + +#include "TypeChecker.h" + +#include "dusk/AST/Diagnostics.h" +#include "dusk/AST/Scope.h" +#include "dusk/AST/NameLookup.h" +#include "dusk/AST/ASTVisitor.h" +#include "dusk/Sema/Sema.h" +#include "dusk/Sema/TypeResolver.h" +#include "dusk/AST/ASTWalker.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace dusk; +using namespace sema; + +namespace { + +class TypeReprChecker : public TypeReprVisitor<TypeReprChecker> { + TypeChecker &TC; + + typedef ASTVisitor super; + + friend super; + +public: + TypeReprChecker(TypeChecker &TC) : TC(TC) {} + +private: + + void visitIdentTypeRepr(IdentTypeRepr *TR) { + auto Ty = llvm::StringSwitch<Type *>(TR->getIdent()) + .Case("Int", TC.Ctx.getIntType()) + .Case("Void", TC.Ctx.getVoidType()) + .Default(nullptr); + + if (Ty) + TR->setType(Ty); + else + TC.diagnose(TR->getLocStart(), diag::unknown_type); + } + + void visitArrayTypeRepr(ArrayTypeRepr *TR) { + typeCheckType(TR->getBaseTyRepr()); + TC.typeCheckStmt(TR->getSize()); + + auto BaseTy = TR->getBaseTyRepr()->getType(); + auto Size = dynamic_cast<NumberLiteralExpr *>( + TR->getSize()->getSubscripStmt()->getValue()); + + if (!BaseTy) + return; + + // Array must not be of null type + if (BaseTy->isVoidType()) { + TC.diagnose(TR->getLocStart(), diag::type_missmatch); + return; + } + + // Array size must be known at compile time + if (!Size) { + TC.diagnose(TR->getSize()->getLocStart(), diag::variable_array_size); + return; + } + auto Ty = new (TC.Ctx) ArrayType(BaseTy, Size->getValue()); + TR->setType(Ty); + } + +public: + void typeCheckType(TypeRepr *TR) { + super::visit(TR); + } +}; + +} // anonymous namespace + +void TypeChecker::typeCheckType(TypeRepr *TR) { + TypeReprChecker(*this).typeCheckType(TR); +} diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 8006e9c..34f62c0 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -19,7 +19,7 @@ using namespace sema; TypeChecker::TypeChecker(Sema &S, NameLookup &C, ASTContext &Ctx, DiagnosticEngine &D) - : S(S), DeclCtx(C), Ctx(Ctx), Diag(D) { + : S(S), Lookup(C), Ctx(Ctx), Diag(D) { Scp.push(Scope()); } @@ -28,123 +28,123 @@ void TypeChecker::diagnose(SMLoc Loc, diag::DiagID ID) { Ctx.setError(); } -bool TypeChecker::preWalk(Decl *D) { - switch (D->getKind()) { - case DeclKind::Let: - return preWalkLetDecl(static_cast<LetDecl *>(D)); - case DeclKind::Func: - return preWalkFuncDecl(static_cast<FuncDecl *>(D)); - case DeclKind::Module: - return preWalkModuleDecl(static_cast<ModuleDecl *>(D)); - case DeclKind::Param: - return preWalkParamDecl(static_cast<ParamDecl *>(D)); - case DeclKind::Var: - return preWalkVarDecl(static_cast<VarDecl *>(D)); - } -} - -bool TypeChecker::postWalk(Decl *D) { - switch (D->getKind()) { - case DeclKind::Let: - return postWalkLetDecl(static_cast<LetDecl *>(D)); - case DeclKind::Func: - return postWalkFuncDecl(static_cast<FuncDecl *>(D)); - case DeclKind::Module: - return postWalkModuleDecl(static_cast<ModuleDecl *>(D)); - case DeclKind::Param: - return postWalkParamDecl(static_cast<ParamDecl *>(D)); - case DeclKind::Var: - return postWalkVarDecl(static_cast<VarDecl *>(D)); - } -} - -bool TypeChecker::preWalk(Expr *E) { - // Skip expression type validation tree if the root expression has a type. - return E->getType() == nullptr; -} - -bool TypeChecker::postWalk(Expr *E) { - switch (E->getKind()) { - case ExprKind::NumberLiteral: - return postWalkNumberLiteralExpr(static_cast<NumberLiteralExpr *>(E)); - case ExprKind::ArrayLiteral: - return postWalkArrayLiteralExpr(static_cast<ArrayLiteralExpr *>(E)); - case ExprKind::Identifier: - return postWalkIdentifierExpr(static_cast<IdentifierExpr *>(E)); - case ExprKind::Paren: - return postWalkParenExpr(static_cast<ParenExpr *>(E)); - case ExprKind::Assign: - return postWalkAssignExpr(static_cast<AssignExpr *>(E)); - case ExprKind::Infix: - return postWalkInfixExpr(static_cast<InfixExpr *>(E)); - case ExprKind::Prefix: - return postWalkPrefixExpr(static_cast<PrefixExpr *>(E)); - case ExprKind::Call: - return postWalkCallExpr(static_cast<CallExpr *>(E)); - case ExprKind::Subscript: - return postWalkSubscriptExpr(static_cast<SubscriptExpr *>(E)); - } -} - -bool TypeChecker::preWalk(Stmt *S) { - switch (S->getKind()) { - case StmtKind::Block: - return preWalkBlockStmt(static_cast<BlockStmt *>(S)); - case StmtKind::Extern: - return preWalkExternStmt(static_cast<ExternStmt *>(S)); - case StmtKind::For: - return preWalkForStmt(static_cast<ForStmt *>(S)); - case StmtKind::Func: - return preWalkFuncStmt(static_cast<FuncStmt *>(S)); - case StmtKind::If: - return preWalkIfStmt(static_cast<IfStmt *>(S)); - case StmtKind::While: - return preWalkWhileStmt(static_cast<WhileStmt *>(S)); - default: return true; - } -} - -bool TypeChecker::postWalk(Stmt *S) { - switch (S->getKind()) { - case StmtKind::Break: - return postWalkBreakStmt(static_cast<BreakStmt *>(S)); - case StmtKind::Return: - return postWalkReturnStmt(static_cast<ReturnStmt *>(S)); - case StmtKind::Range: - return postWalkRangeStmt(static_cast<RangeStmt *>(S)); - case StmtKind::Subscript: - return postWalkSubscriptStmt(static_cast<SubscriptStmt *>(S)); - case StmtKind::Block: - return postWalkBlockStmt(static_cast<BlockStmt *>(S)); - case StmtKind::Extern: - return postWalkExternStmt(static_cast<ExternStmt *>(S)); - case StmtKind::For: - return postWalkForStmt(static_cast<ForStmt *>(S)); - case StmtKind::Func: - return postWalkFuncStmt(static_cast<FuncStmt *>(S)); - case StmtKind::If: - return postWalkIfStmt(static_cast<IfStmt *>(S)); - case StmtKind::While: - return postWalkWhileStmt(static_cast<WhileStmt *>(S)); - } -} - -bool TypeChecker::preWalk(Pattern *P) { - switch (P->getKind()) { - case PatternKind::Variable: - return preWalkVarPattern(static_cast<VarPattern *>(P)); - case PatternKind::Expr: - return preWalkExprPattern(static_cast<ExprPattern *>(P)); - } -} - -bool TypeChecker::postWalk(Pattern *P) { - switch (P->getKind()) { - case PatternKind::Variable: - return postWalkVarPattern(static_cast<VarPattern *>(P)); - case PatternKind::Expr: - return postWalkExprPattern(static_cast<ExprPattern *>(P)); - } -} +//bool TypeChecker::preWalk(Decl *D) { +// switch (D->getKind()) { +// case DeclKind::Let: +// return preWalkLetDecl(static_cast<LetDecl *>(D)); +// case DeclKind::Func: +// return preWalkFuncDecl(static_cast<FuncDecl *>(D)); +// case DeclKind::Module: +// return preWalkModuleDecl(static_cast<ModuleDecl *>(D)); +// case DeclKind::Param: +// return preWalkParamDecl(static_cast<ParamDecl *>(D)); +// case DeclKind::Var: +// return preWalkVarDecl(static_cast<VarDecl *>(D)); +// } +//} +// +//bool TypeChecker::postWalk(Decl *D) { +// switch (D->getKind()) { +// case DeclKind::Let: +// return postWalkLetDecl(static_cast<LetDecl *>(D)); +// case DeclKind::Func: +// return postWalkFuncDecl(static_cast<FuncDecl *>(D)); +// case DeclKind::Module: +// return postWalkModuleDecl(static_cast<ModuleDecl *>(D)); +// case DeclKind::Param: +// return postWalkParamDecl(static_cast<ParamDecl *>(D)); +// case DeclKind::Var: +// return postWalkVarDecl(static_cast<VarDecl *>(D)); +// } +//} +// +//bool TypeChecker::preWalk(Expr *E) { +// // Skip expression type validation tree if the root expression has a type. +// return E->getType() == nullptr; +//} +// +//bool TypeChecker::postWalk(Expr *E) { +// switch (E->getKind()) { +// case ExprKind::NumberLiteral: +// return postWalkNumberLiteralExpr(static_cast<NumberLiteralExpr *>(E)); +// case ExprKind::ArrayLiteral: +// return postWalkArrayLiteralExpr(static_cast<ArrayLiteralExpr *>(E)); +// case ExprKind::Identifier: +// return postWalkIdentifierExpr(static_cast<IdentifierExpr *>(E)); +// case ExprKind::Paren: +// return postWalkParenExpr(static_cast<ParenExpr *>(E)); +// case ExprKind::Assign: +// return postWalkAssignExpr(static_cast<AssignExpr *>(E)); +// case ExprKind::Infix: +// return postWalkInfixExpr(static_cast<InfixExpr *>(E)); +// case ExprKind::Prefix: +// return postWalkPrefixExpr(static_cast<PrefixExpr *>(E)); +// case ExprKind::Call: +// return postWalkCallExpr(static_cast<CallExpr *>(E)); +// case ExprKind::Subscript: +// return postWalkSubscriptExpr(static_cast<SubscriptExpr *>(E)); +// } +//} +// +//bool TypeChecker::preWalk(Stmt *S) { +// switch (S->getKind()) { +// case StmtKind::Block: +// return preWalkBlockStmt(static_cast<BlockStmt *>(S)); +// case StmtKind::Extern: +// return preWalkExternStmt(static_cast<ExternStmt *>(S)); +// case StmtKind::For: +// return preWalkForStmt(static_cast<ForStmt *>(S)); +// case StmtKind::Func: +// return preWalkFuncStmt(static_cast<FuncStmt *>(S)); +// case StmtKind::If: +// return preWalkIfStmt(static_cast<IfStmt *>(S)); +// case StmtKind::While: +// return preWalkWhileStmt(static_cast<WhileStmt *>(S)); +// default: return true; +// } +//} +// +//bool TypeChecker::postWalk(Stmt *S) { +// switch (S->getKind()) { +// case StmtKind::Break: +// return postWalkBreakStmt(static_cast<BreakStmt *>(S)); +// case StmtKind::Return: +// return postWalkReturnStmt(static_cast<ReturnStmt *>(S)); +// case StmtKind::Range: +// return postWalkRangeStmt(static_cast<RangeStmt *>(S)); +// case StmtKind::Subscript: +// return postWalkSubscriptStmt(static_cast<SubscriptStmt *>(S)); +// case StmtKind::Block: +// return postWalkBlockStmt(static_cast<BlockStmt *>(S)); +// case StmtKind::Extern: +// return postWalkExternStmt(static_cast<ExternStmt *>(S)); +// case StmtKind::For: +// return postWalkForStmt(static_cast<ForStmt *>(S)); +// case StmtKind::Func: +// return postWalkFuncStmt(static_cast<FuncStmt *>(S)); +// case StmtKind::If: +// return postWalkIfStmt(static_cast<IfStmt *>(S)); +// case StmtKind::While: +// return postWalkWhileStmt(static_cast<WhileStmt *>(S)); +// } +//} +// +//bool TypeChecker::preWalk(Pattern *P) { +// switch (P->getKind()) { +// case PatternKind::Variable: +// return preWalkVarPattern(static_cast<VarPattern *>(P)); +// case PatternKind::Expr: +// return preWalkExprPattern(static_cast<ExprPattern *>(P)); +// } +//} +// +//bool TypeChecker::postWalk(Pattern *P) { +// switch (P->getKind()) { +// case PatternKind::Variable: +// return postWalkVarPattern(static_cast<VarPattern *>(P)); +// case PatternKind::Expr: +// return postWalkExprPattern(static_cast<ExprPattern *>(P)); +// } +//} diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 0d72af1..e240f76 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -37,80 +37,92 @@ class Sema; /// /// This class takes an AST as an input and resolves types of all it's nodes, /// while validating them. -class TypeChecker : public ASTWalker { +class TypeChecker /*: public ASTWalker*/ { Sema &S; - NameLookup &DeclCtx; + +public: + NameLookup &Lookup; ASTContext &Ctx; std::stack<Scope> Scp; + Scope ASTScope; DiagnosticEngine &Diag; - -public: + TypeChecker(Sema &S, NameLookup &DC, ASTContext &Ctx, DiagnosticEngine &Diag); - virtual bool preWalk(Decl *D) override; - virtual bool postWalk(Decl *D) override; - - virtual bool preWalk(Expr *E) override; - virtual bool postWalk(Expr *E) override; - - virtual bool preWalk(Stmt *S) override; - virtual bool postWalk(Stmt *S) override; - - virtual bool preWalk(Pattern *P) override; - virtual bool postWalk(Pattern *P) override; +// virtual bool preWalk(Decl *D) override; +// virtual bool postWalk(Decl *D) override; +// +// virtual bool preWalk(Expr *E) override; +// virtual bool postWalk(Expr *E) override; +// +// virtual bool preWalk(Stmt *S) override; +// virtual bool postWalk(Stmt *S) override; +// +// virtual bool preWalk(Pattern *P) override; +// virtual bool postWalk(Pattern *P) override; -private: void diagnose(SMLoc Loc, diag::DiagID ID); - // MARK: - Declarations - bool preWalkLetDecl(LetDecl *D); - bool preWalkFuncDecl(FuncDecl *D); - bool preWalkModuleDecl(ModuleDecl *D); - bool preWalkParamDecl(ParamDecl *D); - bool preWalkVarDecl(VarDecl *D); - - bool postWalkLetDecl(LetDecl *D); - bool postWalkFuncDecl(FuncDecl *D); - bool postWalkModuleDecl(ModuleDecl *D); - bool postWalkParamDecl(ParamDecl *D); - bool postWalkVarDecl(VarDecl *D); - - // MARK: - Expressions - bool postWalkNumberLiteralExpr(NumberLiteralExpr *E); - bool postWalkArrayLiteralExpr(ArrayLiteralExpr *E); - bool postWalkIdentifierExpr(IdentifierExpr *E); - bool postWalkParenExpr(ParenExpr *E); - bool postWalkAssignExpr(AssignExpr *E); - bool postWalkInfixExpr(InfixExpr *E); - bool postWalkPrefixExpr(PrefixExpr *E); - bool postWalkCallExpr(CallExpr *E); - bool postWalkSubscriptExpr(SubscriptExpr *E); - - // MARK: - Statements - bool preWalkBlockStmt(BlockStmt *S); - bool preWalkExternStmt(ExternStmt *S); - bool preWalkForStmt(ForStmt *S); - bool preWalkFuncStmt(FuncStmt *S); - bool preWalkIfStmt(IfStmt *S); - bool preWalkWhileStmt(WhileStmt *S); - - bool postWalkBreakStmt(BreakStmt *S); - bool postWalkReturnStmt(ReturnStmt *S); - bool postWalkRangeStmt(RangeStmt *S); - bool postWalkSubscriptStmt(SubscriptStmt *S); - bool postWalkBlockStmt(BlockStmt *S); - bool postWalkExternStmt(ExternStmt *S); - bool postWalkForStmt(ForStmt *S); - bool postWalkFuncStmt(FuncStmt *S); - bool postWalkIfStmt(IfStmt *S); - bool postWalkWhileStmt(WhileStmt *S); + bool typeCheckEquals(Type *LHS, Type *RHS) { + return LHS->isClassOf(RHS); + } - // MARK: - Patterns - bool preWalkVarPattern(VarPattern *P); - bool preWalkExprPattern(ExprPattern *P); + void typeCheckDecl(Decl *D); + Expr *typeCheckExpr(Expr *E); + void typeCheckStmt(Stmt *S); + void typeCheckPattern(Pattern *P); + void typeCheckType(TypeRepr *TR); - bool postWalkVarPattern(VarPattern *P); - bool postWalkExprPattern(ExprPattern *P); +//private: +// // MARK: - Declarations +// bool preWalkLetDecl(LetDecl *D); +// bool preWalkFuncDecl(FuncDecl *D); +// bool preWalkModuleDecl(ModuleDecl *D); +// bool preWalkParamDecl(ParamDecl *D); +// bool preWalkVarDecl(VarDecl *D); +// +// bool postWalkLetDecl(LetDecl *D); +// bool postWalkFuncDecl(FuncDecl *D); +// bool postWalkModuleDecl(ModuleDecl *D); +// bool postWalkParamDecl(ParamDecl *D); +// bool postWalkVarDecl(VarDecl *D); +// +// // MARK: - Expressions +// bool postWalkNumberLiteralExpr(NumberLiteralExpr *E); +// bool postWalkArrayLiteralExpr(ArrayLiteralExpr *E); +// bool postWalkIdentifierExpr(IdentifierExpr *E); +// bool postWalkParenExpr(ParenExpr *E); +// bool postWalkAssignExpr(AssignExpr *E); +// bool postWalkInfixExpr(InfixExpr *E); +// bool postWalkPrefixExpr(PrefixExpr *E); +// bool postWalkCallExpr(CallExpr *E); +// bool postWalkSubscriptExpr(SubscriptExpr *E); +// +// // MARK: - Statements +// bool preWalkBlockStmt(BlockStmt *S); +// bool preWalkExternStmt(ExternStmt *S); +// bool preWalkForStmt(ForStmt *S); +// bool preWalkFuncStmt(FuncStmt *S); +// bool preWalkIfStmt(IfStmt *S); +// bool preWalkWhileStmt(WhileStmt *S); +// +// bool postWalkBreakStmt(BreakStmt *S); +// bool postWalkReturnStmt(ReturnStmt *S); +// bool postWalkRangeStmt(RangeStmt *S); +// bool postWalkSubscriptStmt(SubscriptStmt *S); +// bool postWalkBlockStmt(BlockStmt *S); +// bool postWalkExternStmt(ExternStmt *S); +// bool postWalkForStmt(ForStmt *S); +// bool postWalkFuncStmt(FuncStmt *S); +// bool postWalkIfStmt(IfStmt *S); +// bool postWalkWhileStmt(WhileStmt *S); +// +// // MARK: - Patterns +// bool preWalkVarPattern(VarPattern *P); +// bool preWalkExprPattern(ExprPattern *P); +// +// bool postWalkVarPattern(VarPattern *P); +// bool postWalkExprPattern(ExprPattern *P); }; } // namespace sema diff --git a/lib/Sema/TypeResolver.cpp b/lib/Sema/TypeResolver.cpp index 57e3f6e..2572c68 100644 --- a/lib/Sema/TypeResolver.cpp +++ b/lib/Sema/TypeResolver.cpp @@ -115,16 +115,14 @@ bool TypeResolver::resolveFuncDecl(FuncDecl *D) { if (D->hasTypeRepr()) { RT = D->getTypeRepr()->getType(); } else { - RT = new(Context) VoidType(); + RT = new (Context) VoidType(); } - D->setType(new(Context) FunctionType(AT, RT)); + D->setType(new (Context) FunctionType(AT, RT)); return true; } -bool TypeResolver::resolveModuleDecl(ModuleDecl *D) { - return true; -} +bool TypeResolver::resolveModuleDecl(ModuleDecl *D) { return true; } bool TypeResolver::resolveParamDecl(ParamDecl *D) { if (D->hasTypeRepr()) @@ -143,7 +141,7 @@ Expr *TypeResolver::resolveArrayLiteralExpr(ArrayLiteralExpr *E) { auto Size = E->getValues()->count(); auto Vals = static_cast<ExprPattern *>(E->getValues()); auto BaseTy = Vals->getValues().front()->getType(); - E->setType(new(Context) ArrayType(BaseTy, Size)); + E->setType(new (Context) ArrayType(BaseTy, Size)); return E; } @@ -217,12 +215,12 @@ bool TypeResolver::typeResolveIdentTypeRepr(IdentTypeRepr *TR) { if (TR->getIdent() == "Void") { TR->setType(Context.getVoidType()); return true; - + } else if (TR->getIdent() == "Int") { TR->setType(Context.getVoidType()); return true; } - + Diag.diagnose(TR->getLocStart(), diag::unknown_type); return true; } @@ -230,7 +228,7 @@ bool TypeResolver::typeResolveIdentTypeRepr(IdentTypeRepr *TR) { bool TypeResolver::typeResolveArrayTypeRepr(ArrayTypeRepr *TR) { auto BaseTy = TR->getBaseTyRepr()->getType(); auto Size = 0; // TODO: perform exctraction. TR->getSize(); - - TR->setType(new(Context) ArrayType(BaseTy, Size)); + + TR->setType(new (Context) ArrayType(BaseTy, Size)); return true; } diff --git a/tools/duskc/main.cpp b/tools/duskc/main.cpp index b9cf9a0..c69dee6 100644 --- a/tools/duskc/main.cpp +++ b/tools/duskc/main.cpp @@ -7,6 +7,8 @@ #include <iostream> #include <string> +#include "dusk/AST/Scope.h" + using namespace dusk; using namespace llvm; @@ -29,7 +31,7 @@ int main(int argc, const char *argv[]) { cl::ParseCommandLineOptions(argc, argv); CompilerInstance Compiler; initCompilerInstance(Compiler); - + Compiler.performParseOnly(); if (Compiler.hasASTContext() && !Compiler.getContext().isError()) { Formatter F(Compiler.getContext(), llvm::errs()); -- GitLab