diff --git a/examples/funcDecl.dusk b/examples/funcDecl.dusk index de1eeace293c4614b880aec750ca0d2489d601df..fec9e8636fe5ff8abb11490b5bb23d7324e63a47 100644 --- a/examples/funcDecl.dusk +++ b/examples/funcDecl.dusk @@ -1,10 +1,10 @@ extern func test(); -func inc(i) -> Int { +func inc(i: Int) -> Int { return i + 1; } -func main(arg1) -> Int { +func main(arg1: Int) -> Int { if arg1 % 2 == 0 { arg1 = inc(arg1); } diff --git a/examples/globExpr.dusk b/examples/globExpr.dusk index f5515b40544c0039fc695b8b238c9a9a51e4a060..2494aed6d8789f79302fbae82253ba88ef1f4532 100644 --- a/examples/globExpr.dusk +++ b/examples/globExpr.dusk @@ -1,4 +1,5 @@ -var a = 14; +var a: Int; +a = 14; let d = a + 99; a = (1 + 2) * 8 == 2; a = (1 + 2 * 9) || (4 % 3); diff --git a/include/dusk/AST/ASTContext.h b/include/dusk/AST/ASTContext.h index 44e7b69193e54d6bcb536e9e63573648a747f90a..5f83019bee60de354391f388db09dfaca8c01ef8 100644 --- a/include/dusk/AST/ASTContext.h +++ b/include/dusk/AST/ASTContext.h @@ -83,7 +83,7 @@ public: template <typename T> T *pushTypeRepr(std::unique_ptr<T> &&TyRepr) { TyReprs.push_back(std::move(TyRepr)); - return static_cast<T *>(TyRepr); + return static_cast<T *>(TyReprs.back().get()); } }; diff --git a/include/dusk/AST/ASTVisitor.h b/include/dusk/AST/ASTVisitor.h index 0bd1a5da5dbc08513021e7ce11e3ddbf2df0401f..39f8a29f08bc0e23b8f0729b6535f5b7acd34d8f 100644 --- a/include/dusk/AST/ASTVisitor.h +++ b/include/dusk/AST/ASTVisitor.h @@ -15,6 +15,7 @@ #include "dusk/AST/Expr.h" #include "dusk/AST/Stmt.h" #include "dusk/AST/Pattern.h" +#include "dusk/AST/TypeRepr.h" namespace dusk { @@ -122,6 +123,16 @@ public: 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::Function: + llvm_unreachable("Not implemented yet."); + } + } }; } // namespace dusk diff --git a/include/dusk/AST/Decl.h b/include/dusk/AST/Decl.h index b3eac8b1c9c9b0ca1e6ef4dc37a428f3cb618123..89f6359edc6db5a684a231ea55aabd201eb9afd1 100644 --- a/include/dusk/AST/Decl.h +++ b/include/dusk/AST/Decl.h @@ -49,10 +49,10 @@ class Decl : public ASTNode { /// Location of declaration SMLoc NameLoc; - + /// Type of declaration Type *Ty; - + /// Type representation, if present TypeRepr *TyRepr; @@ -73,11 +73,19 @@ public: /// Returns declaration identifier as string. StringRef getName() const { return Name; } + /// Returns declaration type Type *getType() const { return Ty; } + + /// Sets declaration type void setType(Type *T) { Ty = T; } - + + /// Returns \c true if declaration has an explicit type specification, + /// \c false otherwise. bool hasTypeRepr() const { return TyRepr != nullptr; } - + + /// Returns type representation. + TypeRepr *getTypeRepr() const { return TyRepr; } + virtual SMRange getSourceRange() const override; }; @@ -91,7 +99,9 @@ class ValDecl : public Decl { public: ValDecl(DeclKind K, StringRef N, SMLoc NL, Expr *V); + ValDecl(DeclKind K, StringRef N, SMLoc NL, Expr *V, TypeRepr *TR); + bool hasValue() const { return Value != nullptr; } SMLoc getValLoc() const { return ValLoc; } Expr *getValue() const { return Value; } }; @@ -103,6 +113,7 @@ class VarDecl : public ValDecl { public: VarDecl(StringRef N, SMLoc NL, SMLoc VarL, Expr *V); + VarDecl(StringRef N, SMLoc NL, SMLoc VarL, Expr *V, TypeRepr *TR); SMLoc getVarLoc() const { return VarLoc; } virtual SMRange getSourceRange() const override; @@ -115,6 +126,7 @@ class LetDecl : public ValDecl { public: LetDecl(StringRef N, SMLoc NL, SMLoc LetL, Expr *V); + LetDecl(StringRef N, SMLoc NL, SMLoc LetL, Expr *V, TypeRepr *TR); SMLoc getLettLoc() const { return LetLoc; } @@ -123,8 +135,9 @@ public: /// Declaration of function parameter class ParamDecl : public Decl { - public: +public: ParamDecl(StringRef N, SMLoc NL); + ParamDecl(StringRef N, SMLoc NL, TypeRepr *TR); }; /// Function declaration diff --git a/include/dusk/AST/DiagnosticsParse.h b/include/dusk/AST/DiagnosticsParse.h index 1d33874fcde1241eaf7447fbb6cf7323bbff45f2..dd5a041d5fba9cd13a661b874c06c0f6443ab9cb 100644 --- a/include/dusk/AST/DiagnosticsParse.h +++ b/include/dusk/AST/DiagnosticsParse.h @@ -40,7 +40,11 @@ enum DiagID : unsigned { expected_r_brace, expected_return_type, expected_type_specifier, - expected_func_kw + expected_func_kw, + + + // Types + expected_type_annotation, }; static StringRef getTextForID(DiagID ID) { @@ -86,6 +90,9 @@ static StringRef getTextForID(DiagID ID) { return "Expected type specifier"; case DiagID::expected_func_kw: return "Expected 'func' keyword to at start of function delaration"; + + case DiagID::expected_type_annotation: + return "Expected type annocation ': Type'."; } } diff --git a/include/dusk/AST/TypeRepr.h b/include/dusk/AST/TypeRepr.h index 3771cf3d344276f28644fddeb95cf4fd67832b24..291b43a857a0eb5c6fc9618c37972596b562a8bd 100644 --- a/include/dusk/AST/TypeRepr.h +++ b/include/dusk/AST/TypeRepr.h @@ -11,6 +11,7 @@ #define DUSK_TYPE_REPR_H #include "dusk/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/SMLoc.h" @@ -27,13 +28,24 @@ class TypeRepr { 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; }; class IdentTypeRepr : public TypeRepr { - SMLoc IdentLoc; + SMLoc ColonLoc; + + StringRef Ident; + +public: + IdentTypeRepr(SMLoc CL, StringRef N); + + SMLoc getColonLoc() const { return ColonLoc; } + StringRef getIdent() const { return Ident; } + + virtual SMRange getSourceRange() const override; }; //class ParamListTypeRepr : public TypeRepr { diff --git a/include/dusk/Parse/Parser.h b/include/dusk/Parse/Parser.h index 762d29b9648b6ef96c5a98bc1527d2bbade95573..1f1847eab37aad6191399ee60a1718b8b1ce43ca 100644 --- a/include/dusk/Parse/Parser.h +++ b/include/dusk/Parse/Parser.h @@ -21,6 +21,7 @@ #include "dusk/AST/Stmt.h" #include "dusk/AST/Pattern.h" #include "dusk/AST/Type.h" +#include "dusk/AST/TypeRepr.h" #include "dusk/AST/Diagnostics.h" #include "dusk/Parse/Token.h" #include "dusk/Parse/Lexer.h" @@ -103,11 +104,12 @@ private: Decl *parseVarDecl(); - Decl *parseConstDecl(); + Decl *parseLetDecl(); Expr *parseDeclValue(); Decl *parseFuncDecl(); + FuncRetType *parseFuncDeclType(); Stmt *parseBlock(); @@ -163,6 +165,10 @@ private: Pattern *parseVarPattern(); SmallVector<Decl *, 128> parseVarPatternBody(); Decl *parseVarPatternItem(); + + // MARK: - Types + + TypeRepr *parseIdentType(); /// Creates and adds a new instance of \c ASTNode to the parser result /// and returns a pointer to it. @@ -171,7 +177,7 @@ private: return Context.pushNode(std::move(N)); } - /// Creates and adds a new instance of \c ASTNode to the parser result + /// Creates and adds a new instance of \c Pattern to the parser result /// and returns a pointer to it. template <typename Pattern, typename... Args> Pattern *makePattern(Args &&... args) { @@ -179,12 +185,20 @@ private: return Context.pushPattern(std::move(P)); } - /// Creates and adds a new instance of \c ASTNode to the parser result + /// Creates and adds a new instance of \c Type to the parser result /// and returns a pointer to it. template <typename Type, typename... Args> Type *makeType(Args &&... args) { auto T = std::unique_ptr<Type>(new Type(std::forward<Args>(args)...)); return Context.pushType(std::move(T)); } + + /// Creates and adds a new instance of \c TypeRepr to the parser result + /// and returns a pointer to it. + template <typename Type, typename... Args> + TypeRepr *makeTypeRepr(Args &&... args) { + auto T = std::unique_ptr<Type>(new Type(std::forward<Args>(args)...)); + return Context.pushTypeRepr(std::move(T)); + } }; } // namespace dusk diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index d744c6d3598d49f01f4560ea391db270a1f11a24..2d7a224edf2a5a610d3c1bbfc8bc0f51b2cf4e7b 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -14,6 +14,7 @@ #include "dusk/AST/Stmt.h" #include "dusk/AST/Pattern.h" #include "dusk/AST/Type.h" +#include "dusk/AST/TypeRepr.h" #include "dusk/AST/ASTVisitor.h" #include "dusk/Basic/TokenDefinition.h" #include "dusk/Frontend/Formatter.h" @@ -65,8 +66,15 @@ public: bool visit(VarDecl *D) { Printer.printDeclPre(D); - Printer << D->getName() << " " << tok::assign << " "; - super::visit(D->getValue()); + Printer << D->getName(); + + if (D->hasTypeRepr()) + super::visit(D->getTypeRepr()); + + if (D->hasValue()) { + Printer << " " << tok::assign << " "; + super::visit(D->getValue()); + } Printer.printDeclPost(D); return true; } @@ -88,6 +96,7 @@ public: bool visit(ParamDecl *D) { Printer.printDeclPost(D); Printer << D->getName(); + super::visit(D->getTypeRepr()); Printer.printDeclPost(D); return true; } @@ -283,8 +292,17 @@ public: Printer.printPatternPost(P); return true; } + + // MARK: - Type representations + + bool visit(IdentTypeRepr *T) { + Printer << ": " << T->getIdent(); + return true; + } }; +// MARK: - Pretty Printer + /// Implementation of an \c ASTPrinter, which is used to pretty print the AST. class PrettyPrinter : public StreamPrinter { public: diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index d7cf88a91334f6c9273d2e4d4399c5d342d57c93..3e8a7721abd2a6ec73d9f9f30c49052012f78399 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -9,6 +9,7 @@ set(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/Pattern.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Stmt.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Type.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TypeRepr.cpp ${HEADERS} PARENT_SCOPE ) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 938423184808747d171502a773b337444f20321a..5ad27e40924cddd0bb98217addf93ade55d47b06 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -45,11 +45,17 @@ SMRange Decl::getSourceRange() const { ValDecl::ValDecl(DeclKind K, StringRef N, SMLoc NL, Expr *E) : Decl(K, N, NL), Value(E) {} +ValDecl::ValDecl(DeclKind K, StringRef N, SMLoc NL, Expr *E, TypeRepr *TR) + : Decl(K, N, NL, TR), Value(E) {} + // MARK: - VarDecl class VarDecl::VarDecl(StringRef N, SMLoc NL, SMLoc VarL, Expr *V) : ValDecl(DeclKind::Var, N, NL, V), VarLoc(VarL) {} +VarDecl::VarDecl(StringRef N, SMLoc NL, SMLoc VarL, Expr *V, TypeRepr *TR) + : ValDecl(DeclKind::Var, N, NL, V, TR), VarLoc(VarL) {} + SMRange VarDecl::getSourceRange() const { return {VarLoc, getValue()->getLocEnd()}; } @@ -59,6 +65,9 @@ SMRange VarDecl::getSourceRange() const { LetDecl::LetDecl(StringRef N, SMLoc NL, SMLoc ConstL, Expr *V) : ValDecl(DeclKind::Let, N, NL, V), LetLoc(ConstL) {} +LetDecl::LetDecl(StringRef N, SMLoc NL, SMLoc ConstL, Expr *V, TypeRepr *TR) + : ValDecl(DeclKind::Let, N, NL, V, TR), LetLoc(ConstL) {} + SMRange LetDecl::getSourceRange() const { return {LetLoc, getValue()->getLocEnd()}; } @@ -66,6 +75,8 @@ SMRange LetDecl::getSourceRange() const { // MARK: - ParamDecl class ParamDecl::ParamDecl(StringRef N, SMLoc NL) : Decl(DeclKind::Param, N, NL) {} +ParamDecl::ParamDecl(StringRef N, SMLoc NL, TypeRepr *TR) + : Decl(DeclKind::Param, N, NL, TR) {} // MARK: - FuncDecl class @@ -73,6 +84,7 @@ FuncDecl::FuncDecl(StringRef N, SMLoc NL, SMLoc FuncL, VarPattern *A, FuncRetType *R) : Decl(DeclKind::Func, N, NL), FuncLoc(FuncL), Params(A), RetTy(R) {} + SMRange FuncDecl::getSourceRange() const { return {FuncLoc, Params->getLocEnd()}; } diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cfd90016f0f3076a5e29e93fce9e7fd8c269bfb2 --- /dev/null +++ b/lib/AST/TypeRepr.cpp @@ -0,0 +1,22 @@ +//===--- TypeRepr.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 "dusk/AST/TypeRepr.h" + +using namespace dusk; + +TypeRepr::TypeRepr(TypeReprKind K) : Kind(K) {} + +IdentTypeRepr::IdentTypeRepr(SMLoc CL, StringRef N) + : TypeRepr(TypeReprKind::Ident), ColonLoc(CL), Ident(N) {} + +SMRange IdentTypeRepr::getSourceRange() const { + auto E = Ident.data() + Ident.size(); + return {ColonLoc, SMLoc::getFromPointer(E)}; +} diff --git a/lib/Parser/CMakeLists.txt b/lib/Parser/CMakeLists.txt index d9125657ff21ac7c776f0f34b90254d82a30a05e..2e6c0e38bbed4b434fb731691ba636cb758c50bf 100644 --- a/lib/Parser/CMakeLists.txt +++ b/lib/Parser/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/ParsePattern.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Parser.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ParseStmt.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ParseType.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Token.cpp ${SOURCE} PARENT_SCOPE diff --git a/lib/Parser/ParseDecl.cpp b/lib/Parser/ParseDecl.cpp index 38b1e819381613a35ecfb551acd31fe946fa3f7a..8243c5bb55ed942917676b90f11fe457880bb13e 100644 --- a/lib/Parser/ParseDecl.cpp +++ b/lib/Parser/ParseDecl.cpp @@ -14,24 +14,32 @@ using namespace dusk; /// Let declaration /// /// LetDecl ::= +/// 'let' identifier ':' identifier '=' Expr ';' /// 'let' identifier '=' Expr ';' -Decl *Parser::parseConstDecl() { +Decl *Parser::parseLetDecl() { // Validate correct variable decl assert(Tok.is(tok::kwLet) && "Invalid parsing method."); auto L = consumeToken(); auto ID = Tok; if (!consumeIf(tok::identifier)) { - diagnose(Tok.getLoc(), diag::DiagID::expected_identifier); + diagnose(Tok.getLoc(), diag::expected_identifier); return nullptr; } - - return makeNode<LetDecl>(ID.getText(), ID.getLoc(), L, parseDeclValue()); + + TypeRepr *TR = nullptr; + if (Tok.is(tok::colon)) + if ((TR = parseIdentType()) == nullptr) + return nullptr; + + return makeNode<LetDecl>(ID.getText(), ID.getLoc(), L, parseDeclValue(), TR); } /// Var declaration /// /// VarDecl ::= +/// 'var' identifier ':' identifier '=' Expr ';' +/// 'var' identifier ':' identifier ';' /// 'var' identifier '=' Expr ';' Decl *Parser::parseVarDecl() { // Validate correct variable decl @@ -43,13 +51,23 @@ Decl *Parser::parseVarDecl() { diagnose(Tok.getLoc(), diag::DiagID::expected_identifier); return nullptr; } + + TypeRepr *TR; + if (Tok.is(tok::colon)) + if ((TR = parseIdentType()) == nullptr) + return nullptr; - return makeNode<VarDecl>(ID.getText(), ID.getLoc(), L, parseDeclValue()); + return makeNode<VarDecl>(ID.getText(), ID.getLoc(), L, parseDeclValue(), TR); } /// DeclVal ::= +/// ';' /// '=' Expr ';' Expr *Parser::parseDeclValue() { + /// Empty initialization. + if (consumeIf(tok::semicolon)) + return nullptr; + if (!consumeIf(tok::assign)) { diagnose(Tok.getLoc(), diag::DiagID::expected_identifier); return nullptr; @@ -121,6 +139,12 @@ Decl *Parser::parseParamDecl() { auto ID = Tok; consumeToken(); - return makeNode<ParamDecl>(ID.getText(), ID.getLoc()); + if (Tok.isNot(tok::colon)) { + diagnose(Tok.getLoc(), diag::expected_type_annotation); + return nullptr; + } + if (auto TR = parseIdentType()) + return makeNode<ParamDecl>(ID.getText(), ID.getLoc(), TR); + return nullptr; } diff --git a/lib/Parser/ParseStmt.cpp b/lib/Parser/ParseStmt.cpp index c631e326f49964035f8d15d52f3152fdf1e25ee9..a4b2fc1fe40d9370f772f9d47b62c3075599812c 100644 --- a/lib/Parser/ParseStmt.cpp +++ b/lib/Parser/ParseStmt.cpp @@ -134,7 +134,7 @@ ASTNode *Parser::parseBlockBody() { return parseVarDecl(); case tok::kwLet: - return parseConstDecl(); + return parseLetDecl(); case tok::kwBreak: return parseBreakStmt(); diff --git a/lib/Parser/ParseType.cpp b/lib/Parser/ParseType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0da77561c34e3bb0c33be037404ec255b7d03db5 --- /dev/null +++ b/lib/Parser/ParseType.cpp @@ -0,0 +1,27 @@ +//===--- ParseDecl.cpp - Dusk language parser for types -------------------===// +// +// 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 "dusk/Parse/Parser.h" +#include "dusk/AST/TypeRepr.h" + +using namespace dusk; + +/// IdentType ::= +/// ':' identifier +TypeRepr *Parser::parseIdentType() { + assert(Tok.is(tok::colon) && "Invalid parse method"); + auto CL = consumeToken(); + auto Ty = Tok; + if (!consumeIf(tok::kwInt)) { + diagnose(Tok.getLoc(), diag::expected_identifier); + return nullptr; + } + return makeTypeRepr<IdentTypeRepr>(CL, Ty.getText()); +} + diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp index f6a1afa60403ea51e39cf8d7bce80c702251ec5d..da8fb7d84480c9caba3e561bbe8b7672a7b160a1 100644 --- a/lib/Parser/Parser.cpp +++ b/lib/Parser/Parser.cpp @@ -67,7 +67,7 @@ ASTNode *Parser::parseGlobal() { case tok::kwVar: return parseVarDecl(); case tok::kwLet: - return parseConstDecl(); + return parseLetDecl(); case tok::kwExtern: return parseExterStmt(); case tok::kwFunc: