From 4d98e387770fab1a810d6e5fdb05f3c1771e9fe7 Mon Sep 17 00:00:00 2001 From: Peter Matta <mattapet@fit.cvut.cz> Date: Fri, 25 May 2018 01:05:03 +0200 Subject: [PATCH] Added metaprogramming --- include/dusk/AST/ASTVisitor.h | 90 ++++-------- include/dusk/AST/Decl.h | 14 +- include/dusk/AST/DeclNodes.def | 44 ++++++ include/dusk/AST/Expr.h | 29 ++-- include/dusk/AST/ExprNodes.def | 29 ++++ include/dusk/AST/Pattern.h | 12 +- include/dusk/AST/PatternNodes.def | 22 +++ include/dusk/AST/Stmt.h | 12 +- include/dusk/AST/StmtNodes.def | 38 +++++ include/dusk/AST/Type.h | 19 ++- include/dusk/AST/TypeNodes.def | 33 +++++ include/dusk/AST/TypeRepr.h | 9 +- include/dusk/AST/TypeReprNodes.def | 22 +++ include/dusk/Basic/CMakeLists.txt | 2 +- include/dusk/Basic/TokenDefinition.h | 186 ------------------------ include/dusk/Basic/TokenDefinitions.def | 142 ++++++++++++++++++ include/dusk/Basic/TokenDefinitions.h | 25 ++++ include/dusk/Parse/Parser.h | 4 +- include/dusk/Parse/Token.h | 27 ++-- lib/AST/ASTPrinter.cpp | 93 +++++++----- lib/AST/Decl.cpp | 23 +-- lib/AST/Expr.cpp | 43 +----- lib/AST/Pattern.cpp | 15 +- lib/AST/Type.cpp | 32 +--- lib/AST/TypeRepr.cpp | 13 +- lib/IRGen/GenFunc.cpp | 34 +---- lib/IRGen/GenType.cpp | 21 ++- lib/Parser/Lexer.cpp | 24 +-- lib/Parser/ParseDecl.cpp | 26 +++- lib/Parser/ParseExpr.cpp | 2 +- lib/Parser/ParseStmt.cpp | 116 ++++++++------- lib/Parser/ParseType.cpp | 2 +- lib/Parser/Parser.cpp | 28 ++-- lib/Sema/TypeCheckExpr.cpp | 4 +- lib/Sema/TypeCheckStmt.cpp | 2 +- 35 files changed, 657 insertions(+), 580 deletions(-) create mode 100644 include/dusk/AST/DeclNodes.def create mode 100644 include/dusk/AST/ExprNodes.def create mode 100644 include/dusk/AST/PatternNodes.def create mode 100644 include/dusk/AST/StmtNodes.def create mode 100644 include/dusk/AST/TypeNodes.def create mode 100644 include/dusk/AST/TypeReprNodes.def delete mode 100644 include/dusk/Basic/TokenDefinition.h create mode 100644 include/dusk/Basic/TokenDefinitions.def create mode 100644 include/dusk/Basic/TokenDefinitions.h diff --git a/include/dusk/AST/ASTVisitor.h b/include/dusk/AST/ASTVisitor.h index ea1172d..0937d33 100644 --- a/include/dusk/AST/ASTVisitor.h +++ b/include/dusk/AST/ASTVisitor.h @@ -48,89 +48,63 @@ public: /// Visit a concrete declaration node. DeclRetTy visit(Decl *D) { switch (D->getKind()) { - case DeclKind::Let: - return getDerived().visitLetDecl(static_cast<LetDecl *>(D)); - case DeclKind::Var: - return getDerived().visitVarDecl(static_cast<VarDecl *>(D)); - case DeclKind::Func: - return getDerived().visitFuncDecl(static_cast<FuncDecl *>(D)); - case DeclKind::Module: - return getDerived().visitModuleDecl(static_cast<ModuleDecl *>(D)); - case DeclKind::Param: - return getDerived().visitParamDecl(static_cast<ParamDecl *>(D)); +#define DECL(CLASS, PARENT) \ + case DeclKind::CLASS: \ + return getDerived().visit##CLASS##Decl(static_cast<CLASS##Decl *>(D)); + +#include "dusk/AST/DeclNodes.def" } + llvm_unreachable("All cases handeled"); } /// Visit a concrete expression node. ExprRetTy visit(Expr *E) { switch (E->getKind()) { - case ExprKind::NumberLiteral: - return getDerived().visitNumberLiteralExpr( - static_cast<NumberLiteralExpr *>(E)); - case ExprKind::ArrayLiteral: - return getDerived().visitArrayLiteralExpr( - static_cast<ArrayLiteralExpr *>(E)); - case ExprKind::Identifier: - return getDerived().visitIdentifierExpr(static_cast<IdentifierExpr *>(E)); - case ExprKind::Paren: - return getDerived().visitParenExpr(static_cast<ParenExpr *>(E)); - case ExprKind::Assign: - return getDerived().visitAssignExpr(static_cast<AssignExpr *>(E)); - case ExprKind::Infix: - return getDerived().visitInfixExpr(static_cast<InfixExpr *>(E)); - case ExprKind::Prefix: - return getDerived().visitPrefixExpr(static_cast<PrefixExpr *>(E)); - case ExprKind::Call: - return getDerived().visitCallExpr(static_cast<CallExpr *>(E)); - case ExprKind::Subscript: - return getDerived().visitSubscriptExpr(static_cast<SubscriptExpr *>(E)); +#define EXPR(CLASS, PARENT) \ + case ExprKind::CLASS: \ + return getDerived().visit##CLASS##Expr(static_cast<CLASS##Expr *>(E)); + +#include "dusk/AST/ExprNodes.def" } + llvm_unreachable("All cases handeled"); } /// Visit a concrete statement node. StmtRetTy visit(Stmt *S) { switch (S->getKind()) { - case StmtKind::Break: - return getDerived().visitBreakStmt(static_cast<BreakStmt *>(S)); - case StmtKind::Return: - return getDerived().visitReturnStmt(static_cast<ReturnStmt *>(S)); - case StmtKind::Range: - return getDerived().visitRangeStmt(static_cast<RangeStmt *>(S)); - case StmtKind::Subscript: - return getDerived().visitSubscriptStmt(static_cast<SubscriptStmt *>(S)); - case StmtKind::Block: - return getDerived().visitBlockStmt(static_cast<BlockStmt *>(S)); - case StmtKind::Extern: - return getDerived().visitExternStmt(static_cast<ExternStmt *>(S)); - case StmtKind::For: - return getDerived().visitForStmt(static_cast<ForStmt *>(S)); - case StmtKind::Func: - return getDerived().visitFuncStmt(static_cast<FuncStmt *>(S)); - case StmtKind::If: - return getDerived().visitIfStmt(static_cast<IfStmt *>(S)); - case StmtKind::While: - return getDerived().visitWhileStmt(static_cast<WhileStmt *>(S)); +#define STMT(CLASS, PARENT) \ + case StmtKind::CLASS: \ + return getDerived().visit##CLASS##Stmt(static_cast<CLASS##Stmt *>(S)); + +#include "dusk/AST/StmtNodes.def" } + llvm_unreachable("All cases handeled."); } /// Visit a concrete pattern node. PatternRetTy visit(Pattern *P) { switch (P->getKind()) { - case PatternKind::Expr: - return getDerived().visitExprPattern(static_cast<ExprPattern *>(P)); - case PatternKind::Variable: - return getDerived().visitVarPattern(static_cast<VarPattern *>(P)); +#define PATTERN(CLASS, PARENT) \ + case PatternKind::CLASS: \ + return getDerived() \ + .visit##CLASS##Pattern(static_cast<CLASS##Pattern *>(P)); + +#include "dusk/AST/PatternNodes.def" } + llvm_unreachable("All cases handeles"); } /// Visits concrete TypeRepr TypeReprRetTy visit(TypeRepr *T) { switch (T->getKind()) { - case TypeReprKind::Ident: - return getDerived().visitIdentTypeRepr(static_cast<IdentTypeRepr *>(T)); - case TypeReprKind::Array: - return getDerived().visitArrayTypeRepr(static_cast<ArrayTypeRepr *>(T)); +#define TYPE_REPR(CLASS, PARENT) \ + case TypeReprKind::CLASS: \ + return getDerived() \ + .visit##CLASS##TypeRepr(static_cast<CLASS##TypeRepr *>(T)); + +#include "dusk/AST/TypeReprNodes.def" } + llvm_unreachable("All cases handeled."); } }; diff --git a/include/dusk/AST/Decl.h b/include/dusk/AST/Decl.h index 41f0b9c..0ab6e5e 100644 --- a/include/dusk/AST/Decl.h +++ b/include/dusk/AST/Decl.h @@ -35,9 +35,10 @@ class ASTWalker; class ASTContext; /// Decribes declaration type. -enum struct DeclKind { Let, Var, Param, Func, Module }; - -enum struct RetType { Void, Int }; +enum struct DeclKind { +#define DECL(CLASS, PARENT) CLASS, +#include "dusk/AST/DeclNodes.def" +}; /// Default declaration node. class Decl : public ASTNode { @@ -89,10 +90,9 @@ public: bool walk(ASTWalker &Walker); - VarDecl *getVarDecl(); - LetDecl *getLetDecl(); - ParamDecl *getParamDecl(); - FuncDecl *getFuncDecl(); +#define DECL(CLASS, PARENT) \ + CLASS##Decl *get##CLASS##Decl(); +#include "dusk/AST/DeclNodes.def" }; /// Declaration of value-holdable node diff --git a/include/dusk/AST/DeclNodes.def b/include/dusk/AST/DeclNodes.def new file mode 100644 index 0000000..026779a --- /dev/null +++ b/include/dusk/AST/DeclNodes.def @@ -0,0 +1,44 @@ +//===--- DeclNodes.def - Dusk declaration metaprogramming -------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// +// +// This file contains macros used for macro-metaprogramming with declarations. +// +//===----------------------------------------------------------------------===// + +#ifndef ABSTRACT_DECL +#define ABSTRACT_DECL(Id, Parent) +#endif + +#ifndef CONTEXT_DECL +#define CONTEXT_DECL(Id, Parent) DECL(Id, Parent) +#endif + +#ifndef FUNC_DECL +#define FUNC_DECL(Id, Parent) CONTEXT_DECL(Id, Parent) +#endif + +#ifndef VALUE_DECL +#define VALUE_DECL(Id, Parent) DECL(Id, Parent) +#endif + +ABSTRACT_DECL(Val, Decl) + VALUE_DECL(Let, ValDecl) + VALUE_DECL(Var, ValDecl) + VALUE_DECL(Param, ValDecl) + +FUNC_DECL(Func, Decl) +CONTEXT_DECL(Module, Decl) + + +#undef VALUE_DECL +#undef FUNC_DECL +#undef CONTEXT_DECL +#undef ABSTRACT_DECL +#undef DECL + diff --git a/include/dusk/AST/Expr.h b/include/dusk/AST/Expr.h index 745ccbc..3a6e97f 100644 --- a/include/dusk/AST/Expr.h +++ b/include/dusk/AST/Expr.h @@ -22,6 +22,7 @@ class IdentifierExpr; class ParenExpr; class InfixExpr; class PrefixExpr; +class AssignExpr; class CallExpr; class SubscriptExpr; class BlockStmt; @@ -35,15 +36,8 @@ class ASTWalker; /// Describes expression type. enum struct ExprKind { - NumberLiteral, - ArrayLiteral, - Identifier, - Paren, - Infix, - Assign, - Prefix, - Call, - Subscript +#define EXPR(CLASS, PARENT) CLASS, +#include "dusk/AST/ExprNodes.def" }; /// Base class for all expression type nodes. @@ -53,7 +47,7 @@ class Expr : public ASTNode { /// Type of declaration Type *Ty; - + /// Bool indicating if the expression was solved. bool Solved; @@ -71,20 +65,15 @@ public: /// 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(); +#define EXPR(CLASS, PARENT) \ + CLASS##Expr *get##CLASS##Expr(); +#include "dusk/AST/ExprNodes.def" }; /// Number literal expression encalsulation. diff --git a/include/dusk/AST/ExprNodes.def b/include/dusk/AST/ExprNodes.def new file mode 100644 index 0000000..496c7d0 --- /dev/null +++ b/include/dusk/AST/ExprNodes.def @@ -0,0 +1,29 @@ +//===--- ExprNodes.def - Dusk exression metaprogramming ---------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// +// +// This file contains macros used for macro-metaprogramming with expressions. +// +//===----------------------------------------------------------------------===// + +#ifndef ABSTRACT_EXPR +#define ABSTRACT_EXPR(Id, Parent) +#endif + +EXPR(NumberLiteral, Expr) +EXPR(ArrayLiteral, Expr) +EXPR(Identifier, Expr) +EXPR(Paren, Expr) +EXPR(Assign, Expr) +EXPR(Infix, Expr) +EXPR(Prefix, Expr) +EXPR(Call, Expr) +EXPR(Subscript, Expr) + +#undef ABSTRACT_EXPR +#undef EXPR diff --git a/include/dusk/AST/Pattern.h b/include/dusk/AST/Pattern.h index 7ae4166..bec77d1 100644 --- a/include/dusk/AST/Pattern.h +++ b/include/dusk/AST/Pattern.h @@ -27,7 +27,10 @@ class VarPattern; class ASTWalker; /// Pattern description. -enum struct PatternKind { Expr, Variable }; +enum struct PatternKind { +#define PATTERN(CLASS, PARENT) CLASS, +#include "dusk/AST/PatternNodes.def" +}; class Pattern { /// Pattern type. @@ -50,9 +53,10 @@ public: SMLoc getLocEnd() { return getSourceRange().End; } bool walk(ASTWalker &Walker); - - ExprPattern *getExprPattern(); - VarPattern *getVarPattern(); + +#define PATTERN(CLASS, PARENT) \ + CLASS##Pattern *get##CLASS##Pattern(); +#include "dusk/AST/PatternNodes.def" public: /// Only allow allocation using \c ASTContext diff --git a/include/dusk/AST/PatternNodes.def b/include/dusk/AST/PatternNodes.def new file mode 100644 index 0000000..9380215 --- /dev/null +++ b/include/dusk/AST/PatternNodes.def @@ -0,0 +1,22 @@ +//===--- PatternNodes.def - Dusk pattern metaprogramming ---------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// +// +// This file contains macros used for macro-metaprogramming with patterns. +// +//===----------------------------------------------------------------------===// + +#ifndef ABSTRACT_PATTERN +#define ABSTRACT_PATTERN(Id, Parent) +#endif + +PATTERN(Expr, Pattern) +PATTERN(Var, Pattern) + +#undef ABSTRACT_PATTERN +#undef PATTERN diff --git a/include/dusk/AST/Stmt.h b/include/dusk/AST/Stmt.h index ed04535..cdb53a1 100644 --- a/include/dusk/AST/Stmt.h +++ b/include/dusk/AST/Stmt.h @@ -38,16 +38,8 @@ class ASTContext; /// Describes statement type. enum struct StmtKind { - Break, - Return, - Subscript, - Range, - Extern, - Block, - Func, - For, - While, - If +#define STMT(CLASS, PARENT) CLASS, +#include "dusk/AST/StmtNodes.def" }; class Stmt : public ASTNode { diff --git a/include/dusk/AST/StmtNodes.def b/include/dusk/AST/StmtNodes.def new file mode 100644 index 0000000..a98377d --- /dev/null +++ b/include/dusk/AST/StmtNodes.def @@ -0,0 +1,38 @@ +//===--- StmtNodes.def - Dusk statement metaprogramming ---------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// +// +// This file contains macros used for macro-metaprogramming with statements. +// +//===----------------------------------------------------------------------===// + +#ifndef ABSTRACT_STMT +#define ABSTRACT_STMT(Id, Parent) +#endif + +#ifndef CONTEXT_STMT +#define CONTEXT_STMT(Id, Parent) STMT(Id, Parent) +#endif + +#ifndef CONTROL_STMT +#define CONTROL_STMT(Id, Parent) CONTEXT_STMT(Id, Parent) +#endif + +STMT(Break, Stmt) +STMT(Return, Stmt) +STMT(Subscript, Stmt) +STMT(Range, Stmt) +CONTEXT_STMT(Block, Stmt) +CONTEXT_STMT(Extern, Stmt) +CONTEXT_STMT(Func, Stmt) +CONTROL_STMT(For, Stmt) +CONTROL_STMT(While, Stmt) +CONTROL_STMT(If, Stmt) + +#undef ABSTRACT_STMT +#undef STMT diff --git a/include/dusk/AST/Type.h b/include/dusk/AST/Type.h index fb731df..6136f61 100644 --- a/include/dusk/AST/Type.h +++ b/include/dusk/AST/Type.h @@ -27,9 +27,10 @@ class PatternType; class ArrayType; class ASTContext; -enum struct TypeKind; - -enum struct TypeKind { Void, Int, Value, Pattern, Array, Function }; +enum struct TypeKind { +#define TYPE(CLASS, PARENT) CLASS, +#include "dusk/AST/TypeNodes.def" +}; class Type { /// Exact kind of the type. @@ -44,12 +45,10 @@ public: 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(); - +#define TYPE(CLASS, PARENT) \ + CLASS##Type *get##CLASS##Type(); +#include "dusk/AST/TypeNodes.def" + private: void *operator new(size_t Bytes) throw() = delete; void operator delete(void *Data) throw() = delete; @@ -149,7 +148,7 @@ public: } bool isClassOf(const PatternType *T) const; }; - + } // namespace dusk #endif /* DUSK_TYPE_H */ diff --git a/include/dusk/AST/TypeNodes.def b/include/dusk/AST/TypeNodes.def new file mode 100644 index 0000000..7b6278f --- /dev/null +++ b/include/dusk/AST/TypeNodes.def @@ -0,0 +1,33 @@ +//===--- TypeNodes.def - Dusk type metaprogramming --------------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// +// +// This file contains macros used for macro-metaprogramming with types. +// +//===----------------------------------------------------------------------===// + +#ifndef ABSTRACT_TYPE +#define ABSTRACT_TYPE(Id, Parent) +#endif + +#ifndef VALUE_TYPE +#define VALUE_TYPE(Id, Parent) TYPE(Id, Parent) +#endif + +ABSTRACT_TYPE(Value, Type) + VALUE_TYPE(Int, Value) + VALUE_TYPE(Array, Value) + +TYPE(Void, Type) +TYPE(Function, Type) +TYPE(Pattern, Type) + + +#undef VALUE_TYPE +#undef ABSTRACT_TYPE +#undef TYPE diff --git a/include/dusk/AST/TypeRepr.h b/include/dusk/AST/TypeRepr.h index a365632..77b4248 100644 --- a/include/dusk/AST/TypeRepr.h +++ b/include/dusk/AST/TypeRepr.h @@ -25,8 +25,8 @@ class ASTWalker; class ASTContext; enum struct TypeReprKind { - Ident, - Array +#define TYPE_REPR(CLASS, PARENT) CLASS, +#include "dusk/AST/TypeReprNodes.def" }; class TypeRepr { @@ -47,8 +47,9 @@ public: bool walk(ASTWalker &Walker); - IdentTypeRepr *getIdentTypeRepr(); - ArrayTypeRepr *getArrayTypeRepr(); +#define TYPE_REPR(CLASS, PARENT) \ + CLASS##TypeRepr *get##CLASS##TypeRepr(); +#include "dusk/AST/TypeReprNodes.def" public: /// Only allow allocation using \c ASTContext diff --git a/include/dusk/AST/TypeReprNodes.def b/include/dusk/AST/TypeReprNodes.def new file mode 100644 index 0000000..18472d7 --- /dev/null +++ b/include/dusk/AST/TypeReprNodes.def @@ -0,0 +1,22 @@ +//===--- TypeReprNodes.def - Dusk type repr metaprogramming ------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// +// +// This file contains macros used for macro-metaprogramming with patterns. +// +//===----------------------------------------------------------------------===// + +#ifndef ABSTRACT_TYPE_REPR +#define ABSTRACT_TYPE_REPR(Id, Parent) +#endif + +TYPE_REPR(Ident, TypeRepr) +TYPE_REPR(Array, TypeRepr) + +#undef ABSTRACT_TYPE_REPR +#undef TYPE_REPR diff --git a/include/dusk/Basic/CMakeLists.txt b/include/dusk/Basic/CMakeLists.txt index 4ddb23f..273fb36 100644 --- a/include/dusk/Basic/CMakeLists.txt +++ b/include/dusk/Basic/CMakeLists.txt @@ -1,7 +1,7 @@ set(HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/LLVM.h ${CMAKE_CURRENT_SOURCE_DIR}/SourceManager.h - ${CMAKE_CURRENT_SOURCE_DIR}/TokenDefinition.h + ${CMAKE_CURRENT_SOURCE_DIR}/TokenDefinitions.h ${HEADERS} PARENT_SCOPE ) diff --git a/include/dusk/Basic/TokenDefinition.h b/include/dusk/Basic/TokenDefinition.h deleted file mode 100644 index 939e953..0000000 --- a/include/dusk/Basic/TokenDefinition.h +++ /dev/null @@ -1,186 +0,0 @@ -//===--- TokenDefinition.h --------------------------------------*- C++ -*-===// -// -// 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. -// -//===----------------------------------------------------------------------===// - -#ifndef DUSK_TOKEN_DEFINITION_H -#define DUSK_TOKEN_DEFINITION_H - -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" - -namespace dusk { - -enum struct tok { - // Keywords - kwVar, - kwLet, - kwBreak, - kwReturn, - kwIf, - kwElse, - kwWhile, - kwFor, - kwIn, - kwFunc, - kwExtern, - - // Identifier - identifier, // [a-zA-Z_][a-zA-Z0-9_]+ - - // Literal - number_literal, // dec: [0-9]+ - // hex: 0(x|X)[0-9a-fA-F]+ - // oct: 0(o|O)[0-7]+ - // bin: 0(b|B)(0|1)+ - - comment, // // or /* */ - - // Operators - assign, // = - arrow, // -> - colon, // : - - elipsis_excl, // .. - elipsis_incl, // ... - - semicolon, // ; - comma, // , - - l_brace, // { - r_brace, // } - - l_bracket, // [ - r_bracket, // ] - - l_paren, // ( - r_paren, // ) - - // Arithmetic Operators - plus, // + - minus, // - - mod, // % - divide, // / - multipy, // * - - // Logical Operators - land, // && - lor, // || - - equals, // == - nequals, // != - less, // < - less_eq, // <= - greater, // > - greater_eq, // >= - - lnot, // ! - - // End of file - eof, - - // Unknown token - unknown -}; - -} // namespace dusk - -namespace llvm { -constexpr inline raw_ostream &operator<<(raw_ostream &OS, const dusk::tok &T) { - switch (T) { - // Keywords - case dusk::tok::kwVar: - return OS << "var"; - case dusk::tok::kwLet: - return OS << "let"; - case dusk::tok::kwBreak: - return OS << "break"; - case dusk::tok::kwReturn: - return OS << "return"; - case dusk::tok::kwIf: - return OS << "if"; - case dusk::tok::kwElse: - return OS << "else"; - case dusk::tok::kwWhile: - return OS << "while"; - case dusk::tok::kwFor: - return OS << "for"; - case dusk::tok::kwIn: - return OS << "in"; - case dusk::tok::kwFunc: - return OS << "func"; - case dusk::tok::kwExtern: - return OS << "extern"; - - // Operators - case dusk::tok::assign: - return OS << "="; - case dusk::tok::arrow: - return OS << "->"; - case dusk::tok::elipsis_excl: - return OS << ".."; - case dusk::tok::elipsis_incl: - return OS << "..."; - case dusk::tok::colon: - return OS << ":"; - case dusk::tok::semicolon: - return OS << ";"; - case dusk::tok::comma: - return OS << ","; - case dusk::tok::l_brace: - return OS << "{"; - case dusk::tok::r_brace: - return OS << "}"; - case dusk::tok::l_bracket: - return OS << "["; - case dusk::tok::r_bracket: - return OS << "]"; - case dusk::tok::l_paren: - return OS << "("; - case dusk::tok::r_paren: - return OS << ")"; - - // Arithmetic Operators - case dusk::tok::plus: - return OS << "+"; - case dusk::tok::minus: - return OS << "-"; - case dusk::tok::mod: - return OS << "%"; - case dusk::tok::divide: - return OS << "/"; - case dusk::tok::multipy: - return OS << "*"; - - // Logical Operators - case dusk::tok::lnot: - return OS << "!"; - case dusk::tok::land: - return OS << "&&"; - case dusk::tok::lor: - return OS << "||"; - case dusk::tok::equals: - return OS << "=="; - case dusk::tok::nequals: - return OS << "!="; - case dusk::tok::less: - return OS << "<"; - case dusk::tok::less_eq: - return OS << "<="; - case dusk::tok::greater: - return OS << ">"; - case dusk::tok::greater_eq: - return OS << ">="; - default: - llvm_unreachable("Invalid token string conversion."); - } - return OS; -} - -} // namespace llvm - -#endif /* DUSK_TOKEN_DEFINITION_H */ diff --git a/include/dusk/Basic/TokenDefinitions.def b/include/dusk/Basic/TokenDefinitions.def new file mode 100644 index 0000000..227a5f3 --- /dev/null +++ b/include/dusk/Basic/TokenDefinitions.def @@ -0,0 +1,142 @@ +//===--- TokenDefinitions.def - Dusk token metaprogramming -------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// +// +// This file contains macros used for macro-metaprogramming with patterns. +// +//===----------------------------------------------------------------------===// + +/// TOKEN(name) +/// Expands by default for every token kind. +#ifndef TOKEN +#define TOKEN(name) +#endif + +/// KEYWORD(kw) +/// Expands by default for eveny Dusk token such as 'if', 'else', etc. +/// +/// \note Each token kind is prefixed with 'kw_'. +#ifndef KEYWORD +#define KEYWORD(kw) TOKEN(kw_ ## kw) +#endif + +/// DECL_KEYWORD(kw) +/// Expands for each keyword that is used in a declaration such as 'let'. +#ifndef DECL_KEYWORD +#define DECL_KEYWORD(kw) KEYWORD(kw) +#endif + +/// EXPR_KEYWORD(kw) +/// Expands for each keyword that is used as an expression such as 'true'. +/// +/// \note There are no such keywords just yet. +#ifndef EXPR_KEYWORD +#define EXPR_KEYWORD(kw) KEYWORD(kw) +#endif + +/// STMT_KEYWORD(kw) +/// Expands for each keyword that is used in statement such as 'for'. +#ifndef STMT_KEYWORD +#define STMT_KEYWORD(kw) KEYWORD(kw) +#endif + +/// LITERAL(name) +/// Tokens representing literals such as 'number'. +/// +/// \note Each token kind is suffixed with '_literal'. +#ifndef LITERAL +#define LITERAL(name) TOKEN(name ## _literal) +#endif + +/// PUNCTUATOR(name, str) +/// Expands for every Dusk punctuator. +/// +/// \param name Name of the punctuator such as 'l_paren' etc. +/// +/// \param str A string literal containing the spelling of the punctuator. +/// such as '(' or '->'. +#ifndef PUNCTUATOR +#define PUNCTUATOR(name, str) TOKEN(name) +#endif + +/// MISC(name) +/// Miscellaneous tokens, e.g. 'eof' and 'unknown'. +#ifndef MISC +#define MISC(name) TOKEN(name) +#endif + +// Declaration keywords +DECL_KEYWORD(var) +DECL_KEYWORD(let) + +// Statement keywords +STMT_KEYWORD(break) +STMT_KEYWORD(return) +STMT_KEYWORD(if) +STMT_KEYWORD(else) +STMT_KEYWORD(while) +STMT_KEYWORD(for) +STMT_KEYWORD(in) +STMT_KEYWORD(func) +STMT_KEYWORD(extern) + +// Punctuators +PUNCTUATOR(assign, "=") +PUNCTUATOR(arrow, "->") +PUNCTUATOR(colon, ":") +PUNCTUATOR(semi, ";") +PUNCTUATOR(comma, ",") + +PUNCTUATOR(elipsis_excl, "..") +PUNCTUATOR(elipsis_incl, "...") + +PUNCTUATOR(l_paren, "(") +PUNCTUATOR(r_paren, ")") +PUNCTUATOR(l_bracket, "[") +PUNCTUATOR(r_bracket, "]") +PUNCTUATOR(l_brace, "{") +PUNCTUATOR(r_brace, "}") + +PUNCTUATOR(plus, "+") +PUNCTUATOR(minus, "-") +PUNCTUATOR(mod, "%") +PUNCTUATOR(divide, "/") +PUNCTUATOR(multipy, "*") + +PUNCTUATOR(land, "&&") +PUNCTUATOR(lor, "||") + +PUNCTUATOR(equals, "==") +PUNCTUATOR(nequals, "!=") +PUNCTUATOR(less, "<") +PUNCTUATOR(less_eq, "<=") +PUNCTUATOR(greater, ">") +PUNCTUATOR(greater_eq, ">=") + +PUNCTUATOR(lnot, "!") + +// Single token literals +LITERAL(number) // dec: [0-9]+ + // hex: 0(x|X)[0-9a-fA-F]+ + // oct: 0(o|O)[0-7]+ + // bin: 0(b|B)(0|1)+ + +// Miscellaneous tokens +MISC(identifier) // [a-zA-Z_][a-zA-Z0-9_]+ +MISC(comment) +MISC(eof) +MISC(unknown) + +#undef TOKEN +#undef KEYWORD +#undef DECL_KEYWORD +#undef EXPR_KEYWORD +#undef STMT_KEYWORD +#undef LITERAL +#undef PUNCTUATOR +#undef MISC diff --git a/include/dusk/Basic/TokenDefinitions.h b/include/dusk/Basic/TokenDefinitions.h new file mode 100644 index 0000000..1601fd5 --- /dev/null +++ b/include/dusk/Basic/TokenDefinitions.h @@ -0,0 +1,25 @@ +//===--- TokenDefinitions.h -------------------------------------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef DUSK_TOKEN_DEFINITIONS_H +#define DUSK_TOKEN_DEFINITIONS_H + +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +namespace dusk { + +enum struct tok { +#define TOKEN(TOK) TOK, +#include "dusk/Basic/TokenDefinitions.def" +}; + +} // namespace dusk + +#endif /* DUSK_TOKEN_DEFINITIONS_H */ diff --git a/include/dusk/Parse/Parser.h b/include/dusk/Parse/Parser.h index 7065128..bda2374 100644 --- a/include/dusk/Parse/Parser.h +++ b/include/dusk/Parse/Parser.h @@ -98,10 +98,12 @@ private: // //===------------------------------------------------------------------------=== - ASTNode *parseGlobal(); + ASTNode *parse(); // MARK: - Declarations + Decl *parseDecl(); + Decl *parseVarDecl(); Decl *parseLetDecl(); diff --git a/include/dusk/Parse/Token.h b/include/dusk/Parse/Token.h index 65879dd..3666a99 100644 --- a/include/dusk/Parse/Token.h +++ b/include/dusk/Parse/Token.h @@ -11,7 +11,7 @@ #define DUSK_TOKEN_H #include "dusk/Basic/LLVM.h" -#include "dusk/Basic/TokenDefinition.h" +#include "dusk/Basic/TokenDefinitions.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/SMLoc.h" @@ -112,21 +112,18 @@ public: /// Returns \c true, if token is a keyword, \c false otherwise. bool isKeyword() const { switch (Kind) { - case tok::kwVar: - case tok::kwLet: + case tok::kw_var: + case tok::kw_let: - case tok::kwBreak: - case tok::kwReturn: - case tok::kwIf: - case tok::kwElse: - case tok::kwWhile: - case tok::kwFor: - case tok::kwIn: - case tok::kwFunc: - case tok::kwExtern: - -// case tok::kwVoid: -// case tok::kwInt: + case tok::kw_break: + case tok::kw_return: + case tok::kw_if: + case tok::kw_else: + case tok::kw_while: + case tok::kw_for: + case tok::kw_in: + case tok::kw_func: + case tok::kw_extern: return true; default: diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 23180da..87c857a 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -16,11 +16,27 @@ #include "dusk/AST/Type.h" #include "dusk/AST/TypeRepr.h" #include "dusk/AST/ASTVisitor.h" -#include "dusk/Basic/TokenDefinition.h" +#include "dusk/Basic/TokenDefinitions.h" #include "dusk/Frontend/Formatter.h" using namespace dusk; +namespace llvm { + llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, tok keyword) { + switch (keyword) { +#define KEYWORD(KW) \ + case tok::kw_##KW: OS << #KW; break; +#define PUNCTUATOR(PUN, TEXT) \ + case tok::PUN: OS << TEXT; break; +#include "dusk/Basic/TokenDefinitions.def" + default: + llvm_unreachable("unexpected keyword or punctuator kind"); + } + return OS; + } +} // namespace llvm + + namespace { /// AST pretty printing. @@ -29,7 +45,7 @@ class PrintAST : public ASTVisitor<PrintAST> { typedef ASTVisitor<PrintAST> super; friend super; - + /// AST pretty printer. ASTPrinter &Printer; @@ -46,7 +62,7 @@ public: auto E = dynamic_cast<Expr *>(N); if (E) Printer.printNewline(); - + if (auto D = dynamic_cast<Decl *>(N)) super::visit(D); else if (E != nullptr) @@ -55,7 +71,7 @@ public: super::visit(S); else llvm_unreachable("Unexpected node"); - + if (E) Printer.printText(";"); } @@ -65,12 +81,12 @@ public: void visitLetDecl(LetDecl *D) { Printer.printDeclPre(D); Printer << D->getName(); - + if (D->hasTypeRepr()) { Printer << ": "; super::visit(D->getTypeRepr()); } - + if (D->hasValue()) { Printer << " " << tok::assign << " "; super::visit(D->getValue()); @@ -81,12 +97,12 @@ public: void visitVarDecl(VarDecl *D) { Printer.printDeclPre(D); Printer << D->getName(); - + if (D->hasTypeRepr()) { Printer << ": "; super::visit(D->getTypeRepr()); } - + if (D->hasValue()) { Printer << " " << tok::assign << " "; super::visit(D->getValue()); @@ -99,12 +115,12 @@ public: Printer << D->getName() << "("; super::visit(D->getArgs()); Printer << ")"; - + if (D->hasTypeRepr()) { Printer << " -> "; super::visit(D->getTypeRepr()); } - + Printer.printDeclPost(D); } @@ -124,13 +140,13 @@ public: StringRef Str = {St, (size_t)(En - St)}; Printer << Str; } - + void visitArrayLiteralExpr(ArrayLiteralExpr *E) { Printer << "["; super::visit(E->getValues()); Printer << "]"; } - + void visitIdentifierExpr(IdentifierExpr *E) { Printer << E->getName(); } @@ -174,14 +190,14 @@ public: void visitBreakStmt(BreakStmt *S) { Printer.printStmtPre(S); - Printer << tok::kwBreak; + Printer << tok::kw_break; Printer.printStmtPost(S); } void visitReturnStmt(ReturnStmt *S) { Printer.printStmtPre(S); - Printer << tok::kwReturn << " "; + Printer << tok::kw_return << " "; super::visit(S->getValue()); Printer.printStmtPost(S); @@ -198,7 +214,7 @@ public: super::visit(S->getStart()); Printer << (S->isInclusive() ? tok::elipsis_incl : tok::elipsis_excl); - + super::visit(S->getEnd()); Printer.printStmtPost(S); } @@ -211,7 +227,7 @@ public: IsFirst = false; else Printer.printNewline(); - + auto E = dynamic_cast<Expr *>(N); if (auto D = dynamic_cast<Decl *>(N)) @@ -222,7 +238,7 @@ public: super::visit(S); else llvm_unreachable("Unexpected node"); - + if (E) Printer.printText(";"); } @@ -231,11 +247,11 @@ public: void visitExternStmt(ExternStmt *S) { Printer.printStmtPre(S); - Printer << tok::kwExtern << " "; + Printer << tok::kw_extern << " "; super::visit(S->getPrototype()); Printer.printStmtPost(S); } - + void visitFuncStmt(FuncStmt *S) { Printer.printStmtPre(S); super::visit(S->getPrototype()); @@ -243,13 +259,13 @@ public: super::visit(S->getBody()); Printer.printStmtPost(S); } - + void visitForStmt(ForStmt *S) { Printer.printStmtPre(S); - Printer << tok::kwFor << " "; + Printer << tok::kw_for << " "; super::visit(S->getIter()); - Printer << " " << tok::kwIn << " "; + Printer << " " << tok::kw_in << " "; super::visit(S->getRange()); Printer << " "; super::visit(S->getBody()); @@ -259,25 +275,25 @@ public: void visitWhileStmt(WhileStmt *S) { Printer.printStmtPre(S); - Printer << tok::kwWhile << " "; - + Printer << tok::kw_while << " "; + super::visit(S->getCond()); Printer << " "; super::visit(S->getBody()); - + Printer.printStmtPost(S); } - + void visitIfStmt(IfStmt *S) { Printer.printStmtPre(S); - Printer << tok::kwIf << " "; + Printer << tok::kw_if << " "; super::visit(S->getCond()); Printer << " "; super::visit(S->getThen()); if (S->hasElseBlock()) { - Printer << " " << tok::kwElse << " "; + Printer << " " << tok::kw_else << " "; super::visit(S->getElse()); } @@ -301,13 +317,13 @@ public: super::visit(V); } } - + // MARK: - Type representations - + void visitIdentTypeRepr(IdentTypeRepr *T) { Printer << T->getIdent(); } - + void visitArrayTypeRepr(ArrayTypeRepr *T) { super::visit(T->getBaseTyRepr()); super::visit(T->getSize()); @@ -315,7 +331,7 @@ public: }; // MARK: - Pretty Printer - + /// Implementation of an \c ASTPrinter, which is used to pretty print the AST. class PrettyPrinter : public StreamPrinter { public: @@ -328,15 +344,15 @@ public: case DeclKind::Let: if (!isAtStartOfLine()) printNewline(); - KW = tok::kwLet; + KW = tok::kw_let; break; case DeclKind::Var: if (!isAtStartOfLine()) printNewline(); - KW = tok::kwVar; + KW = tok::kw_var; break; case DeclKind::Func: - KW = tok::kwFunc; + KW = tok::kw_func; break; default: return; @@ -401,7 +417,7 @@ public: virtual void printPatternPre(Pattern *P) override { switch (P->getKind()) { - case PatternKind::Variable: + case PatternKind::Var: case PatternKind::Expr: break; } @@ -409,7 +425,7 @@ public: virtual void printPatternPost(Pattern *P) override { switch (P->getKind()) { - case PatternKind::Variable: + case PatternKind::Var: case PatternKind::Expr: break; } @@ -533,7 +549,6 @@ void StreamPrinter::printText(StringRef Text) { OS << Text; } void Formatter::format() { PrettyPrinter pp(OS); - PrintAST p(pp); - p.ASTVisitor::visit(Ctx.getRootModule()); + PrintAST(pp).ASTVisitor::visit(Ctx.getRootModule()); } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 60a1854..3f13e54 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -20,25 +20,12 @@ 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); +#define DECL(CLASS, PARENT) \ +CLASS##Decl *Decl::get##CLASS##Decl() { \ + assert(Kind == DeclKind::CLASS && "Invalid convertion"); \ + return static_cast<CLASS##Decl *>(this); \ } +#include "dusk/AST/DeclNodes.def" 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 24b06f8..8509e7e 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -18,45 +18,12 @@ using namespace dusk; 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); +#define EXPR(CLASS, PARENT) \ +CLASS##Expr *Expr::get##CLASS##Expr() { \ + assert(Kind == ExprKind::CLASS && "Invalid Expr convertion"); \ + return static_cast<CLASS##Expr *>(this); \ } +#include "dusk/AST/ExprNodes.def" // MARK: - Number literal expresssion diff --git a/lib/AST/Pattern.cpp b/lib/AST/Pattern.cpp index d7e68c0..f8c4f6a 100644 --- a/lib/AST/Pattern.cpp +++ b/lib/AST/Pattern.cpp @@ -18,15 +18,12 @@ 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); +#define PATTERN(CLASS, PARENT) \ +CLASS##Pattern *Pattern::get##CLASS##Pattern() { \ + assert(Kind == PatternKind::CLASS && "Invalid conversion"); \ + return static_cast<CLASS##Pattern *>(this); \ } +#include "dusk/AST/PatternNodes.def" void *Pattern::operator new(size_t Bytes, ASTContext &Context) { return Context.Allocate(Bytes); @@ -43,7 +40,7 @@ size_t ExprPattern::count() const { return Values.size(); } // MARK: - Variable pattern VarPattern::VarPattern(SmallVector<Decl *, 128> &&V, SMLoc L, SMLoc R) - : Pattern(PatternKind::Variable), Vars(V), LPar(L), RPar(R) {} + : Pattern(PatternKind::Var), Vars(V), LPar(L), RPar(R) {} SMRange VarPattern::getSourceRange() const { return {LPar, RPar}; } size_t VarPattern::count() const { return Vars.size(); } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index a5a6274..f23d1e1 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -14,33 +14,15 @@ using namespace dusk; Type::Type(TypeKind K) : Kind(K) {} -void *Type::operator new(size_t Bytes, ASTContext &Context) { - return Context.Allocate(Bytes); -} - -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); +#define TYPE(CLASS, PARENT) \ +CLASS##Type *Type::get##CLASS##Type() { \ + assert(Kind == TypeKind::CLASS && "Invalid conversion"); \ + return static_cast<CLASS##Type *>(this); \ } +#include "dusk/AST/TypeNodes.def" -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); +void *Type::operator new(size_t Bytes, ASTContext &Context) { + return Context.Allocate(Bytes); } ValueType::ValueType(TypeKind K) : Type(K) {} diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index 7afa232..bcc7bfc 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -15,15 +15,12 @@ using namespace dusk; TypeRepr::TypeRepr(TypeReprKind K) : Kind(K), Ty(nullptr) {} -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); +#define TYPE_REPR(CLASS, PARENT) \ +CLASS##TypeRepr *TypeRepr::get##CLASS##TypeRepr() { \ + assert(Kind == TypeReprKind::CLASS && "Invalid conversion"); \ + return static_cast<CLASS##TypeRepr *>(this); \ } +#include "dusk/AST/TypeReprNodes.def" 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 545a042..707c40c 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -221,39 +221,17 @@ public: 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 visitArrayLiteralExpr(ArrayLiteralExpr *E) { - return codegenExpr(IRGF.IRGM, E) != nullptr; - } - bool visitIdentifierExpr(IdentifierExpr *E) { - return codegenExpr(IRGF.IRGM, E) != nullptr; - } - bool visitParenExpr(ParenExpr *E) { - return codegenExpr(IRGF.IRGM, E) != nullptr; - } - bool visitAssignExpr(AssignExpr *E) { - return codegenExpr(IRGF.IRGM, E) != nullptr; - } - bool visitInfixExpr(InfixExpr *E) { - return codegenExpr(IRGF.IRGM, E) != nullptr; - } - bool visitPrefixExpr(PrefixExpr *E) { - return codegenExpr(IRGF.IRGM, E) != nullptr; - } - bool visitCallExpr(CallExpr *E) { - return codegenExpr(IRGF.IRGM, E) != nullptr; - } - bool visitSubscriptExpr(SubscriptExpr *E) { - return codegenExpr(IRGF.IRGM, E) != nullptr; + +#define EXPR(CLASS, PARENT) \ + bool visit##CLASS##Expr(CLASS##Expr *E) { \ + return codegenExpr(IRGF.IRGM, E) != nullptr; \ } +#include "dusk/AST/ExprNodes.def" }; } // anonymous namespace bool irgen::genFunc(IRGenFunc &IRGF, FuncStmt *F) { - GenFunc GF(IRGF); - return GF.ASTVisitor::visit(F->getBody()); + return GenFunc(IRGF).visit(F->getBody()); } diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index 9540549..770e5a8 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -38,17 +38,22 @@ llvm::Type *irgen::codegenArrayType(IRGenModule &IRGM, ArrayType *Ty) { return llvm::ArrayType::get(BaseTy, Ty->getSize()); } +llvm::Type *codegenFunctionType(IRGenModule &IRGM, FunctionType *Ty) { + return nullptr; +} + +llvm::Type *codegenPatternType(IRGenModule &IRGM, PatternType *Ty) { + return nullptr; +} + llvm::Type *irgen::codegenType(IRGenModule &IRGM, Type *Ty) { switch (Ty->getKind()) { - case TypeKind::Int: - return codegenIntType(IRGM, static_cast<IntType *>(Ty)); - case TypeKind::Void: - return codegenVoidType(IRGM, static_cast<VoidType *>(Ty)); - case TypeKind::Array: - return codegenArrayType(IRGM, static_cast<ArrayType *>(Ty)); - default: - llvm_unreachable("Unexpeccted type."); +#define TYPE(CLASS, PARENT) \ + case TypeKind::CLASS: \ + return codegen##CLASS##Type(IRGM, static_cast<CLASS##Type *>(Ty)); +#include "dusk/AST/TypeNodes.def" } + llvm_unreachable("All cases handeled"); } // MARK: - Initialization generation diff --git a/lib/Parser/Lexer.cpp b/lib/Parser/Lexer.cpp index e255d29..ffc72cd 100644 --- a/lib/Parser/Lexer.cpp +++ b/lib/Parser/Lexer.cpp @@ -159,7 +159,7 @@ void Lexer::lexToken() { case ':': return formToken(tok::colon, TokStart); case ';': - return formToken(tok::semicolon, TokStart); + return formToken(tok::semi, TokStart); case '{': return formToken(tok::l_brace, TokStart); @@ -300,17 +300,17 @@ void Lexer::diagnose(Token T, diag::DiagID ID) { tok Lexer::kindOfIdentifier(StringRef Str) { return llvm::StringSwitch<tok>(Str) - .Case("var", tok::kwVar) - .Case("let", tok::kwLet) - .Case("break", tok::kwBreak) - .Case("return", tok::kwReturn) - .Case("if", tok::kwIf) - .Case("else", tok::kwElse) - .Case("while", tok::kwWhile) - .Case("for", tok::kwFor) - .Case("in", tok::kwIn) - .Case("func", tok::kwFunc) - .Case("extern", tok::kwExtern) + .Case("var", tok::kw_var) + .Case("let", tok::kw_let) + .Case("break", tok::kw_break) + .Case("return", tok::kw_return) + .Case("if", tok::kw_if) + .Case("else", tok::kw_else) + .Case("while", tok::kw_while) + .Case("for", tok::kw_for) + .Case("in", tok::kw_in) + .Case("func", tok::kw_func) + .Case("extern", tok::kw_extern) .Default(tok::identifier); } diff --git a/lib/Parser/ParseDecl.cpp b/lib/Parser/ParseDecl.cpp index b74724c..9a88fc0 100644 --- a/lib/Parser/ParseDecl.cpp +++ b/lib/Parser/ParseDecl.cpp @@ -11,6 +11,20 @@ using namespace dusk; +Decl *Parser::parseDecl() { + switch (Tok.getKind()) { + case tok::kw_let: + return parseLetDecl(); + case tok::kw_var: + return parseVarDecl(); + case tok::kw_func: + return parseFuncDecl(); + + default: + return nullptr; + } +} + /// Let declaration /// /// LetDecl ::= @@ -18,7 +32,7 @@ using namespace dusk; /// 'let' identifier '=' Expr ';' Decl *Parser::parseLetDecl() { // Validate correct variable decl - assert(Tok.is(tok::kwLet) && "Invalid parsing method."); + assert(Tok.is(tok::kw_let) && "Invalid parsing method."); auto L = consumeToken(); auto ID = Tok; @@ -45,7 +59,7 @@ Decl *Parser::parseLetDecl() { /// 'var' identifier '=' Expr ';' Decl *Parser::parseVarDecl() { // Validate correct variable decl - assert(Tok.is(tok::kwVar) && "Invalid parsing method."); + assert(Tok.is(tok::kw_var) && "Invalid parsing method."); auto L = consumeToken(); auto ID = Tok; @@ -69,7 +83,7 @@ Decl *Parser::parseVarDecl() { /// '=' Expr ';' Expr *Parser::parseDeclValue() { /// Empty initialization. - if (consumeIf(tok::semicolon)) + if (consumeIf(tok::semi)) return nullptr; if (!consumeIf(tok::assign)) { @@ -78,7 +92,7 @@ Expr *Parser::parseDeclValue() { } auto E = parseExpr(); - if (!consumeIf(tok::semicolon)) { + if (!consumeIf(tok::semi)) { diagnose(Tok.getLoc(), diag::DiagID::expected_semicolon) .fixItAfter(";", Tok.getLoc()); return nullptr; @@ -92,7 +106,7 @@ Expr *Parser::parseDeclValue() { /// 'func' identifier '(' Args ')' RetType CodeBlock Decl *Parser::parseFuncDecl() { // Ensure `func` keyword - assert(Tok.is(tok::kwFunc) && "Invalid parsing method."); + assert(Tok.is(tok::kw_func) && "Invalid parsing method."); auto FL = consumeToken(); @@ -125,7 +139,7 @@ TypeRepr *Parser::parseValDeclType() { /// '->' 'Int' | 'Void' TypeRepr *Parser::parseFuncDeclType() { // Implicit return type is `Void` - if (Tok.isAny(tok::l_brace, tok::semicolon)) + if (Tok.isAny(tok::l_brace, tok::semi)) return nullptr; if (!consumeIf(tok::arrow)) { diff --git a/lib/Parser/ParseExpr.cpp b/lib/Parser/ParseExpr.cpp index 7a10d3e..6269617 100644 --- a/lib/Parser/ParseExpr.cpp +++ b/lib/Parser/ParseExpr.cpp @@ -87,7 +87,7 @@ Expr *Parser::parsePrimaryExprRHS(Expr *Dest) { case tok::r_bracket: case tok::l_brace: case tok::comma: - case tok::semicolon: + case tok::semi: return Dest; /// Enable nested postfix operator expression e.g. <code>a[1][2]</code>. diff --git a/lib/Parser/ParseStmt.cpp b/lib/Parser/ParseStmt.cpp index d1f84a3..9b40d30 100644 --- a/lib/Parser/ParseStmt.cpp +++ b/lib/Parser/ParseStmt.cpp @@ -13,7 +13,47 @@ using namespace dusk; -ASTNode *Parser::parseStatement() { return nullptr; } +ASTNode *Parser::parseStatement() { + while (true) { + switch (Tok.getKind()) { + // End of the code block; + case tok::r_brace: + return nullptr; + + // Empty statement + case tok::semi: + consumeToken(); + break; + + case tok::identifier: + case tok::number_literal: + case tok::l_bracket: + case tok::l_paren: + return parseExprStmt(); + + case tok::kw_break: + return parseBreakStmt(); + + case tok::kw_return: + return parseReturnStmt(); + + case tok::kw_func: + return parseFuncStmt(); + + case tok::kw_for: + return parseForStmt(); + + case tok::kw_if: + return parseIfStmt(); + + case tok::kw_while: + return parseWhileStmt(); + + default: + return nullptr; + } + } +} /// ExprStmt ::= /// Expr ';' @@ -30,7 +70,7 @@ Expr *Parser::parseExprStmt() { diagnose(Tok.getLoc()); return nullptr; } - if (!consumeIf(tok::semicolon)) { + if (!consumeIf(tok::semi)) { diagnose(PreviousLoc, diag::DiagID::expected_semicolon) .fixItAfter(";", PreviousLoc); return nullptr; @@ -42,12 +82,12 @@ Expr *Parser::parseExprStmt() { /// break ';' Stmt *Parser::parseBreakStmt() { // Validate `break` keyword - assert(Tok.is(tok::kwBreak) && "Invalid parse method."); + assert(Tok.is(tok::kw_break) && "Invalid parse method."); auto T = Tok.getText(); auto S = consumeToken(); auto E = llvm::SMLoc::getFromPointer(T.data() + T.size()); - if (!consumeIf(tok::semicolon)) { + if (!consumeIf(tok::semi)) { diagnose(PreviousLoc, diag::DiagID::expected_semicolon) .fixItAfter(";", PreviousLoc); return nullptr; @@ -59,7 +99,7 @@ Stmt *Parser::parseBreakStmt() { /// return Expr ';' Stmt *Parser::parseReturnStmt() { // Validate `return` keyword - assert(Tok.is(tok::kwReturn) && "Invalid parse method."); + assert(Tok.is(tok::kw_return) && "Invalid parse method."); auto RL = consumeToken(); Expr *E = nullptr; @@ -72,8 +112,10 @@ Stmt *Parser::parseReturnStmt() { case tok::l_bracket: E = parseExpr(); break; - case tok::semicolon: + + case tok::semi: break; + default: if (Tok.isNot(tok::eof)) consumeToken(); @@ -81,7 +123,7 @@ Stmt *Parser::parseReturnStmt() { break; } - if (!consumeIf(tok::semicolon)) { + if (!consumeIf(tok::semi)) { diagnose(PreviousLoc, diag::expected_semicolon) .fixItAfter(";", PreviousLoc); return nullptr; @@ -115,7 +157,7 @@ Stmt *Parser::parseBlock() { // Gather code block body std::vector<ASTNode *> Nodes; - while (auto Node = parseBlockBody()) + while (auto Node = parse()) Nodes.push_back(Node); if (!consumeIf(tok::r_brace)) { @@ -127,61 +169,23 @@ Stmt *Parser::parseBlock() { } ASTNode *Parser::parseBlockBody() { - while (true) { - - switch (Tok.getKind()) { - // End of the code block; - case tok::r_brace: - return nullptr; - // Empty expression - case tok::semicolon: - consumeToken(); - break; - - case tok::kwVar: - return parseVarDecl(); - - case tok::kwLet: - return parseLetDecl(); - - case tok::kwBreak: - return parseBreakStmt(); - case tok::kwReturn: - return parseReturnStmt(); - - case tok::identifier: - case tok::number_literal: - case tok::l_bracket: - case tok::l_paren: - return parseExprStmt(); - - case tok::kwFor: - return parseForStmt(); - case tok::kwIf: - return parseIfStmt(); - case tok::kwWhile: - return parseWhileStmt(); - - default: - return nullptr; - } - } + return nullptr; } /// ExternStmt ::= /// 'extern' 'func' indentifier Stmt *Parser::parseExterStmt() { // Validate `exter` keyword - assert(Tok.is(tok::kwExtern) && "Invalid parse method"); + assert(Tok.is(tok::kw_extern) && "Invalid parse method"); auto EL = consumeToken(); - if (Tok.isNot(tok::kwFunc)) { + if (Tok.isNot(tok::kw_func)) { diagnose(Tok.getLoc(), diag::DiagID::expected_func_kw) .fixItBefore("func", Tok.getLoc()); return nullptr; } auto D = new(Context) ExternStmt(EL, parseFuncDecl()); - if (consumeIf(tok::semicolon)) + if (consumeIf(tok::semi)) return D; diagnose(Tok.getLoc(), diag::DiagID::expected_semicolon) @@ -193,7 +197,7 @@ Stmt *Parser::parseExterStmt() { /// 'func' identifier '(' Args ')' RetType Block Stmt *Parser::parseFuncStmt() { // Validate `func` keyword - assert(Tok.is(tok::kwFunc) && "Invalid parse method"); + assert(Tok.is(tok::kw_func) && "Invalid parse method"); auto D = parseFuncDecl(); if (Tok.is(tok::l_brace)) return new(Context) FuncStmt(D, parseBlock()); @@ -207,7 +211,7 @@ Stmt *Parser::parseFuncStmt() { /// 'for' identifier 'in' Expr ('..' | '...') Expr Block Stmt *Parser::parseForStmt() { // Validate `for` keyword. - assert(Tok.is(tok::kwFor) && "Invalid parse method"); + assert(Tok.is(tok::kw_for) && "Invalid parse method"); auto FLoc = consumeToken(); auto Ident = Tok; if (!consumeIf(tok::identifier)) { @@ -216,7 +220,7 @@ Stmt *Parser::parseForStmt() { } auto Var = new(Context) ParamDecl(Ident.getText(), Ident.getLoc()); - if (!consumeIf(tok::kwIn)) { + if (!consumeIf(tok::kw_in)) { diagnose(Tok.getLoc(), diag::DiagID::expected_in_kw) .fixItBefore("in", Tok.getLoc()); return nullptr; @@ -246,7 +250,7 @@ Stmt *Parser::parseRangeStmt() { } Stmt *Parser::parseWhileStmt() { - assert(Tok.is(tok::kwWhile) && "Invalid parse method."); + assert(Tok.is(tok::kw_while) && "Invalid parse method."); auto L = consumeToken(); auto Cond = parseExpr(); @@ -255,7 +259,7 @@ Stmt *Parser::parseWhileStmt() { } Stmt *Parser::parseIfStmt() { - assert(Tok.is(tok::kwIf) && "Invalid parse method."); + assert(Tok.is(tok::kw_if) && "Invalid parse method."); auto L = consumeToken(); auto Cond = parseExpr(); auto Then = parseBlock(); @@ -264,7 +268,7 @@ Stmt *Parser::parseIfStmt() { } Stmt *Parser::parseElseStmt() { - if (!consumeIf(tok::kwElse)) + if (!consumeIf(tok::kw_else)) return nullptr; return parseBlock(); } diff --git a/lib/Parser/ParseType.cpp b/lib/Parser/ParseType.cpp index bdbd889..b23a0d2 100644 --- a/lib/Parser/ParseType.cpp +++ b/lib/Parser/ParseType.cpp @@ -40,7 +40,7 @@ TypeRepr *Parser::parseArrayType(TypeRepr *Base) { case tok::comma: case tok::assign: case tok::r_paren: - case tok::semicolon: + case tok::semi: return Base; case tok::l_bracket: { diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp index ffec6b2..8d03d05 100644 --- a/lib/Parser/Parser.cpp +++ b/lib/Parser/Parser.cpp @@ -56,28 +56,32 @@ ModuleDecl *Parser::parseModule() { std::vector<ASTNode *> Nodes; consumeToken(); while (Tok.isNot(tok::eof) && !R.isError()) - Nodes.push_back(parseGlobal()); + Nodes.push_back(parse()); return new(Context) ModuleDecl(SF.file(), std::move(Nodes)); } -ASTNode *Parser::parseGlobal() { +ASTNode *Parser::parse() { switch (Tok.getKind()) { - case tok::kwVar: - return parseVarDecl(); - case tok::kwLet: - return parseLetDecl(); - case tok::kwExtern: - return parseExterStmt(); - case tok::kwFunc: - return parseFuncStmt(); - +#define DECL_KEYWORD(KW) \ + case tok::kw_##KW: +#include "dusk/Basic/TokenDefinitions.def" + return parseDecl(); + +#define STMT_KEYWORD(KW) \ + case tok::kw_##KW: +#include "dusk/Basic/TokenDefinitions.def" case tok::identifier: case tok::number_literal: case tok::l_paren: - return parseExprStmt(); + case tok::semi: + return parseStatement(); + case tok::eof: + case tok::r_brace: + return nullptr; + default: diagnose(consumeToken()); return nullptr; diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index a267539..6603135 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -323,10 +323,10 @@ private: if (!FnTy || !ArgsTy) return E; - if (!TC.typeCheckEquals(FnTy->getFuncType()->getArgsType(), ArgsTy)) + if (!TC.typeCheckEquals(FnTy->getFunctionType()->getArgsType(), ArgsTy)) return E; - E->setType(FnTy->getFuncType()->getRetType()); + E->setType(FnTy->getFunctionType()->getRetType()); return E; } diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 7da4dbd..5a5f571 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -41,7 +41,7 @@ private: // Extract function type auto Fn = TC.ASTScope.getFnParent()->getStmt()->getFuncStmt(); - auto FnTy = Fn->getPrototype()->getType()->getFuncType(); + auto FnTy = Fn->getPrototype()->getType()->getFunctionType(); // Check if valid void type if (!S->hasValue()) { -- GitLab