From 688dba66c0698945f535aaa1554b953b7e01382f Mon Sep 17 00:00:00 2001
From: Peter Matta <mattapet@fit.cvut.cz>
Date: Wed, 16 May 2018 11:38:15 +0200
Subject: [PATCH] Added new ASTWalker behavior

---
 examples/factRec.dusk         |   6 +-
 examples/factor.dusk          |   5 +-
 examples/fibonacci.dusk       |   5 +-
 examples/funcDecl.dusk        |   4 -
 examples/gcd.dusk             |   8 +-
 examples/inOut.dusk           |   3 -
 examples/interpRec.dusk       |   5 +-
 examples/isPrime.dusk         |  49 ++---
 include/dusk/AST/ASTVisitor.h | 106 ++++++++-
 include/dusk/AST/ASTWalker.h  | 110 +++++++++-
 include/dusk/AST/Decl.h       |   7 +-
 include/dusk/AST/Expr.h       |  20 +-
 include/dusk/AST/Pattern.h    |   5 +
 include/dusk/AST/Stmt.h       |  17 +-
 include/dusk/AST/TypeRepr.h   |   3 +
 lib/AST/ASTNode.cpp           |  14 ++
 lib/AST/ASTPrinter.cpp        |  80 +++----
 lib/AST/ASTWalker.cpp         | 403 +++++++++++++++++++++++++++++++---
 lib/IRGen/CMakeLists.txt      |   2 +
 lib/IRGen/GenExpr.cpp         |   2 +-
 lib/IRGen/GenFunc.cpp         |  12 +-
 lib/IRGen/IRGenModule.cpp     |  29 +--
 lib/IRGen/IRGenModule.h       |   5 +
 lib/IRGen/IRGenValue.cpp      |  57 +++++
 lib/IRGen/IRGenValue.h        | 128 +++++++++++
 lib/Sema/TypeCheckExpr.cpp    |   4 +-
 26 files changed, 906 insertions(+), 183 deletions(-)
 create mode 100644 lib/IRGen/IRGenValue.cpp
 create mode 100644 lib/IRGen/IRGenValue.h

diff --git a/examples/factRec.dusk b/examples/factRec.dusk
index 3333913..a35bac6 100644
--- a/examples/factRec.dusk
+++ b/examples/factRec.dusk
@@ -1,7 +1,3 @@
-extern func println(int: Int) -> Void;
-extern func readln() -> Int;
-
-
 func fact(n: Int) -> Int {
     if n == 0 {
         return 1;
@@ -10,7 +6,7 @@ func fact(n: Int) -> Int {
     }
 }
 
-func main_() {
+func main() {
     let n = readln();
     println(fact(n));
 }
diff --git a/examples/factor.dusk b/examples/factor.dusk
index 67dce84..d4518b7 100644
--- a/examples/factor.dusk
+++ b/examples/factor.dusk
@@ -1,6 +1,3 @@
-extern func println(int: Int) -> Void;
-extern func readln() -> Int;
-
 func factorize(n: Int, fact: Int) -> Int {
     var ret = n;
     while ret % fact == 0 {
@@ -33,7 +30,7 @@ func factorization(n: Int) {
     }
 }
 
-func main_() {
+func main() {
     let n = readln();
     factorization(n);
 }
diff --git a/examples/fibonacci.dusk b/examples/fibonacci.dusk
index 3dd6c3c..e899778 100644
--- a/examples/fibonacci.dusk
+++ b/examples/fibonacci.dusk
@@ -1,6 +1,3 @@
-extern func println(int: Int) -> Void;
-extern func readln() -> Int;
-
 func fib(n: Int) -> Int {
     if n < 2 {
         return n;
@@ -9,7 +6,7 @@ func fib(n: Int) -> Int {
     }
 }
 
-func main_() {
+func main() {
     let n = readln();
     println(fib(n));
 }
diff --git a/examples/funcDecl.dusk b/examples/funcDecl.dusk
index 908c46e..b247d79 100644
--- a/examples/funcDecl.dusk
+++ b/examples/funcDecl.dusk
@@ -1,7 +1,3 @@
-//extern func test();
-extern func println(output: Int) -> Void;
-extern func readln() -> Int;
-
 /*func main(arg1: Int) -> Int {
     return arg1;
 }*/
diff --git a/examples/gcd.dusk b/examples/gcd.dusk
index 42383f4..2d9f66a 100644
--- a/examples/gcd.dusk
+++ b/examples/gcd.dusk
@@ -1,6 +1,3 @@
-extern func println(int: Int) -> Void;
-extern func readln() -> Int;
-
 func gcdi(a: Int, b: Int) -> Int {
     while b != 0 {
         let tmp = b;
@@ -11,8 +8,7 @@ func gcdi(a: Int, b: Int) -> Int {
 }
 
 func gcdr(a: Int, b: Int) -> Int {
-    let tmp = a % b;
-    if tmp == 0 {
+    if a % b == 0 {
         return b;
     } else {
         return gcdr(b, tmp);
@@ -30,7 +26,7 @@ func gcdrGuessing(a: Int, b: Int) -> Int {
     return gcdrGuessingInner(a, b, b);
 }
 
-func main_() {
+func main() {
     println(gcdi(27*2, 27*3));
     println(gcdr(27*2, 27*3));
     println(gcdrGuessing(27*2, 27*3));
diff --git a/examples/inOut.dusk b/examples/inOut.dusk
index 9afe30f..de315f1 100644
--- a/examples/inOut.dusk
+++ b/examples/inOut.dusk
@@ -1,6 +1,3 @@
-extern func println(int: Int) -> Void;
-extern func readln() -> Int;
-
 var n: Int;
 
 func main_() {
diff --git a/examples/interpRec.dusk b/examples/interpRec.dusk
index 140066d..1789cc4 100644
--- a/examples/interpRec.dusk
+++ b/examples/interpRec.dusk
@@ -1,6 +1,3 @@
-extern func println(int: Int) -> Void;
-extern func readln() -> Int;
-
 func isOdd(n: Int) -> Int {
     if n > 0 {
         return isEven(n - 1);
@@ -15,7 +12,7 @@ func isEven(n: Int) -> Int {
     return 1;
 }
 
-func main_() {
+func main() {
     let n = readln();
     println(isEven(n));
     println(isOdd(n));
diff --git a/examples/isPrime.dusk b/examples/isPrime.dusk
index 1d876ae..0d7363d 100644
--- a/examples/isPrime.dusk
+++ b/examples/isPrime.dusk
@@ -1,6 +1,3 @@
-extern func println(int: Int) -> Void;
-extern func readln() -> Int;
-
 func isPrime(n: Int) -> Int {
     if n < 2 {
         return 0;
@@ -33,29 +30,29 @@ func isPrime(n: Int) -> Int {
     }
 }
 
-func main_() {
-    // println(0);
-    // println(isPrime(0));
-    // println(1);
-    // println(isPrime(1));
-    // println(2);
-    // println(isPrime(2));
-    // println(3);
-    // println(isPrime(3));
-    // println(4);
-    // println(isPrime(4));
-    // println(5);
-    // println(isPrime(5));
-    // println(6);
-    // println(isPrime(6));
-    // println(7);
-    // println(isPrime(7));
-    // println(8);
-    // println(isPrime(8));
-    // println(9);
-    // println(isPrime(9));
-    // println(10);
-    // println(isPrime(10));
+func main() {
+    println(0);
+    println(isPrime(0));
+    println(1);
+    println(isPrime(1));
+    println(2);
+    println(isPrime(2));
+    println(3);
+    println(isPrime(3));
+    println(4);
+    println(isPrime(4));
+    println(5);
+    println(isPrime(5));
+    println(6);
+    println(isPrime(6));
+    println(7);
+    println(isPrime(7));
+    println(8);
+    println(isPrime(8));
+    println(9);
+    println(isPrime(9));
+    println(10);
+    println(isPrime(10));
     println(11);
     println(isPrime(11));
     println(12);
diff --git a/include/dusk/AST/ASTVisitor.h b/include/dusk/AST/ASTVisitor.h
index a83d8e6..7d28973 100644
--- a/include/dusk/AST/ASTVisitor.h
+++ b/include/dusk/AST/ASTVisitor.h
@@ -39,19 +39,19 @@ public:
   /// Returns a reference to the derived class.
   Derived &getDerived() { return *static_cast<Derived *>(this); }
 
-  bool visit(ASTNode *N) {
+  bool visit_(ASTNode *N) {
     if (auto *D = dynamic_cast<Decl *>(N))
-      return visit(D);
+      return visit_(D);
     if (auto *E = dynamic_cast<Expr *>(N))
-      return visit(E);
+      return visit_(E);
     if (auto *S = dynamic_cast<Stmt *>(N))
-      return visit(S);
+      return visit_(S);
 
     llvm_unreachable("Unexpected node");
   }
 
   /// Visit a concrete declaration node.
-  bool visit(Decl *D) {
+  bool visit_(Decl *D) {
     switch (D->getKind()) {
     case DeclKind::Let:
       return getDerived().visit(static_cast<LetDecl *>(D));
@@ -67,7 +67,7 @@ public:
   }
 
   /// Visit a conrete expression node.
-  bool visit(Expr *E) {
+  bool visit_(Expr *E) {
     switch (E->getKind()) {
     case ExprKind::NumberLiteral:
       return getDerived().visit(static_cast<NumberLiteralExpr *>(E));
@@ -91,7 +91,7 @@ public:
   }
 
   /// Visit a concrete statement node.
-  bool visit(Stmt *S) {
+  bool visit_(Stmt *S) {
     switch (S->getKind()) {
     case StmtKind::Break:
       return getDerived().visit(static_cast<BreakStmt *>(S));
@@ -117,7 +117,7 @@ public:
   }
 
   /// Visit a concrete pattern node.
-  bool visit(Pattern *P) {
+  bool visit_(Pattern *P) {
     switch (P->getKind()) {
     case PatternKind::Expr:
       return getDerived().visit(static_cast<ExprPattern *>(P));
@@ -127,7 +127,7 @@ public:
   }
   
   /// Visits concrete TypeRepr
-  bool visit(TypeRepr *T) {
+  bool visit_(TypeRepr *T) {
     switch (T->getKind()) {
     case TypeReprKind::Ident:
       return getDerived().visit(static_cast<IdentTypeRepr *>(T));
@@ -135,6 +135,94 @@ public:
       return getDerived().visit(static_cast<ArrayTypeRepr *>(T));
     }
   }
+  
+  /// Visit a concrete declaration node.
+  bool 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));
+    }
+  }
+  
+  /// Visit a concrete expression node.
+  Expr *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));
+    }
+  }
+  
+  /// Visit a concrete statement node.
+  bool 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));
+    }
+  }
+  
+  /// Visit a concrete pattern node.
+  bool 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));
+    }
+  }
+  
+  /// Visits concrete TypeRepr
+  bool 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));
+    }
+  }
 };
 
 } // namespace dusk
diff --git a/include/dusk/AST/ASTWalker.h b/include/dusk/AST/ASTWalker.h
index a87ffe5..1250893 100644
--- a/include/dusk/AST/ASTWalker.h
+++ b/include/dusk/AST/ASTWalker.h
@@ -11,12 +11,14 @@
 #define DUSK_AST_WALKER_H
 
 #include "dusk/Basic/LLVM.h"
+#include <utility>
 
 namespace dusk {
 class Decl;
 class Expr;
 class Stmt;
 class Pattern;
+class TypeRepr;
 
 /// \brief Base class for all classes, that whish to traverse the AST.
 ///
@@ -42,7 +44,7 @@ public:
   /// \return \c true if the node should terminate traversal,
   ///  \c false otherwise.
   virtual bool postWalk(Decl *D) { return true; }
-
+  
   /// This method is called before a node is being walked.
   ///
   /// \param E An expression node that will be walked.
@@ -87,6 +89,112 @@ public:
   /// \return \c true if the node should terminate traversal,
   ///  \c false otherwise.
   virtual bool postWalk(Pattern *P) { return true; }
+
+  
+  
+  /// This method is called before a declaration is being walked.
+  ///
+  /// \param D A declaration node that will be walked.
+  ///
+  /// \return \c true if the node should be walked, \c false otherwise.
+  ///
+  /// Default implementation returns \c true.
+  virtual bool preWalkDecl(Decl *D) { return true; }
+  
+  /// This method is called after declaration children were walked.
+  ///
+  /// \param D A declaration node that was walked.
+  ///
+  /// \return \c true if the node should continue traversal,
+  ///  \c false otherwise.
+  ///
+  /// Default implementation returns \c true.
+  virtual bool postWalkDecl(Decl *D) { return true; }
+  
+  /// This method is called before an expression is being walked.
+  ///
+  /// \param E An expression node that will be walked.
+  ///
+  /// \return A pair consisting of a \c bool indicating, whether this node
+  ///  should be skipped or not and an expression that should replace this
+  ///  expression in the tree. If \c null is returned, the traversal is
+  ///  terminated.
+  ///
+  /// Default implementation returns \c {true, E}.
+  virtual std::pair<bool, Expr *> preWalkExpr(Expr *E) { return {true, E}; }
+  
+  /// This method is called after expression children were walked.
+  ///
+  /// \param E An expression node that was walked.
+  ///
+  /// \return \c null, in which case the walk is terminater, otherwise the
+  ///  returned expression replaces walked expression in the tree.
+  ///
+  /// Default implementation returns its argument.
+  virtual Expr *postWalkExpr(Expr *E) { return E; }
+  
+  
+  /// This method is called before a statement is being walked.
+  ///
+  /// \param S A statement node that will be walked.
+  ///
+  /// \return \c true if the node should be walked, \c false otherwise.
+  ///
+  /// Default implementation returns \c true.
+  virtual bool preWalkStmt(Stmt *S) { return true; }
+
+  /// This method is called after statement children were walked.
+  ///
+  /// \param S A statement node that was walked.
+  ///
+  /// \return \c true if the node should continue traversal,
+  ///  \c false otherwise.
+  ///
+  /// Default implementation returns \c true.
+  virtual bool postWalkStmt(Stmt *S) { return true; }
+  
+  
+  /// This method is called before a pattern is being walked.
+  ///
+  /// \param P A pattern node that will be walked.
+  ///
+  /// \return \c true if the node should be walked, \c false otherwise.
+  ///
+  /// Default implementation returns \c true.
+  virtual bool preWalkPattern(Pattern *P) { return true; }
+
+  /// This method is called after pattern children were walked.
+  ///
+  /// \param P A pattern node that was walked.
+  ///
+  /// \return \c true if the node should continue traversal,
+  ///  \c false otherwise.
+  ///
+  /// Default implementation returns \c true.
+  virtual bool postWalkPattern(Pattern *P) { return true; }
+
+  /// This method is called before a type represenation is being walked.
+  ///
+  /// \param Tr A type representation node that will be walked.
+  ///
+  /// \return \c true if the node should be walked, \c false otherwise.
+  ///
+  /// Default implementation returns \c true.
+  virtual bool preWalkTypeRepr(TypeRepr *Tr) { return true; }
+
+  /// This method is called after type representation children were walked.
+  ///
+  /// \param Tr A type representation node that was walked.
+  ///
+  /// \return \c true if the node should continue traversal,
+  ///  \c false otherwise.
+  ///
+  /// Default implementation returns \c true.
+  virtual bool postWalkTypeRepr(TypeRepr *Tr) { return true; }
+  
+private:
+  ASTWalker(const ASTWalker &) = delete;
+  ASTWalker &operator=(const ASTWalker &) = delete;
 };
 
 } // namespace dusk
diff --git a/include/dusk/AST/Decl.h b/include/dusk/AST/Decl.h
index 8fb3506..16f40fa 100644
--- a/include/dusk/AST/Decl.h
+++ b/include/dusk/AST/Decl.h
@@ -86,7 +86,9 @@ public:
   /// Returns type representation.
   TypeRepr *getTypeRepr() const { return TyRepr; }
 
-  virtual SMRange getSourceRange() const override;
+  SMRange getSourceRange() const override;
+  
+  bool walk(ASTWalker &Walker) override;
 };
 
 /// Declaration of value-holdable node
@@ -101,9 +103,10 @@ public:
   ValDecl(DeclKind K, StringRef N, SMLoc NL, Expr *V);
   ValDecl(DeclKind K, StringRef N, SMLoc NL, Expr *V, TypeRepr *TR);
 
-  bool hasValue() const { return Value != nullptr; }
   SMLoc getValLoc() const { return ValLoc; }
+  bool hasValue() const { return Value != nullptr; }
   Expr *getValue() const { return Value; }
+  void setValue(Expr *V) { Value = V; }
 };
 
 /// Declaration of a variable
diff --git a/include/dusk/AST/Expr.h b/include/dusk/AST/Expr.h
index 172593d..7fea43f 100644
--- a/include/dusk/AST/Expr.h
+++ b/include/dusk/AST/Expr.h
@@ -65,6 +65,8 @@ public:
   
   /// Sets declaration type
   void setType(Type *T) { Ty = T; }
+  
+  bool walk(ASTWalker &Walker) override;
 };
 
 /// Number literal expression encalsulation.
@@ -76,7 +78,7 @@ public:
   NumberLiteralExpr(int64_t V, SMRange ValL);
 
   SMRange getValLoc() const { return ValueLoc; }
-  int getValue() const { return Value; }
+  int64_t getValue() const { return Value; }
 
   SMRange getSourceRange() const override;
 };
@@ -127,6 +129,7 @@ public:
   ParenExpr(Expr *E, SMLoc L, SMLoc R);
 
   Expr *getExpr() const { return Expression; }
+  void setExpr(Expr *E) { Expression = E; }
 
   SMRange getSourceRange() const override;
 };
@@ -142,6 +145,8 @@ public:
 
   Expr *getLHS() const { return LHS; }
   Expr *getRHS() const { return RHS; }
+  void setLHS(Expr *L) { LHS = L; }
+  void setRHS(Expr *R) { RHS = R; }
   Token getOp() const { return Op; }
 
   SMRange getSourceRange() const override;
@@ -152,10 +157,12 @@ class AssignExpr : public Expr {
   Expr *Source;
 
 public:
-  AssignExpr(Expr *L, Expr *R);
+  AssignExpr(Expr *D, Expr *S);
 
   Expr *getDest() const { return Dest; }
   Expr *getSource() const { return Source; }
+  void setDest(Expr *D) { Dest = D; }
+  void setSource(Expr *S) { Source = S; }
 
   SMRange getSourceRange() const override;
 };
@@ -168,6 +175,7 @@ public:
   PrefixExpr(Expr *D, Token O);
 
   Expr *getDest() const { return Dest; }
+  void setDest(Expr *D) { Dest = D; }
   Token getOp() const { return Op; }
 
   SMRange getSourceRange() const override;
@@ -183,9 +191,10 @@ class CallExpr : public Expr {
 public:
   CallExpr(Expr *C, Pattern *A);
 
-  Expr *getCalle() const { return Callee; }
+  Expr *getCallee() const { return Callee; }
   Pattern *getArgs() { return Args; }
-
+  void setCallee(Expr *C) { Callee = C; }
+  
   SMRange getSourceRange() const override;
 };
 
@@ -201,7 +210,8 @@ public:
 
   Expr *getBase() { return Base; }
   Stmt *getSubscript() { return Subscript; }
-
+  void setBase(Expr *B) { Base = B; }
+  
   SMRange getSourceRange() const override;
 };
 
diff --git a/include/dusk/AST/Pattern.h b/include/dusk/AST/Pattern.h
index 1ee108a..b61fb07 100644
--- a/include/dusk/AST/Pattern.h
+++ b/include/dusk/AST/Pattern.h
@@ -22,6 +22,7 @@ class Expr;
 class Stmt;
 class Type;
 class ParamDecl;
+class ASTWalker;
 
 /// Pattern description.
 enum struct PatternKind { Expr, Variable };
@@ -45,6 +46,8 @@ public:
   
   SMLoc getLocStart() { return getSourceRange().Start; }
   SMLoc getLocEnd() { return getSourceRange().End; }
+  
+  bool walk(ASTWalker &Walker);
 };
 
 /// Expression pattern
@@ -63,6 +66,7 @@ public:
   ExprPattern(SmallVector<Expr *, 128> &&V, SMLoc L, SMLoc R);
 
   ArrayRef<Expr *> getValues() const { return Values; }
+  SmallVector<Expr *, 128> &getValues() { return Values; }
   SMLoc getLPar() const { return LPar; }
   SMLoc getRPar() const { return RPar; }
 
@@ -88,6 +92,7 @@ public:
   VarPattern(SmallVector<Decl *, 128> &&V, SMLoc L, SMLoc R);
 
   ArrayRef<Decl *> getVars() const { return Vars; }
+  SmallVector<Decl *, 128> &getVars() { return Vars; }
   SMLoc getLPar() const { return LPar; }
   SMLoc getRPar() const { return RPar; }
 
diff --git a/include/dusk/AST/Stmt.h b/include/dusk/AST/Stmt.h
index ade30dc..9bd3d76 100644
--- a/include/dusk/AST/Stmt.h
+++ b/include/dusk/AST/Stmt.h
@@ -48,9 +48,11 @@ public:
   virtual ~Stmt() = default;
 
   StmtKind getKind() const { return Kind; }
+  
+  bool walk(ASTWalker &Walker) override;
 };
 
-/// Represents a `break` statement in a loop.
+/// Represents a \c break statement in a loop.
 class BreakStmt : public Stmt {
   /// Range of \c break keyword
   SMRange BreakLoc;
@@ -58,10 +60,10 @@ class BreakStmt : public Stmt {
 public:
   BreakStmt(SMRange BR);
 
-  virtual SMRange getSourceRange() const override;
+  SMRange getSourceRange() const override;
 };
 
-/// Represents a `return` statement.
+/// Represents a \c return statement.
 class ReturnStmt : public Stmt {
   /// Location of \c return keyword
   SMLoc RetLoc;
@@ -73,6 +75,7 @@ public:
   ReturnStmt(SMLoc RL, Expr *V);
 
   Expr *getValue() const { return Value; }
+  void setValue(Expr *V) { Value = V; }
   bool hasValue() const { return Value != nullptr; }
   virtual SMRange getSourceRange() const override;
 };
@@ -92,6 +95,7 @@ public:
   SubscriptStmt(Expr *V, SMLoc L, SMLoc R);
 
   Expr *getValue() const { return Value; }
+  void setValue(Expr *V) { Value = V; }
   SMLoc getLBracket() const { return LBracket; }
   SMLoc getRBracket() const { return RBracket; }
 
@@ -114,6 +118,8 @@ public:
 
   Expr *getStart() const { return Start; }
   Expr *getEnd() const { return End; }
+  void setStart(Expr *S) { Start = S; }
+  void setEnd(Expr *E) { End = E; }
   Token getOp() const { return Op; }
 
   /// Return \c true, if range is inclusive, \c false otherwise.
@@ -136,7 +142,8 @@ class BlockStmt : public Stmt {
 public:
   BlockStmt(SMLoc S, SMLoc E, std::vector<ASTNode *> &&N);
 
-  ArrayRef<ASTNode *> getNodes() { return Nodes; }
+  ArrayRef<ASTNode *> getNodes() const { return Nodes; }
+  std::vector<ASTNode *> &getNodes() { return Nodes; }
   virtual SMRange getSourceRange() const override;
 };
 
@@ -206,6 +213,7 @@ public:
   WhileStmt(SMLoc WL, Expr *C, Stmt *B);
 
   Expr *getCond() const { return Cond; }
+  void setCond(Expr *C) { Cond = C; }
   Stmt *getBody() const { return Body; }
 
   virtual SMRange getSourceRange() const override;
@@ -226,6 +234,7 @@ public:
   IfStmt(SMLoc IL, Expr *C, Stmt *T, Stmt *E = nullptr);
 
   Expr *getCond() const { return Cond; }
+  void setCond(Expr *C) { Cond = C; }
   Stmt *getThen() const { return Then; }
   Stmt *getElse() const { return Else; }
   bool hasElseBlock() const { return Else != nullptr; }
diff --git a/include/dusk/AST/TypeRepr.h b/include/dusk/AST/TypeRepr.h
index e0f4fbb..598c8ba 100644
--- a/include/dusk/AST/TypeRepr.h
+++ b/include/dusk/AST/TypeRepr.h
@@ -18,6 +18,7 @@
 namespace dusk {
 class Expr;
 class Stmt;
+class ASTWalker;
 
 enum struct TypeReprKind {
   Ident,
@@ -34,6 +35,8 @@ public:
   SMLoc getLocStart() const { return getSourceRange().Start; }
   SMLoc getLocEnd() const { return getSourceRange().End; }
   virtual SMRange getSourceRange() const = 0;
+  
+  bool walk(ASTWalker &Walker);
 };
 
 /// Simple single identifier type e.g. ': Int'
diff --git a/lib/AST/ASTNode.cpp b/lib/AST/ASTNode.cpp
index 9ef0649..947f0b8 100644
--- a/lib/AST/ASTNode.cpp
+++ b/lib/AST/ASTNode.cpp
@@ -14,3 +14,17 @@
 #include "dusk/AST/Stmt.h"
 
 using namespace dusk;
+
+bool ASTNode::walk(ASTWalker &Walker) {
+  if (auto D = dynamic_cast<Decl *>(this))
+    return D->walk(Walker);
+  
+  else if (auto E = dynamic_cast<Expr *>(this))
+    return E->walk(Walker);
+  
+  else if (auto S = dynamic_cast<Stmt *>(this))
+    return S->walk(Walker);
+  
+  else
+    llvm_unreachable("Unexpected AST node found.");
+}
diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp
index 1bd709a..41d635c 100644
--- a/lib/AST/ASTPrinter.cpp
+++ b/lib/AST/ASTPrinter.cpp
@@ -45,7 +45,7 @@ public:
       if (E)
         Printer.printNewline();
       
-      super::visit(N);
+      super::visit_(N);
       
       if (E)
         Printer.printText(";");
@@ -60,12 +60,12 @@ public:
     
     if (D->hasTypeRepr()) {
       Printer << ": ";
-      super::visit(D->getTypeRepr());
+      super::visit_(D->getTypeRepr());
     }
     
     if (D->hasValue()) {
       Printer << " " << tok::assign << " ";
-      super::visit(D->getValue());
+      super::visit_(D->getValue());
     }
     Printer.printDeclPost(D);
     return true;
@@ -77,12 +77,12 @@ public:
     
     if (D->hasTypeRepr()) {
       Printer << ": ";
-      super::visit(D->getTypeRepr());
+      super::visit_(D->getTypeRepr());
     }
     
     if (D->hasValue()) {
       Printer << " " << tok::assign << " ";
-      super::visit(D->getValue());
+      super::visit_(D->getValue());
     }
     Printer.printDeclPost(D);
     return true;
@@ -91,12 +91,12 @@ public:
   bool visit(FuncDecl *D) {
     Printer.printDeclPre(D);
     Printer << D->getName() << "(";
-    super::visit(D->getArgs());
+    super::visit_(D->getArgs());
     Printer << ")";
     
     if (D->hasTypeRepr()) {
       Printer << " -> ";
-      super::visit(D->getTypeRepr());
+      super::visit_(D->getTypeRepr());
     }
     
     Printer.printDeclPost(D);
@@ -106,7 +106,7 @@ public:
   bool visit(ParamDecl *D) {
     Printer.printDeclPost(D);
     Printer << D->getName() << ": ";
-    super::visit(D->getTypeRepr());
+    super::visit_(D->getTypeRepr());
     Printer.printDeclPost(D);
     return true;
   }
@@ -128,49 +128,49 @@ public:
   
   bool visit(ArrayLiteralExpr *E) {
     Printer << "[";
-    super::visit(E->getValues());
+    super::visit_(E->getValues());
     Printer << "]";
     return true;
   }
 
   bool visit(ParenExpr *E) {
     Printer << "(";
-    super::visit(E->getExpr());
+    super::visit_(E->getExpr());
     Printer << ")";
     return true;
   }
 
   bool visit(AssignExpr *E) {
-    super::visit(E->getDest());
+    super::visit_(E->getDest());
     Printer << " " << tok::assign << " ";
-    super::visit(E->getSource());
+    super::visit_(E->getSource());
     return true;
   }
 
   bool visit(CallExpr *E) {
-    super::visit(E->getCalle());
+    super::visit_(E->getCallee());
     Printer << "(";
-    super::visit(E->getArgs());
+    super::visit_(E->getArgs());
     Printer << ")";
     return true;
   }
 
   bool visit(InfixExpr *E) {
-    super::visit(E->getLHS());
+    super::visit_(E->getLHS());
     Printer << " " << E->getOp().getKind() << " ";
-    super::visit(E->getRHS());
+    super::visit_(E->getRHS());
     return true;
   }
 
   bool visit(PrefixExpr *E) {
     Printer << E->getOp().getKind();
-    super::visit(E->getDest());
+    super::visit_(E->getDest());
     return true;
   }
 
   bool visit(SubscriptExpr *E) {
-    super::visit(E->getBase());
-    super::visit(E->getSubscript());
+    super::visit_(E->getBase());
+    super::visit_(E->getSubscript());
     return true;
   }
 
@@ -187,7 +187,7 @@ public:
     Printer.printStmtPre(S);
 
     Printer << tok::kwReturn << " ";
-    super::visit(S->getValue());
+    super::visit_(S->getValue());
 
     Printer.printStmtPost(S);
     return true;
@@ -195,18 +195,18 @@ public:
 
   bool visit(SubscriptStmt *S) {
     Printer.printStmtPre(S);
-    super::visit(S->getValue());
+    super::visit_(S->getValue());
     Printer.printStmtPost(S);
     return true;
   }
 
   bool visit(RangeStmt *S) {
     Printer.printStmtPre(S);
-    super::visit(S->getStart());
+    super::visit_(S->getStart());
 
     Printer << S->getOp().getKind();
 
-    super::visit(S->getEnd());
+    super::visit_(S->getEnd());
     Printer.printStmtPost(S);
     return true;
   }
@@ -220,7 +220,7 @@ public:
       else
         Printer.printNewline();
 
-      super::visit(N);
+      super::visit_(N);
       if (auto E = dynamic_cast<Expr *>(N))
         Printer.printText(";");
     }
@@ -231,16 +231,16 @@ public:
   bool visit(ExternStmt *S) {
     Printer.printStmtPre(S);
     Printer << tok::kwExtern << " ";
-    super::visit(S->getPrototype());
+    super::visit_(S->getPrototype());
     Printer.printStmtPost(S);
     return true;
   }
   
   bool visit(FuncStmt *S) {
     Printer.printStmtPre(S);
-    super::visit(S->getPrototype());
+    super::visit_(S->getPrototype());
     Printer << " ";
-    super::visit(S->getBody());
+    super::visit_(S->getBody());
     Printer.printStmtPost(S);
     return true;
   }
@@ -249,11 +249,11 @@ public:
     Printer.printStmtPre(S);
 
     Printer << tok::kwFor << " ";
-    super::visit(S->getIter());
+    super::visit_(S->getIter());
     Printer << " " << tok::kwIn << " ";
-    super::visit(S->getRange());
+    super::visit_(S->getRange());
     Printer << " ";
-    super::visit(S->getBody());
+    super::visit_(S->getBody());
 
     Printer.printStmtPost(S);
     return true;
@@ -263,13 +263,13 @@ public:
     Printer.printStmtPre(S);
     Printer << tok::kwIf << " ";
 
-    super::visit(S->getCond());
+    super::visit_(S->getCond());
     Printer << " ";
-    super::visit(S->getThen());
+    super::visit_(S->getThen());
 
     if (S->hasElseBlock()) {
       Printer << " " << tok::kwElse << " ";
-      super::visit(S->getElse());
+      super::visit_(S->getElse());
     }
 
     Printer.printStmtPost(S);
@@ -280,9 +280,9 @@ public:
     Printer.printStmtPre(S);
     Printer << tok::kwWhile << " ";
 
-    super::visit(S->getCond());
+    super::visit_(S->getCond());
     Printer << " ";
-    super::visit(S->getBody());
+    super::visit_(S->getBody());
 
     Printer.printStmtPost(S);
     return true;
@@ -294,7 +294,7 @@ public:
     bool isFirst = true;
     for (auto V : P->getValues()) {
       Printer.printSeparator(isFirst, ", ");
-      super::visit(V);
+      super::visit_(V);
     }
     return true;
   }
@@ -303,7 +303,7 @@ public:
     bool isFirst = true;
     for (auto V : P->getVars()) {
       Printer.printSeparator(isFirst, ", ");
-      super::visit(V);
+      super::visit_(V);
     }
     return true;
   }
@@ -316,8 +316,8 @@ public:
   }
   
   bool visit(ArrayTypeRepr *T) {
-    super::visit(T->getBaseTyRepr());
-    super::visit(T->getSize());
+    super::visit_(T->getBaseTyRepr());
+    super::visit_(T->getSize());
     return true;
   }
 };
@@ -542,6 +542,6 @@ void StreamPrinter::printText(StringRef Text) { OS << Text; }
 void Formatter::format() {
   PrettyPrinter pp(OS);
   PrintAST p(pp);
-  p.ASTVisitor::visit(Ctx.getRootModule());
+  p.ASTVisitor::visit_(Ctx.getRootModule());
 }
 
diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp
index ab7c9e6..d4d747d 100644
--- a/lib/AST/ASTWalker.cpp
+++ b/lib/AST/ASTWalker.cpp
@@ -40,11 +40,323 @@ class Traversal : public ASTVisitor<Traversal> {
 
   /// Convenience type alias.
   typedef ASTVisitor super;
-
+  
+  friend class ASTVisitor<Traversal>;
+  
+  // MARK: - Declarations
+  
+  bool visitLetDecl(LetDecl *D) {
+    if (D->hasTypeRepr())
+      if (!traverse(D->getTypeRepr()))
+        return false;
+    
+    if (D->hasValue()) {
+      auto E = traverse(D->getValue());
+      if (!E)
+        return false;
+      D->setValue(E);
+    }
+    return true;
+  }
+  
+  bool visitVarDecl(VarDecl *D) {
+    if (D->hasTypeRepr())
+      if (!traverse(D->getTypeRepr()))
+        return false;
+    
+    if (D->hasValue()) {
+      auto E = traverse(D->getValue());
+      if (!E)
+        return false;
+      D->setValue(E);
+    }
+    return true;
+  }
+  
+  bool visitParamDecl(ParamDecl *D) {
+    return !D->hasTypeRepr() || traverse(D->getTypeRepr());
+  }
+  
+  bool visitFuncDecl(FuncDecl *D) {
+    if (!traverse(D->getArgs()))
+      return false;
+    return !D->hasTypeRepr() || traverse(D->getTypeRepr());
+  }
+  
+  bool visitModuleDecl(ModuleDecl *D) {
+    for (auto &N : D->getContents()) {
+      if (auto D = dynamic_cast<Decl *>(N))
+        if (!traverse(D))
+          return false;
+      
+      if (auto E = dynamic_cast<Expr *>(N))
+        if ((N = traverse(E)) == nullptr)
+          return false;
+      
+      if (auto S = dynamic_cast<Stmt *>(N))
+        if (!traverse(S))
+          return false;
+    }
+    return true;
+  }
+  
+  // MARK: - Expressions
+  
+  Expr *visitNumberLiteralExpr(NumberLiteralExpr *E) {
+    return E;
+  }
+  
+  Expr *visitArrayLiteralExpr(ArrayLiteralExpr *E) {
+    return E;
+  }
+  
+  Expr *visitIdentifierExpr(IdentifierExpr *E) {
+    return E;
+  }
+  
+  Expr *visitParenExpr(ParenExpr *E) {
+    if (auto Ex = traverse(E->getExpr()))
+      E->setExpr(Ex);
+    else
+      return nullptr;
+    return E;
+  }
+  
+  Expr *visitInfixExpr(InfixExpr *E) {
+    auto Ex = traverse(E->getLHS());
+    if (!Ex)
+      return nullptr;
+    E->setLHS(Ex);
+    Ex = traverse(E->getRHS());
+    if (!Ex)
+      return nullptr;
+    E->setRHS(Ex);
+    return E;
+  }
+  
+  Expr *visitAssignExpr(AssignExpr *E) {
+    auto Ex = traverse(E->getDest());
+    if (!Ex)
+      return nullptr;
+    E->setDest(Ex);
+    Ex = traverse(E->getSource());
+    if (!Ex)
+      return nullptr;
+    E->setSource(Ex);
+    return E;
+  }
+  
+  Expr *visitPrefixExpr(PrefixExpr *E) {
+    if (auto Ex = traverse(E->getDest()))
+      E->setDest(Ex);
+    else
+      return nullptr;
+    return E;
+  }
+  
+  Expr *visitCallExpr(CallExpr *E) {
+    if (auto Ex = traverse(E->getCallee()))
+      E->setCallee(Ex);
+    else
+      return nullptr;
+    
+    if (!traverse(E->getArgs()))
+      return nullptr;
+    return E;
+  }
+  
+  Expr *visitSubscriptExpr(SubscriptExpr *E) {
+    if (auto Ex = traverse(E->getBase()))
+      E->setBase(Ex);
+    else
+      return nullptr;
+    
+    if (!traverse(E->getSubscript()))
+      return nullptr;
+    return E;
+  }
+  
+  // MAKR: - Statements
+  
+  bool visitBreakStmt(BreakStmt *S) {
+    return true;
+  }
+  
+  bool visitReturnStmt(ReturnStmt *S) {
+    if (S->hasValue()) {
+      if (auto Val = traverse(S->getValue()))
+        S->setValue(Val);
+      else
+        return false;
+    }
+    return true;
+  }
+  
+  bool visitSubscriptStmt(SubscriptStmt *S) {
+    if (auto Val = traverse(S->getValue()))
+      S->setValue(Val);
+    else
+      return false;
+    return true;
+  }
+  
+  bool visitRangeStmt(RangeStmt *S) {
+    auto Val = traverse(S->getStart());
+    if (!Val)
+      return false;
+    S->setStart(Val);
+    
+    Val = traverse(S->getEnd());
+    if (!Val)
+      return false;
+    S->setEnd(Val);
+    return true;
+  }
+  
+  bool visitBlockStmt(BlockStmt *S) {
+    for (auto &N : S->getNodes()) {
+      if (auto D = dynamic_cast<Decl *>(N)) {
+        if (!traverse(D))
+          return false;
+      
+      } else if (auto E = dynamic_cast<Expr *>(N)) {
+        if ((N = traverse(E)) == nullptr)
+          return false;
+      
+      } else if (auto S = dynamic_cast<Stmt *>(N)) {
+        if (!traverse(S))
+          return false;
+        
+      } else {
+        llvm_unreachable("Unexpected AST node.");
+      }
+    }
+    return true;
+  }
+  
+  bool visitExternStmt(ExternStmt *S) {
+    return traverse(S->getPrototype());
+  }
+  
+  bool visitFuncStmt(FuncStmt *S) {
+    if (!traverse(S->getPrototype()))
+      return false;
+    return traverse(S->getBody());
+  }
+  
+  bool visitForStmt(ForStmt *S) {
+    if (!traverse(S->getIter()))
+      return false;
+    if (!traverse(S->getRange()))
+      return false;
+    return traverse(S->getBody());
+  }
+  
+  bool visitWhileStmt(WhileStmt *S) {
+    if (auto C = traverse(S->getCond()))
+      S->setCond(C);
+    else
+      return false;
+    return traverse(S->getBody());
+  }
+  
+  bool visitIfStmt(IfStmt *S) {
+    if (auto C = traverse(S->getCond()))
+      S->setCond(C);
+    else
+      return false;
+    if (!traverse(S->getThen()))
+      return false;
+    return !S->hasElseBlock() || traverse(S->getElse());
+  }
+  
+  // MARK: - Patterns
+  
+  bool visitExprPattern(ExprPattern *P) {
+    for (auto &E : P->getValues()) {
+      if (auto Val = traverse(E))
+        E = Val;
+      else
+        return false;
+    }
+    return true;
+  }
+  
+  bool visitVarPattern(VarPattern *P) {
+    for (auto Var : P->getVars())
+      if (!traverse(Var))
+        return false;
+    return false;
+  }
+  
+  // MARK: - Type representations
+  
+  bool visitIdentTypeRepr(IdentTypeRepr *TR) {
+    return true;
+  }
+  
+  bool visitArrayTypeRepr(ArrayTypeRepr *TR) {
+    if (!traverse(TR->getBaseTyRepr()))
+      return false;
+    return traverse(TR->getSize());
+  }
+  
 public:
   /// Constructs a basic traversal object.
   Traversal(ASTWalker &W) : Walker(W) {}
-
+  
+  bool traverse(Decl *D) {
+    // Skip current subtree
+    if (!Walker.preWalkDecl(D))
+      return true;
+    if (!super::visit(D))
+      return false;
+    
+    return Walker.postWalkDecl(D);
+  }
+  
+  Expr *traverse(Expr *E) {
+    auto Pre = Walker.preWalkExpr(E);
+    // Skip current subtree
+    if (!Pre.first || !Pre.second)
+      return Pre.second;
+    
+    E = super::visit(E);
+    
+    if (E)
+      E = Walker.postWalkExpr(E);
+    return E;
+  }
+  
+  bool traverse(Stmt *S) {
+    // Skip current subtree
+    if (!Walker.preWalkStmt(S))
+      return true;
+    if (!super::visit(S))
+      return false;
+    
+    return Walker.postWalkStmt(S);
+  }
+  
+  bool traverse(Pattern *P) {
+    // Skip current subtree
+    if (!Walker.preWalkPattern(P))
+      return true;
+    if (!super::visit(P))
+      return false;
+    return Walker.postWalkPattern(P);
+  }
+  
+  bool traverse(TypeRepr *TR) {
+    // Skip current subtree
+    if (!Walker.preWalkTypeRepr(TR))
+      return true;
+    if (!super::visit(TR))
+      return false;
+    
+    return Walker.postWalkTypeRepr(TR);
+  }
+  
   // MARK: - Declaration nodes
 
   bool visit(LetDecl *D) {
@@ -52,7 +364,7 @@ public:
     if (!Walker.preWalk(D))
       return true;
 
-    if (!super::visit(D->getValue()))
+    if (!super::visit_(D->getValue()))
       return false;
     return Walker.postWalk(D);
   }
@@ -62,7 +374,7 @@ public:
     if (!Walker.preWalk(D))
       return true;
 
-    if (!super::visit(D->getArgs()))
+    if (!super::visit_(D->getArgs()))
       return false;
     return Walker.postWalk(D);
   }
@@ -72,7 +384,7 @@ public:
       return true;
 
     for (auto C : D->getContents())
-      if (!super::visit(C))
+      if (!super::visit_(C))
         return false;
     return Walker.postWalk(D);
   }
@@ -90,7 +402,7 @@ public:
     if (!Walker.preWalk(D))
       return true;
     
-    if (D->hasValue() && !super::visit(D->getValue()))
+    if (D->hasValue() && !super::visit_(D->getValue()))
       return false;
     return Walker.postWalk(D);
   }
@@ -108,7 +420,7 @@ public:
     // Skip subtree
     if (!Walker.preWalk(E))
       return true;
-    if (!super::visit(E->getValues()))
+    if (!super::visit_(E->getValues()))
       return false;
     return Walker.postWalk(E);
   }
@@ -126,7 +438,7 @@ public:
     if (!Walker.preWalk(E))
       return true;
 
-    if (!super::visit(E->getExpr()))
+    if (!super::visit_(E->getExpr()))
       return false;
     return Walker.postWalk(E);
   }
@@ -136,9 +448,9 @@ public:
     if (!Walker.preWalk(E))
       return true;
 
-    if (!super::visit(E->getDest()))
+    if (!super::visit_(E->getDest()))
       return false;
-    if (!super::visit(E->getSource()))
+    if (!super::visit_(E->getSource()))
       return false;
     return Walker.postWalk(E);
   }
@@ -148,9 +460,9 @@ public:
     if (!Walker.preWalk(E))
       return true;
 
-    if (!super::visit(E->getLHS()))
+    if (!super::visit_(E->getLHS()))
       return false;
-    if (!super::visit(E->getRHS()))
+    if (!super::visit_(E->getRHS()))
       return false;
     return Walker.postWalk(E);
   }
@@ -160,7 +472,7 @@ public:
     if (!Walker.preWalk(E))
       return true;
 
-    if (!super::visit(E->getDest()))
+    if (!super::visit_(E->getDest()))
       return false;
     return Walker.postWalk(E);
   }
@@ -170,9 +482,9 @@ public:
     if (!Walker.preWalk(E))
       return true;
 
-    if (!super::visit(E->getCalle()))
+    if (!super::visit_(E->getCallee()))
       return false;
-    if (!super::visit(E->getArgs()))
+    if (!super::visit_(E->getArgs()))
       return false;
     return Walker.postWalk(E);
   }
@@ -182,9 +494,9 @@ public:
     if (!Walker.preWalk(E))
       return true;
 
-    if (!super::visit(E->getBase()))
+    if (!super::visit_(E->getBase()))
       return false;
-    if (!super::visit(E->getSubscript()))
+    if (!super::visit_(E->getSubscript()))
       return false;
     return Walker.postWalk(E);
   }
@@ -203,7 +515,7 @@ public:
     if (!Walker.preWalk(S))
       return true;
 
-    if (S->hasValue() && !super::visit(S->getValue()))
+    if (S->hasValue() && !super::visit_(S->getValue()))
       return false;
     return Walker.postWalk(S);
   }
@@ -213,9 +525,9 @@ public:
     if (!Walker.preWalk(S))
       return false;
 
-    if (!super::visit(S->getStart()))
+    if (!super::visit_(S->getStart()))
       return false;
-    if (!super::visit(S->getEnd()))
+    if (!super::visit_(S->getEnd()))
       return false;
     return Walker.postWalk(S);
   }
@@ -225,7 +537,7 @@ public:
     if (!Walker.preWalk(S))
       return true;
     
-    if (!super::visit(S->getValue()))
+    if (!super::visit_(S->getValue()))
       return false;
     return Walker.postWalk(S);
   }
@@ -236,7 +548,7 @@ public:
       return true;
 
     for (auto N : S->getNodes())
-      if (!super::visit(N))
+      if (!super::visit_(N))
         return false;
     return Walker.postWalk(S);
   }
@@ -246,7 +558,7 @@ public:
     if (!Walker.preWalk(S))
       return true;
     
-    if (!super::visit(S->getPrototype()))
+    if (!super::visit_(S->getPrototype()))
       return false;
     return Walker.postWalk(S);
   }
@@ -256,9 +568,9 @@ public:
     if (!Walker.preWalk(S))
       return true;
     
-    if (!super::visit(S->getPrototype()))
+    if (!super::visit_(S->getPrototype()))
       return false;
-    if (!super::visit(S->getBody()))
+    if (!super::visit_(S->getBody()))
       return false;
     return Walker.postWalk(S);
   }
@@ -268,9 +580,9 @@ public:
     if (!Walker.preWalk(S))
       return false;
 
-    if (!super::visit(S->getRange()))
+    if (!super::visit_(S->getRange()))
       return false;
-    if (!super::visit(S->getBody()))
+    if (!super::visit_(S->getBody()))
       return false;
     return Walker.postWalk(S);
   }
@@ -280,11 +592,11 @@ public:
     if (!Walker.preWalk(S))
       return true;
 
-    if (!super::visit(S->getCond()))
+    if (!super::visit_(S->getCond()))
       return false;
-    if (!super::visit(S->getThen()))
+    if (!super::visit_(S->getThen()))
       return false;
-    if (S->hasElseBlock() && !super::visit(S->getElse()))
+    if (S->hasElseBlock() && !super::visit_(S->getElse()))
       return false;
     return Walker.postWalk(S);
   }
@@ -294,9 +606,9 @@ public:
     if (!Walker.preWalk(S))
       return true;
 
-    if (!super::visit(S->getCond()))
+    if (!super::visit_(S->getCond()))
       return false;
-    if (!super::visit(S->getBody()))
+    if (!super::visit_(S->getBody()))
       return false;
     return Walker.postWalk(S);
   }
@@ -309,7 +621,7 @@ public:
       return true;
 
     for (auto V : P->getValues())
-      if (!super::visit(V))
+      if (!super::visit_(V))
         return false;
     return Walker.postWalk(P);
   }
@@ -320,7 +632,7 @@ public:
       return true;
 
     for (auto V : P->getVars())
-      if (!super::visit(V))
+      if (!super::visit_(V))
         return false;
     return Walker.postWalk(P);
   }
@@ -330,6 +642,25 @@ public:
 
 // MARK: - Basic ASTNodes implementations
 
-bool ASTNode::walk(ASTWalker &Walker) {
-  return Traversal(Walker).ASTVisitor::visit(this);
+bool Decl::walk(ASTWalker &Walker) {
+//  return Traversal(Walker).ASTVisitor::visit_(this);
+  return Traversal(Walker).traverse(this);
+}
+
+bool Expr::walk(ASTWalker &Walker) {
+  //  return Traversal(Walker).ASTVisitor::visit_(this);
+    return Traversal(Walker).traverse(this) != nullptr;
+}
+
+bool Stmt::walk(ASTWalker &Walker) {
+  //  return Traversal(Walker).ASTVisitor::visit_(this);
+    return Traversal(Walker).traverse(this);
+}
+
+bool Pattern::walk(ASTWalker &Walker) {
+  return Traversal(Walker).traverse(this);
+}
+
+bool TypeRepr::walk(ASTWalker &Walker) {
+  return Traversal(Walker).traverse(this);
 }
diff --git a/lib/IRGen/CMakeLists.txt b/lib/IRGen/CMakeLists.txt
index 9d3d15b..0dd1c35 100644
--- a/lib/IRGen/CMakeLists.txt
+++ b/lib/IRGen/CMakeLists.txt
@@ -15,6 +15,8 @@ set(SOURCE
     ${CMAKE_CURRENT_SOURCE_DIR}/IRGenFunc.h
     ${CMAKE_CURRENT_SOURCE_DIR}/IRGenModule.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/IRGenModule.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/IRGenValue.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/IRGenValue.h
     ${CMAKE_CURRENT_SOURCE_DIR}/LoopInfo.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/LoopInfo.h
     ${SOURCE}
diff --git a/lib/IRGen/GenExpr.cpp b/lib/IRGen/GenExpr.cpp
index 5622cc5..863f23f 100644
--- a/lib/IRGen/GenExpr.cpp
+++ b/lib/IRGen/GenExpr.cpp
@@ -170,7 +170,7 @@ llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, AssignExpr *E) {
 
 llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, CallExpr *E) {
   // Get callee as identifier.
-  auto CalleeID = static_cast<IdentifierExpr *>(E->getCalle());
+  auto CalleeID = static_cast<IdentifierExpr *>(E->getCallee());
 
   // Get args
   auto ArgsPttrn = static_cast<ExprPattern *>(E->getArgs());
diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp
index fb3ca65..71f4e5e 100644
--- a/lib/IRGen/GenFunc.cpp
+++ b/lib/IRGen/GenFunc.cpp
@@ -50,7 +50,7 @@ public:
 
   bool visit(BlockStmt *S) {
     for (auto N : S->getNodes())
-      if (!super::visit(N))
+      if (!super::visit_(N))
         return false;
     return true;
   }
@@ -90,7 +90,7 @@ public:
     // Emit Then branch
     IRGF.Builder.SetInsertPoint(ThenBB);
     IRGF.IRGM.Lookup.push();
-    if (!super::visit(S->getThen()))
+    if (!super::visit_(S->getThen()))
       return false;
     IRGF.IRGM.Lookup.pop();
     if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
@@ -100,7 +100,7 @@ public:
     if (S->hasElseBlock()) {
       IRGF.Builder.SetInsertPoint(ElseBB);
       IRGF.IRGM.Lookup.push();
-      if (!super::visit(S->getElse()))
+      if (!super::visit_(S->getElse()))
         return false;
       IRGF.IRGM.Lookup.pop();
       if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
@@ -136,7 +136,7 @@ public:
 
     // Emit loop body
     IRGF.Builder.SetInsertPoint(BodyBlock);
-    if (!super::visit(S->getBody()))
+    if (!super::visit_(S->getBody()))
       return false;
     // Jump back to the condition
     if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
@@ -178,7 +178,7 @@ public:
     
     // Emit loop body
     IRGF.Builder.SetInsertPoint(BodyBlock);
-    if (!super::visit(S->getBody()))
+    if (!super::visit_(S->getBody()))
       return false;
     // Jump back to the condition
     auto Ty = llvm::Type::getInt64Ty(IRGF.IRGM.LLVMContext);
@@ -235,6 +235,6 @@ public:
 
 bool irgen::genFunc(IRGenFunc &IRGF, FuncStmt *F) {
   GenFunc GF(IRGF);
-  return GF.ASTVisitor::visit(F->getBody());
+  return GF.ASTVisitor::visit_(F->getBody());
 }
 
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index b4ce45c..ac179a1 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -35,25 +35,6 @@ IRGenModule::IRGenModule(ASTContext &Ctx, llvm::LLVMContext &LLVMCtx,
 
 Address IRGenModule::declareVal(Decl *D) {
   return codegenDecl(*this, D);
-//  auto Ty = codegenType(*this, D->getType());
-//  if (Lookup.getDepth() == 0) {
-//    if (!Lookup.declareVar(D))
-//      llvm_unreachable("Redefinition of a variable");
-//
-//    auto GV = new llvm::GlobalVariable(*Module, Ty, false,
-//                                         llvm::GlobalValue::InternalLinkage,
-//                                         nullptr, D->getName());
-//    auto InitVal = codegenInit(*this, D->getType());
-//    GV->setInitializer(InitVal);
-//
-//    return GV;
-//  } else {
-//    if (!Lookup.declareVar(D))
-//      llvm_unreachable("Redefinition of a variable");
-//    auto Addr = codegenAlloca(*this, D->getType());
-//    Vals[D] = Addr;
-//    return Addr;
-//  }
 }
 
 Address IRGenModule::declareFunc(FuncDecl *D) {
@@ -78,6 +59,13 @@ Address IRGenModule::getVal(StringRef N) {
   return Module->getGlobalVariable(N, true);
 }
 
+LValue IRGenModule::getValue(StringRef ID) {
+  if (auto Value = std::move(Values[Lookup.getVal(ID)]))
+    return Value;
+  auto Addr = Module->getGlobalVariable(ID, true);
+  return LValue::getVal(nullptr, Addr);
+}
+
 llvm::Function *IRGenModule::getFunc(StringRef N) {
   return Module->getFunction(N);
 }
@@ -86,7 +74,6 @@ llvm::Value *dusk::getRuntimeFunc(llvm::Module *M, StringRef N,
                                   ArrayRef<llvm::Type *> ArgsT,
                                   llvm::Type *RetT) {
   auto Proto = llvm::FunctionType::get(RetT, ArgsT, false);
-  auto Fn = llvm::Function::Create(Proto, llvm::GlobalValue::ExternalLinkage);
-  return Fn;
+  return llvm::Function::Create(Proto, llvm::GlobalValue::ExternalLinkage);
 }
 
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index a11ec7e..ccb97d2 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -16,6 +16,7 @@
 #include "llvm/IR/IRBuilder.h"
 
 #include "Address.h"
+#include "IRGenValue.h"
 
 namespace llvm {
 class Constant;
@@ -43,6 +44,7 @@ public:
   
   NameLookup Lookup;
   llvm::DenseMap<Decl *, Address> Vals;
+  llvm::DenseMap<Decl *, LValue> Values;
 
   IRGenModule(ASTContext &Ctx, llvm::LLVMContext &LLVMCtx, llvm::Module *M,
               llvm::IRBuilder<> &B);
@@ -56,6 +58,9 @@ public:
   Address getVal(StringRef N);
   /// Returns declared function.
   llvm::Function *getFunc(StringRef N);
+  
+  /// Return lvalue for given identifier.
+  LValue getValue(StringRef ID);
 };
   
 } // namespace irgen
diff --git a/lib/IRGen/IRGenValue.cpp b/lib/IRGen/IRGenValue.cpp
new file mode 100644
index 0000000..db1f916
--- /dev/null
+++ b/lib/IRGen/IRGenValue.cpp
@@ -0,0 +1,57 @@
+//===--- IRGenValue.cpp ---------------------------------------------------===//
+//
+//                                 dusk-lang
+// This source file is part of a dusk-lang project, which is a semestral
+// assignement for BI-PJP course at Czech Technical University in Prague.
+// The software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IRGenValue.h"
+
+#include "dusk/AST/Type.h"
+#include "llvm/IR/Value.h"
+
+using namespace dusk;
+using namespace irgen;
+
+// MARK: - rvalue
+
+RValue::RValue() : Value(nullptr), Ty(nullptr) {}
+
+// MARK: - lvalue
+
+LValue::LValue()
+    : Kind(LValue::Simple), Value(nullptr), Ty(nullptr), ArrIdx(nullptr) {}
+
+LValue::LValue(Type *Ty, Address Addr)
+    : Kind(LValue::Simple), Value(Addr), Ty(Ty), ArrIdx(nullptr) {}
+
+LValue::LValue(Type *Ty, Address Addr, llvm::Value *Idx)
+  : Kind(LValue::ArrayElement), Value(Addr), Ty(Ty), ArrIdx(Idx) {}
+
+LValue::LValue(LValue &&Other)
+    : Kind(Other.Kind), Value(Other.Value), Ty(Other.Ty), ArrIdx(Other.ArrIdx) {
+  assert(isValid() && "Copy of invalid l-value");
+}
+
+LValue &LValue::operator=(LValue &&Other) {
+  assert(!isValid() && "Overriding valid value");
+  Kind = Other.Kind;
+  Value = Other.Value;
+  Ty = Other.Ty;
+  ArrIdx = Other.ArrIdx;
+  return *this;
+}
+
+LValue LValue::getVal(Type *Ty, Address Val) {
+  LValue Ret(Ty, Val);
+  Ret.Kind = LValue::Simple;
+  return Ret;
+}
+
+LValue LValue::getArrayElem(Type *Ty, Address Val, llvm::Value *Idx) {
+  LValue Ret(Ty, Val, Idx);
+  return Ret;
+}
+
diff --git a/lib/IRGen/IRGenValue.h b/lib/IRGen/IRGenValue.h
new file mode 100644
index 0000000..1ea1543
--- /dev/null
+++ b/lib/IRGen/IRGenValue.h
@@ -0,0 +1,128 @@
+//===--- IRGenValue.h - Value representation --------------------*- 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_IRGEN_IRGEN_VALUE_H
+#define DUSK_IRGEN_IRGEN_VALUE_H
+
+#include "Address.h"
+
+namespace llvm {
+class Value;
+} // namespace llvm
+
+namespace dusk {
+class Type;
+
+namespace irgen {
+
+/// Represents a single rvalue reference.
+class RValue {
+  llvm::Value *Value;
+
+  Type *Ty;
+
+public:
+  RValue();
+  
+  static RValue get(Type *Ty, llvm::Value *V);
+
+private:
+  RValue(const RValue &) = delete;
+  RValue &operator=(const RValue &) = delete;
+};
+
+
+/// Represents a single lvalue refenrece.
+class LValue {
+  enum KindType { Simple, ArrayElement };
+
+  KindType Kind;
+
+  /// Encapsulated raw value address.
+  llvm::Value *Value;
+
+  /// Type of value.
+  Type *Ty;
+  
+  /// Index of referenced element in array.
+  llvm::Value *ArrIdx;
+
+public:
+  /// Creates an empty invalid lvalue.
+  LValue();
+  /// Creates a siple lvalue
+  LValue(Type *Ty, Address Addr);
+  /// Creates a array access lvalue.
+  LValue(Type *Ty, Address Addr, llvm::Value *Idx);
+  /// Moving constructor for copying of lvalues.
+  LValue(LValue &&);
+  LValue &operator=(LValue &&);
+
+  operator bool() const { return isValid(); }
+  
+  /// Return \c true if type and value are set, \c false otherwise.
+  bool isValid() const { return Ty != nullptr && Value != nullptr; }
+  
+  bool isSimple() const { return Kind == Simple; }
+  bool isArrayElement() const { return Kind == ArrayElement; }
+
+  /// Sets raw address of referenced value.
+  void setAddress(Address Addr) { Value = Addr; }
+  
+  /// Returns raw address of referenced value.
+  Address getAddress() const { return Value; }
+  
+  /// Sets type of referenced value.
+  void setType(Type *T) { Ty = T; }
+  
+  /// Returns raw address of referenced value.
+  Type *getType() const { return Ty; }
+  
+  /// Returns pointer to the referenced value.
+  ///
+  /// \note Referenced value must be a simple value.
+  llvm::Value *getPointer() const {
+    assert(isSimple() && "Invalid address access.");
+    return Value;
+  }
+
+  /// Returns pointer to the start of the array, which contains referenced
+  /// element.
+  ///
+  /// \note Referened value must be an array element.
+  llvm::Value *getArrayPtr() const {
+    assert(isArrayElement() && "Invalid address access.");
+    return Value;
+  }
+  
+  /// Return index of referenced value as value.
+  ///
+  /// \note Referened value must be an array element.
+  llvm::Value *getElementIndex() const {
+    assert(isArrayElement() && "Invalid address access.");
+    return Value;
+  }
+
+  // MARK: - static construction methods
+  
+  /// Creates and returns a simple lvalue.
+  static LValue getVal(Type *Ty, Address Val);
+  
+  /// Creates and returns an array element lvalue.
+  static LValue getArrayElem(Type *Ty, Address Val, llvm::Value *Idx);
+
+private:
+  LValue(const LValue &) = delete;
+  LValue &operator=(const LValue &) = delete;
+};
+
+} // namespace irgen
+} // namespace dusk
+
+#endif /* DUSK_IRGEN_IRGEN_VALUE_H */
diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp
index 7b32cc9..7f5f8f8 100644
--- a/lib/Sema/TypeCheckExpr.cpp
+++ b/lib/Sema/TypeCheckExpr.cpp
@@ -85,11 +85,11 @@ bool TypeChecker::postWalkPrefixExpr(PrefixExpr *E) {
 }
 
 bool TypeChecker::postWalkCallExpr(CallExpr *E) {
-  auto FTy = dynamic_cast<FunctionType *>(E->getCalle()->getType());
+  auto FTy = dynamic_cast<FunctionType *>(E->getCallee()->getType());
 
   // Check if references a function
   if (!FTy) {
-    diagnose(E->getCalle()->getLocStart(), diag::func_call_non_func_type);
+    diagnose(E->getCallee()->getLocStart(), diag::func_call_non_func_type);
     return false;
   }
 
-- 
GitLab