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