diff --git a/CMakeLists.txt b/CMakeLists.txt
index 76493d03aa95d40587a42cde6990f434f083521f..dba0d98815f16600b5a12a2ba98e7d0c9662640f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 3.4 FATAL_ERROR)
-set(LIB_TARGET dusklib)
+set(LIB_TARGET dusk)
 set(PROJECT_VERSION 1.0.0)
 project(
     "dusk-lang"
@@ -23,12 +23,12 @@ add_definitions(${LLVM_DEFINITIONS})
 include_directories(${LLVM_INCLUDE_DIRS})
 llvm_map_components_to_libnames(llvm_libs all)
 
-# add dusklib target
+# add lib target
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/include)
 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib)
 
-# setup dusklib
+# setup lib
 add_library(${LIB_TARGET} SHARED ${SOURCE})
 set_target_properties(${LIB_TARGET} PROPERTIES
     VERSION ${PROJECT_VERSION}
diff --git a/examples/funcDecl.dusk b/examples/funcDecl.dusk
index 4b34590da67bcbf2bad48d4f143617f87cadfafc..2b13d556e106100b00d9f83ec4012b0b72671877 100644
--- a/examples/funcDecl.dusk
+++ b/examples/funcDecl.dusk
@@ -1,14 +1,22 @@
-extern func test();
-extern func println(output: Int) -> Void;
+//extern func test();
+extern func println(output: Int) -> Int;
 
-func main(arg1: Int) -> Int {
-    if arg1 % 2 == 0 {
-        return inc(arg1);
-    }
-    println(arg1);
+/*func main(arg1: Int) -> Int {
     return arg1;
+}*/
+
+func isEven(val: Int) {
+    var i = 0;
+    while 1 {
+        println(i);
+        i = i + 1;
+        if i > val {
+            break;
+        }
+    }
 }
 
 func inc(i: Int) -> Int {
+    println(i);
     return i + 1;
 }
diff --git a/examples/globExpr.dusk b/examples/globExpr.dusk
index 4166ea3bf3db8c2d0d061da64f2adb89e66a6986..49a177689e3a61a584944d4bacb4e7d06c7cae9e 100644
--- a/examples/globExpr.dusk
+++ b/examples/globExpr.dusk
@@ -7,3 +7,11 @@ a = (1 + 2) * 8 == 2;
 a = (1 + 2 * d) || (4 % 3);
 ext(d);
 
+
+// var v = ext(a);
+// var vv;
+// var vvv: Int;
+// let l: Int = 4;
+// let ll = 44;
+// let lll: Int;
+ll = 14;
diff --git a/include/dusk/AST/CMakeLists.txt b/include/dusk/AST/CMakeLists.txt
index 1fa3515f0dc92fa81f43633e4bb36f8936fb6176..8b7c4a4eae2c0d68d95ee005112a0758cf8f3e1f 100644
--- a/include/dusk/AST/CMakeLists.txt
+++ b/include/dusk/AST/CMakeLists.txt
@@ -8,6 +8,7 @@ set(HEADERS
     ${CMAKE_CURRENT_SOURCE_DIR}/Diagnostics.h
     ${CMAKE_CURRENT_SOURCE_DIR}/DiagnosticsParse.h
     ${CMAKE_CURRENT_SOURCE_DIR}/Expr.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/NameLookup.h
     ${CMAKE_CURRENT_SOURCE_DIR}/Pattern.h
     ${CMAKE_CURRENT_SOURCE_DIR}/Scope.h
     ${CMAKE_CURRENT_SOURCE_DIR}/Stmt.h
diff --git a/include/dusk/Sema/Context.h b/include/dusk/AST/NameLookup.h
similarity index 80%
rename from include/dusk/Sema/Context.h
rename to include/dusk/AST/NameLookup.h
index 3c3a08c415cb06b8dd24742d3ed87f4b7e66588a..f4283898f19e70e7f1bf58a9810f59b6d5567c28 100644
--- a/include/dusk/Sema/Context.h
+++ b/include/dusk/AST/NameLookup.h
@@ -1,4 +1,4 @@
-//===--- Context.h - Semantic declaration context ---------------*- C++ -*-===//
+//===--- NameLookup.h - Name lookup of declarations -------------*- C++ -*-===//
 //
 //                                 dusk-lang
 // This source file is part of a dusk-lang project, which is a semestral
@@ -7,8 +7,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef DUSK_SEMA_CONTEXT_H
-#define DUSK_SEMA_CONTEXT_H
+#ifndef DUSK_CONTEXT_H
+#define DUSK_CONTEXT_H
 
 #include "dusk/Basic/LLVM.h"
 #include "llvm/ADT/StringRef.h"
@@ -17,16 +17,14 @@
 
 namespace dusk {
 class Decl;
-  
-namespace sema {
 
 /// Represents current context declaration level.
 ///
 /// Constructors of this struct are private, instances of \c ContextVals class
 /// can be made by only \c Context instances.
-struct ContextImpl {
+struct LookupImpl {
   /// Holds pointer to the parent context.
-  std::unique_ptr<ContextImpl> Parent = nullptr;
+  std::unique_ptr<LookupImpl> Parent = nullptr;
   
   /// Holds constant declarations of current scope.
   llvm::StringMap<Decl *> Consts;
@@ -49,37 +47,37 @@ public:
   /// Returns variable for given name, if found, \c nullptr otherwise.
   Decl *get(StringRef Str) const;
   
-  /// Pushes a new context to the stack and returns a pointer to the top of the
-  /// stack.
-  ContextImpl *push();
+  /// Pushes a new context layer to the stack and returns a pointer to the top
+  /// of the stack.
+  LookupImpl *push();
   
-  /// Pop a top context from the stack and returns a pointer to the top of the
-  /// stack.
+  /// Pop a top context layer from the stack and returns a pointer to the top
+  /// of the stack.
   ///
   /// \note This method calls \c delete \c this on itself, therefore noone
   /// should access this object after calling this method.
-  ContextImpl *pop();
+  LookupImpl *pop();
   
 private:
-  friend class Context;
-  ContextImpl() = default;
-  ContextImpl(ContextImpl *P);
+  friend class NameLookup;
+  LookupImpl() = default;
+  LookupImpl(LookupImpl *P);
   
-  ContextImpl(const ContextImpl &other) = delete;
-  ContextImpl &operator=(const ContextImpl &other) = delete;
+  LookupImpl(const LookupImpl &other) = delete;
+  LookupImpl &operator=(const LookupImpl &other) = delete;
 };
 
-/// Represents a current declaration context.
+/// Represents a current declaration lookup context.
 ///
 /// Holds declaration of variables, constatnts and functions.
-class Context {
+class NameLookup {
   llvm::StringMap<Decl *> Funcs;
-  ContextImpl *Impl;
+  LookupImpl *Impl;
   unsigned Depth = 0;
   
 public:
-  Context();
-  ~Context();
+  NameLookup();
+  ~NameLookup();
   
   /// Returns current depth of the context.
   unsigned getDepth() const { return Depth; }
@@ -131,9 +129,7 @@ public:
   /// Pops current scope from the internal stack.
   void pop();
 };
-
-} // namespace sema
   
 } // namespace dusk
 
-#endif /* DUSK_SEMA_CONTEXT_H */
+#endif /* DUSK_NAME_LOOKUP_H */
diff --git a/include/dusk/IRGen/CMakeLists.txt b/include/dusk/IRGen/CMakeLists.txt
index 7c9df5ca67fa2dda671b7954bd526167bce034c9..a5c99b172835fd56238fbe2aafde372bc5e74bff 100644
--- a/include/dusk/IRGen/CMakeLists.txt
+++ b/include/dusk/IRGen/CMakeLists.txt
@@ -1,5 +1,4 @@
 set(HEADERS
-    ${CMAKE_CURRENT_SOURCE_DIR}/Context.h
     ${CMAKE_CURRENT_SOURCE_DIR}/IRGenerator.h
     ${HEADERS}
     PARENT_SCOPE
diff --git a/include/dusk/IRGen/Context.h b/include/dusk/IRGen/Context.h
deleted file mode 100644
index 2ef5bc6f7bdfd4dde91c6f468c866f1f9b7c976b..0000000000000000000000000000000000000000
--- a/include/dusk/IRGen/Context.h
+++ /dev/null
@@ -1,171 +0,0 @@
-//===--- Context.h - Dusck context interface --------------------*- 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 implements Dusk context interaface.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef DUSK_IRGEN_CONTEXT_H
-#define DUSK_IRGEN_CONTEXT_H
-
-#include "dusk/Basic/LLVM.h"
-#include "dusk/AST/Scope.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/Value.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/GlobalVariable.h"
-#include "llvm/IR/BasicBlock.h"
-#include <utility>
-#include <memory>
-
-namespace dusk {
-class Decl;
-class FuncDecl;
-class ParamDecl;
-
-namespace irgen {
-
-/// Represents a basic block range.
-struct BlockRange {
-  llvm::BasicBlock *Start;
-  llvm::BasicBlock *End;
-
-  BlockRange();
-  BlockRange(llvm::BasicBlock *S, llvm::BasicBlock *E);
-};
-
-/// Represents current context declaration level.
-///
-/// Constructors of this struct are private, instances of \c ContextVals class
-/// can be made by only \c Context instances.
-struct ContextImpl {
-  /// Holds pointer to the parent context.
-  std::unique_ptr<ContextImpl> Parent = nullptr;
-
-  /// Holds value declarations of current scope.
-  llvm::StringMap<llvm::Value *> Values;
-
-public:
-  /// Returns \c true if there is a reachable value delcaration for given name
-  /// the scope, \c false otherwise.
-  bool contains(StringRef Str) const { return get(Str) != nullptr; }
-
-  /// Returns \c true if a declaration for given name was performed in current
-  /// scope.
-  bool isDeclared(StringRef Str) const;
-
-  /// Returns variable for given name, if found, \c nullptr otherwise.
-  llvm::Value *get(StringRef Str) const;
-
-  /// Pushes a new context to the stack and returns a pointer to the top of the
-  /// stack.
-  ContextImpl *push();
-
-  /// Pop a top context from the stack and returns a pointer to the top of the
-  /// stack.
-  ///
-  /// \note This method calls \c delete \c this on itself, therefore noone
-  /// should access this object after calling this method.
-  ContextImpl *pop();
-
-private:
-  friend class Context;
-  ContextImpl() = default;
-  ContextImpl(ContextImpl *P);
-
-  ContextImpl(const ContextImpl &other) = delete;
-  ContextImpl &operator=(const ContextImpl &other) = delete;
-};
-
-/// Represents a current declaration context.
-///
-/// Holds declaration of variables, constatnts and functions.
-class Context {
-  typedef std::pair<llvm::BasicBlock *, llvm::BasicBlock> BBRange;
-
-  llvm::LLVMContext &Ctx;
-  llvm::StringMap<llvm::FunctionType *> Funcs;
-  llvm::DenseMap<Scope *, BlockRange> ScopeRanges;
-  ContextImpl *Impl;
-  unsigned Depth = 0;
-
-public:
-  llvm::Module *Module;
-  llvm::IRBuilder<> &Builder;
-
-  Context(llvm::LLVMContext &C, llvm::Module *M, llvm::IRBuilder<> &B);
-  ~Context();
-
-  operator llvm::LLVMContext &() { return Ctx; }
-
-  /// Returns current depth of the context.
-  unsigned getDepth() const { return Depth; }
-
-  /// \brief Declares a value in current scope.
-  ///
-  /// \return \c true on success, \c false if the current scope is already
-  /// a value or function with the same identifier.
-  bool declareVal(const Decl *);
-  
-  /// \brief Declares a value in current scope.
-  ///
-  /// \return \c true on success, \c false if the current scope is already
-  /// a value or function with the same identifier.
-  bool declareVal(const Decl *, llvm::Function *);
-
-  /// \brief Declares a function.
-  ///
-  /// \note Function can be delcared only in the global scope.
-  ///
-  /// \return \c true on success, \c false if a function with given identifier
-  /// already exists.
-  bool declareFunc(const FuncDecl *);
-
-  /// Returns a value for given identifier.
-  ///
-  /// If no value is found, \c nullptr is returned.
-  llvm::Value *getVal(StringRef Str) const;
-
-
-  /// Returns function type for given identifier.
-  ///
-  /// If no type is found, \c nullptr is returned.
-  llvm::FunctionType *getFuncProto(StringRef Str);
-
-  /// Return function for given identifier.
-  llvm::Function *getFunc(StringRef Str);
-
-  /// Returns \c true, if in the current scope if a declaration associated with
-  /// given identifier.
-  bool contains(StringRef Str) const;
-
-  /// Pushes a new scope to the internal stack.
-  void push();
-
-  /// Pops current scope from the internal stack.
-  void pop();
-
-  void pushScope(Scope *S, BlockRange R);
-
-  BlockRange &getRange(Scope *S);
-
-  void popScope(Scope *S);
-};
-
-} // namespace irgen
-
-} // namespace dusk
-
-#endif /* DUSK_IRGEN_CONTEXT_H */
diff --git a/include/dusk/IRGen/IRGenerator.h b/include/dusk/IRGen/IRGenerator.h
index 0ef40053790f110c10beda6b0d3658e7f8dd06fd..93354b02bdc5566bc9715043fb008c8cbc087aaa 100644
--- a/include/dusk/IRGen/IRGenerator.h
+++ b/include/dusk/IRGen/IRGenerator.h
@@ -16,8 +16,8 @@
 #include "dusk/AST/Pattern.h"
 #include "dusk/AST/ASTWalker.h"
 #include "dusk/AST/Diagnostics.h"
+#include "dusk/AST/NameLookup.h"
 #include "dusk/AST/ASTContext.h"
-#include "dusk/IRGen/Context.h"
 
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/APInt.h"
@@ -41,22 +41,17 @@ namespace irgen {
 
 class IRGenerator : public ASTWalker {
   llvm::StringMap<llvm::AllocaInst *> NamedValues;
-  ASTContext &ASTCtx;
+  ASTContext &Context;
   DiagnosticEngine &Diag;
-  llvm::LLVMContext Ctx;
+  llvm::LLVMContext LLVMContext;
   llvm::IRBuilder<> Builder;
   std::unique_ptr<llvm::Module> Module;
-  
-  
 
 public:
   IRGenerator(ASTContext &Ctx, DiagnosticEngine &Diag);
   ~IRGenerator();
   
   llvm::Module *perform();
-  
-private:
-    bool declareFuncs(Context &Ctx, ModuleDecl *M);
 };
 
 } // namespace ir
diff --git a/include/dusk/Sema/CMakeLists.txt b/include/dusk/Sema/CMakeLists.txt
index 899180fcce42a5666254a11597f7cd2dfcd2a6aa..f79444778b836feb3bd5b3a34cabc30a94b63d4e 100644
--- a/include/dusk/Sema/CMakeLists.txt
+++ b/include/dusk/Sema/CMakeLists.txt
@@ -1,5 +1,4 @@
 set(HEADERS
-    ${CMAKE_CURRENT_SOURCE_DIR}/Context.h
     ${CMAKE_CURRENT_SOURCE_DIR}/Sema.h
     ${HEADERS}
     PARENT_SCOPE
diff --git a/include/dusk/Sema/Sema.h b/include/dusk/Sema/Sema.h
index 4cb08fdbc947640ed712ae53d6a7ba2f7fd19c73..b282121e40ae159cb5e500186fa9696c121bbedc 100644
--- a/include/dusk/Sema/Sema.h
+++ b/include/dusk/Sema/Sema.h
@@ -13,7 +13,7 @@
 #include "dusk/AST/ASTContext.h"
 #include "dusk/AST/ASTNode.h"
 #include "dusk/AST/Diagnostics.h"
-#include "dusk/Sema/Context.h"
+#include "dusk/AST/NameLookup.h"
 #include "dusk/AST/Scope.h"
 #include "llvm/Support/SourceMgr.h"
 
@@ -38,7 +38,7 @@ class Sema {
   ASTContext &Ctx;
   DiagnosticEngine &Diag;
   
-  Context DeclCtx;
+  NameLookup DeclCtx;
   Scope Scp;
   
 public:
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 8cf5d93b600b8b0ec528ce5586233e2dc4dd73a9..205f2e292865b992790e641f12d5484c283e758a 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -6,6 +6,7 @@ set(SOURCE
     ${CMAKE_CURRENT_SOURCE_DIR}/Decl.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Diagnostics.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Expr.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/NameLookup.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Pattern.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Scope.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Stmt.cpp
diff --git a/lib/Sema/Context.cpp b/lib/AST/NameLookup.cpp
similarity index 67%
rename from lib/Sema/Context.cpp
rename to lib/AST/NameLookup.cpp
index f979db6012c23e5968691284032037835e187d2d..346290203c9cee0eda74e180425650cba343ad0a 100644
--- a/lib/Sema/Context.cpp
+++ b/lib/AST/NameLookup.cpp
@@ -1,4 +1,4 @@
-//===--- Context.cpp ------------------------------------------------------===//
+//===--- NameLookup.cpp ---------------------------------------------------===//
 //
 //                                 dusk-lang
 // This source file is part of a dusk-lang project, which is a semestral
@@ -7,29 +7,28 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "dusk/Sema/Context.h"
+#include "dusk/AST/NameLookup.h"
 #include "dusk/AST/Decl.h"
 
 using namespace dusk;
-using namespace sema;
 
 // MARK: - Context values
 
-ContextImpl::ContextImpl(ContextImpl *P) : Parent(P) {}
+LookupImpl::LookupImpl(LookupImpl *P) : Parent(P) {}
 
-ContextImpl *ContextImpl::push() { return new ContextImpl(this); }
+LookupImpl *LookupImpl::push() { return new LookupImpl(this); }
 
-ContextImpl *ContextImpl::pop() {
+LookupImpl *LookupImpl::pop() {
   auto Ret = Parent.release();
   delete this;
   return Ret;
 }
 
-bool ContextImpl::isDeclared(StringRef Str) const {
+bool LookupImpl::isDeclared(StringRef Str) const {
   return Vars.find(Str) != Vars.end() || Consts.find(Str) != Consts.end();
 }
 
-Decl *ContextImpl::getVar(StringRef Str) const {
+Decl *LookupImpl::getVar(StringRef Str) const {
   auto Var = Vars.find(Str);
   if (Var != Vars.end())
     return Var->second;
@@ -39,7 +38,7 @@ Decl *ContextImpl::getVar(StringRef Str) const {
   return nullptr;
 }
 
-Decl *ContextImpl::get(StringRef Str) const {
+Decl *LookupImpl::get(StringRef Str) const {
   if (auto Var = getVar(Str))
     return Var;
   
@@ -54,11 +53,11 @@ Decl *ContextImpl::get(StringRef Str) const {
 
 // MARK: - Context
 
-Context::Context(): Impl(new ContextImpl()) {}
+NameLookup::NameLookup(): Impl(new LookupImpl()) {}
 
-Context::~Context() { delete Impl; }
+NameLookup::~NameLookup() { delete Impl; }
 
-bool Context::declareVar(Decl *D) {
+bool NameLookup::declareVar(Decl *D) {
   // Check if already declared in current scope
   if (Impl->isDeclared(D->getName()) || Funcs[D->getName()] != nullptr)
     return false;
@@ -67,7 +66,7 @@ bool Context::declareVar(Decl *D) {
   return true;
 }
 
-bool Context::declareLet(Decl *D) {
+bool NameLookup::declareLet(Decl *D) {
   // Check if already declared in current scope
   if (Impl->isDeclared(D->getName()) || Funcs[D->getName()] != nullptr)
     return false;
@@ -75,7 +74,7 @@ bool Context::declareLet(Decl *D) {
   return true;
 }
 
-bool Context::declareFunc(Decl *Fn) {
+bool NameLookup::declareFunc(Decl *Fn) {
   // Validate that we're in global scope.
   assert(Depth == 0 && "Function declaration must be declared in global scope");
   
@@ -86,24 +85,24 @@ bool Context::declareFunc(Decl *Fn) {
   return true;
 }
 
-Decl *Context::getVal(StringRef Str) const { return Impl->get(Str); }
+Decl *NameLookup::getVal(StringRef Str) const { return Impl->get(Str); }
 
-Decl *Context::getVar(StringRef Str) const { return Impl->getVar(Str); }
+Decl *NameLookup::getVar(StringRef Str) const { return Impl->getVar(Str); }
 
-Decl *Context::getFunc(StringRef Str) { return Funcs[Str]; }
+Decl *NameLookup::getFunc(StringRef Str) { return Funcs[Str]; }
 
 
-bool Context::contains(StringRef Str) const {
+bool NameLookup::contains(StringRef Str) const {
   return Funcs.find(Str) != Funcs.end() || Impl->contains(Str);
 }
 
-void Context::push() {
+void NameLookup::push() {
   ++Depth;
   // Update the 'virtual' stack.
   Impl = Impl->push();
 }
 
-void Context::pop() {
+void NameLookup::pop() {
   assert(Depth != 0 && "Cannot pop from global scope");
   --Depth;
   // Update the 'virtual' stack.
diff --git a/lib/IRGen/Address.h b/lib/IRGen/Address.h
new file mode 100644
index 0000000000000000000000000000000000000000..dbb894ee38dd5b369e8a4d8684550ce1349124ec
--- /dev/null
+++ b/lib/IRGen/Address.h
@@ -0,0 +1,67 @@
+//===--- Address.h - Address 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_ADDRESS_H
+#define DUSK_IRGEN_ADDRESS_H
+
+#include "dusk/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/Value.h"
+#include "llvm/IR/DerivedTypes.h"
+
+namespace dusk {
+
+namespace irgen {
+
+/// A simple convenience address wrapper.
+class Address {
+  /// Encapsulated address.
+  llvm::Value *Addr;
+
+public:
+  /// Creates an invalid address.
+  Address() : Addr(nullptr) {}
+  
+  /// Creates a valid address.
+  Address(llvm::Value *A) : Addr(A) {
+    assert(Addr != nullptr && "Creating an invalid address");
+  }
+
+  /// Convenience imlicit conversion
+  operator llvm::Value *() const {
+    return getAddress();
+  }
+  
+  /// Access the address.
+  llvm::Value *operator->() const {
+    assert(isValid() && "Accessing an invalid address");
+    return getAddress();
+  }
+
+  /// Returns \c true if address is no null, \c false otherwise.
+  bool isValid() const { return Addr != nullptr; }
+
+  /// Returns address value.
+  llvm::Value *getAddress() const { return Addr; }
+  
+  /// Returns address type as a pointer type.
+  llvm::PointerType *getType() const {
+    return llvm::cast<llvm::PointerType>(Addr->getType());
+  }
+  
+  /// Returns IR name of address.
+  llvm::StringRef getName() const {
+    return getAddress()->getName();
+  }
+};
+
+} // namespace irgen
+} // namespcae dusk
+
+#endif /* DUSK_IRGEN_ADDRESS_H */
diff --git a/lib/IRGen/CMakeLists.txt b/lib/IRGen/CMakeLists.txt
index f0a2add9efe19ebc4b0018ad9497cd436160e3d5..f02686421abb9ad62e044a7fc7e6a4d4255086c4 100644
--- a/lib/IRGen/CMakeLists.txt
+++ b/lib/IRGen/CMakeLists.txt
@@ -1,12 +1,18 @@
 set(SOURCE
-    ${CMAKE_CURRENT_SOURCE_DIR}/Context.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/GenDecl.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/GenDecl.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/Address.h
     ${CMAKE_CURRENT_SOURCE_DIR}/GenExpr.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/GenExpr.h
-    ${CMAKE_CURRENT_SOURCE_DIR}/GenStmt.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/GenStmt.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/GenFunc.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/GenFunc.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/GenModule.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/GenModule.h
     ${CMAKE_CURRENT_SOURCE_DIR}/IRGenerator.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/IRGenFunc.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/IRGenFunc.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/IRGenModule.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/IRGenModule.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/LoopInfo.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/LoopInfo.h
     ${SOURCE}
     PARENT_SCOPE
 )
diff --git a/lib/IRGen/Context.cpp b/lib/IRGen/Context.cpp
deleted file mode 100644
index 584ffcdedd0d61a84b05b1bb30fe9da0f6e3e6bb..0000000000000000000000000000000000000000
--- a/lib/IRGen/Context.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-//===--- Context.cpp - Dusck context implementation -----------------------===//
-//
-//                                 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 implements Dusk context implementation.
-//
-//===----------------------------------------------------------------------===//
-
-#include "dusk/IRGen/Context.h"
-#include "dusk/AST/Decl.h"
-#include "dusk/AST/Pattern.h"
-#include "dusk/AST/Type.h"
-#include <vector>
-
-#include "GenExpr.h"
-
-using namespace dusk;
-using namespace irgen;
-
-// MARK: - Block range
-
-BlockRange::BlockRange() : Start(nullptr), End(nullptr) {}
-BlockRange::BlockRange(llvm::BasicBlock *S, llvm::BasicBlock *E)
-    : Start(S), End(E) {}
-
-// MARK: - Context values
-
-ContextImpl::ContextImpl(ContextImpl *P) : Parent(P) {}
-
-ContextImpl *ContextImpl::push() { return new ContextImpl(this); }
-
-ContextImpl *ContextImpl::pop() {
-  auto Ret = Parent.release();
-  delete this;
-  return Ret;
-}
-
-bool ContextImpl::isDeclared(StringRef Str) const {
-  return Values.find(Str) != Values.end();
-}
-
-llvm::Value *ContextImpl::get(StringRef Str) const {
-  auto Val = Values.find(Str);
-  if (Val != Values.end())
-    return Val->second;
-  if (Parent != nullptr)
-    return Parent->get(Str);
-  return nullptr;
-}
-
-// MARK: - Context
-
-Context::Context(llvm::LLVMContext &C, llvm::Module *M, llvm::IRBuilder<> &B)
-    : Ctx(C), Impl(new ContextImpl()), Module(M), Builder(B) {}
-
-Context::~Context() { delete Impl; }
-
-bool Context::declareVal(const Decl *D) {
-  // Check if already declared in current scope
-  if (Impl->isDeclared(D->getName()) || Funcs[D->getName()] != nullptr)
-    return false;
-
-  // Check if global
-  if (Depth == 0) {
-    auto GV =
-        Module->getOrInsertGlobal(D->getName(), llvm::Type::getInt64Ty(Ctx));
-    Impl->Values[D->getName()] = GV;
-    return true;
-  }
-
-  auto Ty = llvm::Type::getInt64Ty(Ctx);
-  auto Var = Builder.CreateAlloca(Ty, 0, D->getName());
-  Impl->Values[D->getName()] = Var;
-  return true;
-}
-
-bool Context::declareVal(const Decl *D, llvm::Function *F) {
-  // Check if already declared in current scope
-  if (Impl->isDeclared(D->getName()) || Funcs[D->getName()] != nullptr)
-    return false;
-  
-  llvm::IRBuilder<> TmpB(&F->getEntryBlock(), F->getEntryBlock().begin());
-  
-  auto Ty = llvm::Type::getInt64Ty(Ctx);
-  auto Var = TmpB.CreateAlloca(Ty, 0, D->getName());
-  Impl->Values[D->getName()] = Var;
-  return true;
-}
-
-bool Context::declareFunc(const FuncDecl *Fn) {
-  // Validate that we're in global scope.
-  assert(Depth == 0 && "Function declaration must be declared in global scope");
-
-  // Check if already declared in current scope
-  if (Funcs[Fn->getName()] != nullptr)
-    return false;
-
-  auto FnType = static_cast<FunctionType *>(Fn->getType());
-  auto Ty = llvm::Type::getInt64Ty(Ctx);
-  auto Args = std::vector<llvm::Type *>(Fn->getArgs()->count(), Ty);
-  llvm::Type *RetTy;
-
-  // Resolve return type
-  switch (FnType->getRetType()->getKind()) {
-  case TypeKind::Int:
-    RetTy = llvm::Type::getInt64Ty(Ctx);
-    break;
-  case TypeKind::Void:
-    RetTy = llvm::Type::getVoidTy(Ctx);
-    break;
-  default:
-    llvm_unreachable("Unsupported return type");
-  }
-  auto FT = llvm::FunctionType::get(RetTy, Args, false);
-  Funcs[Fn->getName()] = FT;
-  return true;
-}
-
-llvm::Value *Context::getVal(StringRef Str) const { return Impl->get(Str); }
-
-llvm::FunctionType *Context::getFuncProto(StringRef Str) { return Funcs[Str]; }
-
-llvm::Function *Context::getFunc(StringRef Str) {
-  if (auto F = Module->getFunction(Str))
-    return F;
-  return nullptr;
-}
-
-bool Context::contains(StringRef Str) const {
-  return Funcs.find(Str) != Funcs.end() || Impl->contains(Str);
-}
-
-void Context::push() {
-  ++Depth;
-  // Update the 'virtual' stack.
-  Impl = Impl->push();
-}
-
-void Context::pop() {
-  assert(Depth != 0 && "Cannot pop from global scope");
-  --Depth;
-  // Update the 'virtual' stack.
-  Impl = Impl->pop();
-}
-
-void Context::pushScope(Scope *S, BlockRange R) {
-  assert(ScopeRanges.find(S) == ScopeRanges.end() && "Duplicate scope range");
-  ScopeRanges.try_emplace(S, R);
-}
-
-BlockRange &Context::getRange(Scope *S) {
-  assert(ScopeRanges.find(S) != ScopeRanges.end() && "Missing scope range");
-  return ScopeRanges[S];
-}
-
-void Context::popScope(Scope *S) {
-  assert(ScopeRanges.find(S) != ScopeRanges.end() && "Missing scope range");
-  ScopeRanges.erase(S);
-}
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
deleted file mode 100644
index 71199f2567739de974511d8bff331b10a70edaf3..0000000000000000000000000000000000000000
--- a/lib/IRGen/GenDecl.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-//===--- GenDecl.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 "GenDecl.h"
-#include "GenExpr.h"
-
-using namespace dusk;
-using namespace irgen;
-
-bool irgen::codegenDecl(Context &Ctx, VarDecl *D) {
-  if (!Ctx.declareVal(D))
-    llvm_unreachable("Redefinition");
-  
-  auto Addr = Ctx.getVal(D->getName());
-  auto Val = codegenExpr(Ctx, D->getValue());
-  Ctx.Builder.CreateStore(Val, Addr);
-  return true;
-}
-
-bool irgen::codegenDecl(Context &Ctx, LetDecl *D) {
-  if (!Ctx.declareVal(D))
-    llvm_unreachable("Redefinition");
-  
-  auto Addr = Ctx.getVal(D->getName());
-  auto Val = codegenExpr(Ctx, D->getValue());
-  Ctx.Builder.CreateStore(Val, Addr);
-  return true;
-}
-
-bool irgen::codegenDecl(Context &Ctx, FuncDecl *D) {
-  if (!Ctx.declareFunc(D))
-    llvm_unreachable("Redefinition of function");
-  
-  auto P = Ctx.getFuncProto(D->getName());
-  auto F = llvm::Function::Create(P, llvm::Function::ExternalLinkage,
-                                  D->getName(), Ctx.Module);
-  unsigned Idx = 0;
-  auto Args = D->getArgs()->getVars();
-  for (auto &Arg : F->args())
-    Arg.setName(Args[Idx++]->getName());
-  return true;
-}
-
-bool irgen::codegenDecl(Context &Ctx, ParamDecl *D) {
-  if (!Ctx.declareVal(D))
-    llvm_unreachable("Redefinition.");
-  return true;
-}
-
-bool irgen::codegenDecl(Context &Ctx, Decl *D) {
-  switch (D->getKind()) {
-  case DeclKind::Var:
-    return codegenDecl(Ctx, static_cast<VarDecl *>(D));
-  case DeclKind::Let:
-    return codegenDecl(Ctx, static_cast<LetDecl *>(D));
-  case DeclKind::Func:
-    return codegenDecl(Ctx, static_cast<FuncDecl *>(D));
-  case DeclKind::Param:
-    return codegenDecl(Ctx, static_cast<ParamDecl *>(D));
-  default:
-    llvm_unreachable("Invalid declaration");
-  }
-}
-
diff --git a/lib/IRGen/GenDecl.h b/lib/IRGen/GenDecl.h
deleted file mode 100644
index 802ab7ded75aa6e6017419f91c5b1c8c13988f3a..0000000000000000000000000000000000000000
--- a/lib/IRGen/GenDecl.h
+++ /dev/null
@@ -1,37 +0,0 @@
-//===--- GenDecl.h - Dusk IR declaration generation -------------*- 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_DECL_H
-#define DUSK_IRGEN_DECL_H
-
-#include "dusk/AST/Decl.h"
-#include "dusk/AST/Expr.h"
-#include "dusk/AST/Stmt.h"
-#include "dusk/AST/Pattern.h"
-#include "dusk/IRGen/Context.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Value.h"
-#include "llvm/IR/LLVMContext.h"
-#include "GenExpr.h"
-
-namespace dusk {
-
-namespace irgen {
-  
-bool codegenDecl(Context &Ctx, Decl *D);
-bool codegenDecl(Context &Ctx, VarDecl *D);
-bool codegenDecl(Context &Ctx, LetDecl *D);
-bool codegenDecl(Context &Ctx, FuncDecl *D);
-bool codegenDecl(Context &Ctx, ParamDecl *D);
-  
-} // namespace irgen
-
-} // namespace dusk
-
-#endif /* DUSK_IRGEN_DECL_H */
diff --git a/lib/IRGen/GenExpr.cpp b/lib/IRGen/GenExpr.cpp
index c6933a2385f07b0727282365fcf7b654e133007a..19ede3a6252557e87c1a5a43b010251e6a3e80f3 100644
--- a/lib/IRGen/GenExpr.cpp
+++ b/lib/IRGen/GenExpr.cpp
@@ -13,105 +13,107 @@
 #include "dusk/AST/Expr.h"
 #include "dusk/AST/Stmt.h"
 #include "dusk/AST/Pattern.h"
-#include "dusk/IRGen/Context.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/IR/Constant.h"
 #include <vector>
 
+#include "IRGenModule.h"
+#include "IRGenFunc.h"
+
 using namespace dusk;
 using namespace irgen;
 
-llvm::Value *cast(llvm::Value *V, Context &Ctx, llvm::Type *Ty) {
-  return Ctx.Builder.CreateIntCast(V, Ty, true);
+static llvm::Value *cast(IRGenModule &IRGM, llvm::Value *V, llvm::Type *Ty) {
+  return IRGM.Builder.CreateIntCast(V, Ty, true);
 }
 
-llvm::Value *irgen::codegenExpr(Context &Ctx, NumberLiteralExpr *E) {
-  auto Ty = llvm::Type::getInt64Ty(Ctx);
+llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, NumberLiteralExpr *E) {
+  auto Ty = llvm::Type::getInt64Ty(IRGM.LLVMContext);
   return llvm::ConstantInt::get(Ty, E->getValue());
 }
 
-llvm::Value *irgen::codegenExpr(Context &Ctx, IdentifierExpr *E) {
-  auto Addr = Ctx.getVal(E->getName());
-  return Ctx.Builder.CreateLoad(Addr, E->getName());
+llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, IdentifierExpr *E) {
+  auto Addr = IRGM.getVal(E->getName());
+  return IRGM.Builder.CreateLoad(Addr, E->getName());
 }
 
-llvm::Value *irgen::codegenExpr(Context &Ctx, InfixExpr *E) {
-  auto LHS = codegenExpr(Ctx, E->getLHS());
-  auto RHS = codegenExpr(Ctx, E->getRHS());
-  auto Ty = llvm::Type::getInt64Ty(Ctx);
+llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, InfixExpr *E) {
+  auto LHS = codegenExpr(IRGM, E->getLHS());
+  auto RHS = codegenExpr(IRGM, E->getRHS());
+  auto Ty = llvm::Type::getInt64Ty(IRGM.LLVMContext);
   if (!LHS || !RHS)
     return nullptr;
 
   switch (E->getOp().getKind()) {
   // Arithemtic operations
   case tok::plus:
-    return Ctx.Builder.CreateAdd(LHS, RHS, "addtmp");
+    return IRGM.Builder.CreateAdd(LHS, RHS, "addtmp");
   case tok::minus:
-    return Ctx.Builder.CreateSub(LHS, RHS, "subtmp");
+    return IRGM.Builder.CreateSub(LHS, RHS, "subtmp");
   case tok::multipy:
-    return Ctx.Builder.CreateMul(LHS, RHS, "multmp");
+    return IRGM.Builder.CreateMul(LHS, RHS, "multmp");
   case tok::divide:
-    return Ctx.Builder.CreateSDiv(LHS, RHS, "divtmp");
+    return IRGM.Builder.CreateSDiv(LHS, RHS, "divtmp");
   case tok::mod:
-    return Ctx.Builder.CreateSRem(LHS, RHS, "modtmp");
+    return IRGM.Builder.CreateSRem(LHS, RHS, "modtmp");
 
   // Logical operations
   case tok::land:
-    return cast(Ctx.Builder.CreateAnd(LHS, RHS, "andtmp"), Ctx, Ty);
+    return cast(IRGM, IRGM.Builder.CreateAnd(LHS, RHS, "andtmp"), Ty);
   case tok::lor:
-    return cast(Ctx.Builder.CreateOr(LHS, RHS, "ortmp"), Ctx, Ty);
+    return cast(IRGM, IRGM.Builder.CreateOr(LHS, RHS, "ortmp"), Ty);
   case tok::equals:
-    return cast(Ctx.Builder.CreateICmpEQ(LHS, RHS, "eqtmp"), Ctx, Ty);
+    return cast(IRGM, IRGM.Builder.CreateICmpEQ(LHS, RHS, "eqtmp"), Ty);
   case tok::nequals:
-    return cast(Ctx.Builder.CreateICmpNE(LHS, RHS, "neqtmp"), Ctx, Ty);
+    return cast(IRGM, IRGM.Builder.CreateICmpNE(LHS, RHS, "neqtmp"), Ty);
   case tok::greater:
-    return cast(Ctx.Builder.CreateICmpSGT(LHS, RHS, "gttmp"), Ctx, Ty);
+    return cast(IRGM, IRGM.Builder.CreateICmpSGT(LHS, RHS, "gttmp"), Ty);
   case tok::greater_eq:
-    return cast(Ctx.Builder.CreateICmpSGE(LHS, RHS, "getmp"), Ctx, Ty);
+    return cast(IRGM, IRGM.Builder.CreateICmpSGE(LHS, RHS, "getmp"), Ty);
   case tok::less:
-    return cast(Ctx.Builder.CreateICmpSLT(LHS, RHS, "lttmp"), Ctx, Ty);
+    return cast(IRGM, IRGM.Builder.CreateICmpSLT(LHS, RHS, "lttmp"), Ty);
   case tok::less_eq:
-    return cast(Ctx.Builder.CreateICmpSLE(LHS, RHS, "letmp"), Ctx, Ty);
+    return cast(IRGM, IRGM.Builder.CreateICmpSLE(LHS, RHS, "letmp"), Ty);
 
   default:
     llvm_unreachable("Invalid infix operand");
   }
 }
 
-llvm::Value *irgen::codegenExpr(Context &Ctx, PrefixExpr *E) {
-  auto Val = codegenExpr(Ctx, E->getDest());
-  auto Ty = llvm::Type::getInt64Ty(Ctx);
+llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, PrefixExpr *E) {
+  auto Val = codegenExpr(IRGM, E->getDest());
+  auto Ty = llvm::Type::getInt64Ty(IRGM.LLVMContext);
   if (!Val)
     return nullptr;
 
   switch (E->getOp().getKind()) {
   case tok::lnot:
-    return cast(Ctx.Builder.CreateNot(Val), Ctx, Ty);
+    return cast(IRGM, IRGM.Builder.CreateNot(Val), Ty);
 
   case tok::minus: {
-    auto Ty = llvm::Type::getInt64Ty(Ctx);
+    auto Ty = llvm::Type::getInt64Ty(IRGM.LLVMContext);
     auto Zero = llvm::ConstantInt::get(Ty, 0);
-    return Ctx.Builder.CreateSub(Zero, Val, "unary-subtmp");
+    return IRGM.Builder.CreateSub(Zero, Val, "unary-subtmp");
   }
   default:
     llvm_unreachable("Invalid prefix operand");
   }
 }
 
-llvm::Value *irgen::codegenExpr(Context &Ctx, AssignExpr *E) {
+llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, AssignExpr *E) {
   // Ensure the LHS is a identifier.
   auto VarExpr = static_cast<IdentifierExpr *>(E->getDest());
 
   // Get variable address
-  auto VarAddr = Ctx.getVal(VarExpr->getName());
-  auto Val = codegenExpr(Ctx, E->getSource());
+  auto VarAddr = IRGM.getVal(VarExpr->getName());
+  auto Val = codegenExpr(IRGM, E->getSource());
   if (!VarAddr || !Val)
     llvm_unreachable("Invalid val or addr");
 
-  return Ctx.Builder.CreateStore(Val, VarAddr, "assign");
+  return IRGM.Builder.CreateStore(Val, VarAddr, "assign");
 }
 
-llvm::Value *irgen::codegenExpr(Context &Ctx, CallExpr *E) {
+llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, CallExpr *E) {
   // Get callee as identifier.
   auto CalleeID = static_cast<IdentifierExpr *>(E->getCalle());
 
@@ -119,32 +121,34 @@ llvm::Value *irgen::codegenExpr(Context &Ctx, CallExpr *E) {
   auto ArgsPttrn = static_cast<ExprPattern *>(E->getArgs());
 
   // Get declared function
-  auto Fn = Ctx.getFunc(CalleeID->getName());
+  auto Fn = IRGM.getFunc(CalleeID->getName());
 
   auto Args = std::vector<llvm::Value *>();
-  llvm::errs() << Fn->arg_size();
   for (auto Arg : ArgsPttrn->getValues())
-    Args.push_back(codegenExpr(Ctx, Arg));
-  return Ctx.Builder.CreateCall(Fn, Args);
+    Args.push_back(codegenExpr(IRGM, Arg));
+  return IRGM.Builder.CreateCall(Fn, Args);
 }
 
-llvm::Value *irgen::codegenExpr(Context &Ctx, Expr *E) {
-  switch (E->getKind()) {
-  case ExprKind::NumberLiteral:
-    return codegenExpr(Ctx, static_cast<NumberLiteralExpr *>(E));
-  case ExprKind::Identifier:
-    return codegenExpr(Ctx, static_cast<IdentifierExpr *>(E));
-  case ExprKind::Paren:
-    return codegenExpr(Ctx, static_cast<ParenExpr *>(E)->getExpr());
-  case ExprKind::Assign:
-    return codegenExpr(Ctx, static_cast<AssignExpr *>(E));
-  case ExprKind::Infix:
-    return codegenExpr(Ctx, static_cast<InfixExpr *>(E));
-  case ExprKind::Prefix:
-    return codegenExpr(Ctx, static_cast<PrefixExpr *>(E));
-  case ExprKind::Call:
-    return codegenExpr(Ctx, static_cast<CallExpr *>(E));
-  case ExprKind::Subscript:
-    return codegenExpr(Ctx, static_cast<SubscriptExpr *>(E));
+
+llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, Expr *E) {
+    switch (E->getKind()) {
+    case ExprKind::NumberLiteral:
+      return codegenExpr(IRGM, static_cast<NumberLiteralExpr *>(E));
+    case ExprKind::Identifier:
+      return codegenExpr(IRGM, static_cast<IdentifierExpr *>(E));
+    case ExprKind::Paren:
+      return codegenExpr(IRGM, static_cast<ParenExpr *>(E)->getExpr());
+    case ExprKind::Assign:
+      return codegenExpr(IRGM, static_cast<AssignExpr *>(E));
+    case ExprKind::Infix:
+      return codegenExpr(IRGM, static_cast<InfixExpr *>(E));
+    case ExprKind::Prefix:
+      return codegenExpr(IRGM, static_cast<PrefixExpr *>(E));
+    case ExprKind::Call:
+      return codegenExpr(IRGM, static_cast<CallExpr *>(E));
+    case ExprKind::Subscript:
+//      return codegenExpr(IRGM, static_cast<SubscriptExpr *>(E));
+      llvm_unreachable("Not implemented.");
   }
 }
+
diff --git a/lib/IRGen/GenExpr.h b/lib/IRGen/GenExpr.h
index bd3a6f37d60ce290bd71f1ead151a6a1bce8c639..a1e4559ad50f2bcbc87c448be14d59b420db7f5d 100644
--- a/lib/IRGen/GenExpr.h
+++ b/lib/IRGen/GenExpr.h
@@ -10,6 +10,8 @@
 #ifndef DUSK_IRGEN_EXPR_H
 #define DUSK_IRGEN_EXPR_H
 
+#include "llvm/IR/IRBuilder.h"
+
 namespace llvm {
   class Value;
 }
@@ -22,20 +24,22 @@ class InfixExpr;
 class PrefixExpr;
 class AssignExpr;
 class CallExpr;
-  
+
+
 namespace irgen {
-class Context;
-  
-llvm::Value *codegenExpr(Context &Ctx, Expr *E);
-llvm::Value *codegenExpr(Context &Ctx, NumberLiteralExpr *E);
-llvm::Value *codegenExpr(Context &Ctx, IdentifierExpr *E);
-llvm::Value *codegenExpr(Context &Ctx, InfixExpr *E);
-llvm::Value *codegenExpr(Context &Ctx, PrefixExpr *E);
-llvm::Value *codegenExpr(Context &Ctx, AssignExpr *E);
-llvm::Value *codegenExpr(Context &Ctx, CallExpr *E);
-  
+class IRGenModule;
+class IRGenFunc;
+
+llvm::Value *codegenExpr(IRGenModule &IRGM, NumberLiteralExpr *E);
+llvm::Value *codegenExpr(IRGenModule &IRGM, IdentifierExpr *E);
+llvm::Value *codegenExpr(IRGenModule &IRGM, InfixExpr *E);
+llvm::Value *codegenExpr(IRGenModule &IRGM, PrefixExpr *E);
+llvm::Value *codegenExpr(IRGenModule &IRGM, AssignExpr *E);
+llvm::Value *codegenExpr(IRGenModule &IRGM, CallExpr *E);
+llvm::Value *codegenExpr(IRGenModule &IRGM, Expr *E);
+
 } // namespace irgen
-  
+
 } // namespace dusk
 
 #endif /* DUSK_IRGEN_EXPR_H */
diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fb11e1b47e5fecfd64b3ad9cf18acbab070d4f1a
--- /dev/null
+++ b/lib/IRGen/GenFunc.cpp
@@ -0,0 +1,196 @@
+//===--- GenFunc.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 "GenFunc.h"
+
+#include "dusk/AST/Decl.h"
+#include "dusk/AST/Expr.h"
+#include "dusk/AST/Stmt.h"
+#include "dusk/AST/Pattern.h"
+#include "dusk/AST/Type.h"
+#include "dusk/AST/Decl.h"
+#include "dusk/AST/ASTVisitor.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Type.h"
+
+#include "GenExpr.h"
+#include "IRGenFunc.h"
+
+using namespace dusk;
+using namespace irgen;
+
+static llvm::Value *emitCond(IRGenFunc &IRGF, Expr *E) {
+  auto Cond = codegenExpr(IRGF.IRGM, E);
+  auto Ty = llvm::Type::getInt64Ty(IRGF.IRGM.LLVMContext);
+  auto Zero = llvm::ConstantInt::get(Ty, 0);
+  return IRGF.Builder.CreateICmpNE(Cond, Zero, "ifcond");
+}
+
+namespace {
+
+class GenFunc: public ASTVisitor<GenFunc> {
+  typedef ASTVisitor super;
+
+  IRGenFunc &IRGF;
+
+public:
+  GenFunc(IRGenFunc &IRGF) : IRGF(IRGF) {}
+
+  bool visit(ValDecl *D) {
+    auto Addr = IRGF.declare(D);
+    if (D->hasValue()) {
+      auto Val = codegenExpr(IRGF.IRGM, D->getValue());
+      IRGF.Builder.CreateStore(Val, Addr);
+    }
+    return Addr.isValid();
+  }
+
+  bool visit(BlockStmt *S) {
+    for (auto N : S->getNodes())
+      if (!super::visit(N))
+        return false;
+    return true;
+  }
+
+  bool visit(BreakStmt *S) {
+    // Get end block of top level loop
+    auto EndBB = IRGF.LoopStack.getInfo().getEndBlock();
+    return IRGF.Builder.CreateBr(EndBB) != nullptr;
+  }
+
+  bool visit(ReturnStmt *S) {
+    if (!IRGF.Fn->getReturnType()->isVoidTy()) {
+      auto RetVal = codegenExpr(IRGF.IRGM, S->getValue());
+      IRGF.setRetVal(RetVal);
+    }
+    IRGF.Builder.CreateBr(IRGF.getRetBlock());
+    return true;
+  }
+
+  bool visit(IfStmt *S) {
+    // Create basic blocks
+    auto ThenBB =
+        llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "if.then", IRGF.Fn);
+    auto ElseBB = llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "if.else");
+    auto ContBB = llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "if.cont");
+    // Add basic blocks to function
+    IRGF.Fn->getBasicBlockList().push_back(ElseBB);
+    IRGF.Fn->getBasicBlockList().push_back(ContBB);
+
+    // Emit conditional jump
+    auto Cond = emitCond(IRGF, S->getCond());
+    if (S->hasElseBlock())
+      IRGF.Builder.CreateCondBr(Cond, ThenBB, ElseBB);
+    else
+      IRGF.Builder.CreateCondBr(Cond, ThenBB, ContBB);
+
+    // Emit Then branch
+    IRGF.Builder.SetInsertPoint(ThenBB);
+    IRGF.IRGM.Lookup.push();
+    if (!super::visit(S->getThen()))
+      return false;
+    IRGF.IRGM.Lookup.pop();
+    if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
+      IRGF.Builder.CreateBr(ContBB);
+
+    // Emit else branch
+    if (S->hasElseBlock()) {
+      IRGF.Builder.SetInsertPoint(ElseBB);
+      IRGF.IRGM.Lookup.push();
+      if (!super::visit(S->getElse()))
+        return false;
+      IRGF.IRGM.Lookup.pop();
+      if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
+        IRGF.Builder.CreateBr(ContBB);
+    } else {
+      ElseBB->removeFromParent();
+    }
+
+    // Set pointer to the cont block.
+    IRGF.Builder.SetInsertPoint(ContBB);
+    return true;
+  }
+
+  bool visit(WhileStmt *S) {
+    // Create loop blocks
+    auto HeaderBlock =
+        llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.header", IRGF.Fn);
+    auto BodyBlock =
+        llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.body");
+    auto EndBlock = llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.end");
+    IRGF.IRGM.Lookup.push();
+    IRGF.LoopStack.push(HeaderBlock, EndBlock);
+
+    // Add block to function.
+    IRGF.Fn->getBasicBlockList().push_back(BodyBlock);
+    IRGF.Fn->getBasicBlockList().push_back(EndBlock);
+
+    IRGF.Builder.CreateBr(HeaderBlock);
+    // Emit condition
+    IRGF.Builder.SetInsertPoint(HeaderBlock);
+    auto Cond = emitCond(IRGF, S->getCond());
+    IRGF.Builder.CreateCondBr(Cond, BodyBlock, EndBlock);
+
+    // Emit loop body
+    IRGF.Builder.SetInsertPoint(BodyBlock);
+    if (!super::visit(S->getBody()))
+      return false;
+    // Jump back to the condition
+    if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
+      IRGF.Builder.CreateBr(HeaderBlock);
+
+    IRGF.Builder.SetInsertPoint(EndBlock);
+    IRGF.LoopStack.pop();
+    IRGF.IRGM.Lookup.pop();
+    return true;
+  }
+
+  bool visit(ForStmt *S) { return true; }
+  bool visit(FuncStmt *S) { return true; }
+  bool visit(RangeStmt *S) { return true; }
+  bool visit(SubscriptStmt *S) { return true; }
+  bool visit(ExternStmt *S) { return true; }
+  bool visit(FuncDecl *S) { return true; }
+  bool visit(ModuleDecl *D) { return true; }
+  bool visit(ParamDecl *D) { return true; }
+  bool visit(NumberLiteralExpr *E) {
+    return codegenExpr(IRGF.IRGM, E) != nullptr;
+  }
+  bool visit(IdentifierExpr *E) {
+    return codegenExpr(IRGF.IRGM, E) != nullptr;
+  }
+  bool visit(ParenExpr *E) {
+    return codegenExpr(IRGF.IRGM, E) != nullptr;
+  }
+  bool visit(AssignExpr *E) {
+    return codegenExpr(IRGF.IRGM, E) != nullptr;
+  }
+  bool visit(InfixExpr *E) {
+    return codegenExpr(IRGF.IRGM, E) != nullptr;
+  }
+  bool visit(PrefixExpr *E) {
+    return codegenExpr(IRGF.IRGM, E) != nullptr;
+  }
+  bool visit(CallExpr *E) {
+    return codegenExpr(IRGF.IRGM, E) != nullptr;
+  }
+  bool visit(SubscriptExpr *E) {
+    return codegenExpr(IRGF.IRGM, E) != nullptr;
+  }
+};
+
+} // anonymous namespace
+
+bool irgen::genFunc(IRGenFunc &IRGF, FuncStmt *F) {
+  GenFunc GF(IRGF);
+  return GF.ASTVisitor::visit(F->getBody());
+}
+
diff --git a/lib/IRGen/GenFunc.h b/lib/IRGen/GenFunc.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e395c070de0b36892cdad9fb1d7ca95e0255510
--- /dev/null
+++ b/lib/IRGen/GenFunc.h
@@ -0,0 +1,43 @@
+//===--- GenFunc.h - Function generation state ------------------*- 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_GEN_FUNC_H
+#define DUSK_IRGEN_GEN_FUNC_H
+
+#include "dusk/Basic/LLVM.h"
+
+#include "Address.h"
+
+namespace llvm {
+  
+class Function;
+class FunctionType;
+class BasicBlock;
+
+} // namespace llvm
+
+namespace dusk {
+class Decl;
+class Stmt;
+class FuncDecl;
+class FuncStmt;
+class BlockStmt;
+class Type;
+class FunctionType;
+  
+namespace irgen {
+class IRGenFunc;
+  
+bool genFunc(IRGenFunc &IRGF, FuncStmt *F);
+  
+  
+} // namespace irgen
+} // namespace dusk
+
+#endif /* DUSK_IRGEN_GEN_FUNC_H */
diff --git a/lib/IRGen/GenModule.cpp b/lib/IRGen/GenModule.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..09af283d93c2cf4f4b891670c444a3afe76fe5b5
--- /dev/null
+++ b/lib/IRGen/GenModule.cpp
@@ -0,0 +1,93 @@
+//===--- GenModule.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 "GenModule.h"
+
+#include "dusk/AST/Decl.h"
+#include "dusk/AST/Expr.h"
+#include "dusk/AST/Stmt.h"
+#include "dusk/AST/ASTWalker.h"
+
+#include "IRGenModule.h"
+#include "IRGenFunc.h"
+#include "GenFunc.h"
+
+using namespace dusk;
+using namespace irgen;
+
+namespace {
+
+/// A simple AST walker, that declares all functions.
+class FuncDeclarator: public ASTWalker {
+  IRGenModule &IRGM;
+
+public:
+  FuncDeclarator(IRGenModule &IRGM) : IRGM(IRGM) {}
+  
+  // Skip all global declarations except function and module declarations
+  virtual bool preWalk(Decl *D) override {
+    if (dynamic_cast<FuncDecl *>(D) != nullptr)
+      return true;
+    if (dynamic_cast<ModuleDecl *>(D) != nullptr)
+      return true;
+    return false;
+  }
+  
+  // Skip all expressions
+  virtual bool preWalk(Expr *E) override { return false; }
+  
+  virtual bool preWalk(Stmt *S) override {
+    // Skip all statements except function declarations
+    if (dynamic_cast<FuncStmt *>(S) != nullptr)
+      return true;
+    if (dynamic_cast<ExternStmt *>(S) != nullptr)
+      return true;
+    return false;
+  }
+  
+  // Actually declare given function
+  virtual bool postWalk(Decl *D) override {
+    auto Fn = static_cast<FuncDecl *>(D);
+    assert(IRGM.declareFunc(Fn) != nullptr && "Redefinition of a function");
+    return true;
+  }
+};
+
+} // anonymous namespace
+
+
+static void decalreFunctions(IRGenModule &IRGM) {
+  FuncDeclarator FD(IRGM);
+  for (auto N : IRGM.Context.getRootModule()->getContents())
+    N->walk(FD);
+}
+
+void irgen::genModule(IRGenModule &IRGM) {
+  decalreFunctions(IRGM);
+  
+  for (auto N : IRGM.Context.getRootModule()->getContents()) {
+    if (auto D = dynamic_cast<ValDecl *>(N)) {
+      if (IRGM.declareVal(D) == nullptr)
+        llvm_unreachable("Redefinition of a value");
+    
+    } else if (auto Fn = dynamic_cast<FuncStmt *>(N)) {
+      IRGenFunc IRGF(IRGM, IRGM.Builder,
+                     IRGM.getFunc(Fn->getPrototype()->getName()), Fn);
+
+      if (!genFunc(IRGF, Fn))
+        llvm_unreachable("Error generating a function.");
+      
+    } else if (auto Fn = dynamic_cast<ExternStmt *>(N)) {
+      continue;
+      
+    } else {
+      llvm_unreachable("Unexpected top-level statement");
+    }
+  }
+}
diff --git a/lib/IRGen/GenModule.h b/lib/IRGen/GenModule.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba42b68e25e882dee77431537d194434a7da878c
--- /dev/null
+++ b/lib/IRGen/GenModule.h
@@ -0,0 +1,22 @@
+//===--- GenModule.h - Dusk IR generation for module ------------*- 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_GEN_MODULE_H
+#define DUSK_IRGEN_GEN_MODULE_H
+
+namespace dusk {
+namespace irgen {
+class IRGenModule;
+  
+void genModule(IRGenModule &IRGM);
+  
+} // namesapce irgen
+} // namespace dusk
+
+#endif /* DUSK_IRGEN_GEN_MODULE_H */
diff --git a/lib/IRGen/GenStmt.cpp b/lib/IRGen/GenStmt.cpp
deleted file mode 100644
index 4b0170a1f1f8acbc1d0259aca3f81a3fb3c98bbe..0000000000000000000000000000000000000000
--- a/lib/IRGen/GenStmt.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-//===--- GenStmt.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 "GenStmt.h"
-#include "GenDecl.h"
-#include "GenExpr.h"
-
-using namespace dusk;
-using namespace irgen;
-
-// MARK: - Break statement
-
-bool irgen::codegenStmt(Context &Ctx, Scope &Scp, BreakStmt *S) {
-  auto Ret = Ctx.getRange(Scp.getBreakParent());
-  Ctx.Builder.CreateBr(Ret.End);
-  return true;
-}
-
-// MARK: - Return statement
-
-bool irgen::codegenStmt(Context &Ctx, Scope &Scp, ReturnStmt *S) {
-  if (S->hasValue())
-    Ctx.Builder.CreateRet(codegenExpr(Ctx, S->getValue()));
-  else
-    Ctx.Builder.CreateRetVoid();
-  return true;
-}
-
-// MARK: - Block statement
-
-bool irgen::codegenStmt(Context &Ctx, Scope &Scp, BlockStmt *S) {
-  for (auto N : S->getNodes()) {
-    if (auto D = dynamic_cast<Decl *>(N))
-      if (!codegenDecl(Ctx, D))
-        return false;
-    
-    if (auto E = dynamic_cast<Expr *>(N))
-      if (codegenExpr(Ctx, E) == nullptr)
-        return false;
-    
-    if (auto S = dynamic_cast<Stmt *>(N))
-      if (!codegenStmt(Ctx, Scp, S))
-        return false;
-  }
-  return true;
-}
-
-// MARK: - Func statement
-
-void genArgs(Context &Ctx, VarPattern *P, llvm::Function *F) {
-  for (auto Arg : P->getVars())
-    if (!Ctx.declareVal(Arg, F))
-      llvm_unreachable("Redefinition of arg");
-  for (auto &Arg : F->args())
-    Ctx.Builder.CreateStore(&Arg, Ctx.getVal(Arg.getName()));
-}
-
-bool irgen::codegenStmt(Context &Ctx, Scope &Scp, FuncStmt *S) {
-  auto Scp_ = Scope(&Scp, Scope::FnScope);
-  auto F = Ctx.getFunc(S->getPrototype()->getName());
-  auto Args = static_cast<FuncDecl *>(S->getPrototype())->getArgs();
-  
-  // Create entry block for the function
-  auto BB = llvm::BasicBlock::Create(Ctx, "entry", F);
-  Ctx.Builder.SetInsertPoint(BB);
-  Ctx.push();
-  genArgs(Ctx, Args, F);
-  codegenStmt(Ctx, Scp_, S->getBody());
-  Ctx.pop();
-  return true;
-}
-
-// MARK: - If statement
-
-llvm::Value *condGen(Context &Ctx, Expr *E) {
-  auto CondV = codegenExpr(Ctx, E);
-  auto Zero = llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), 0);
-  return Ctx.Builder.CreateICmpNE(CondV, Zero, "cmpZero");
-}
-
-bool genBranch(Context &Ctx, Scope &Scp, llvm::BasicBlock *BB, Stmt *S) {
-  Ctx.Builder.SetInsertPoint(BB);
-  Ctx.push();
-   codegenStmt(Ctx, Scp, S);
-  Ctx.pop();
-  return true;
-}
-
-bool irgen::codegenStmt(Context &Ctx, Scope &Scp, IfStmt *S) {
-  auto Scp_ = Scope(&Scp, Scope::ControlScope);
-  auto Cond = condGen(Ctx, S->getCond());
-  auto F = Ctx.Builder.GetInsertBlock()->getParent();
-  auto ThenBB = llvm::BasicBlock::Create(Ctx, "then", F);
-  auto ElseBB = llvm::BasicBlock::Create(Ctx, "else");
-  auto MergeBB = llvm::BasicBlock::Create(Ctx, "endif");
-  F->getBasicBlockList().push_back(ElseBB);
-  F->getBasicBlockList().push_back(MergeBB);
-  
-  Ctx.Builder.CreateCondBr(Cond, ThenBB, ElseBB);
-  genBranch(Ctx, Scp_, ThenBB, S->getThen());
-  Ctx.Builder.CreateBr(MergeBB);
-  if (S->hasElseBlock())
-    genBranch(Ctx, Scp_, ElseBB, S->getElse());
-  Ctx.Builder.CreateBr(MergeBB);
-  Ctx.Builder.SetInsertPoint(MergeBB);
-  return true;
-}
-
-// MARK: - While statement
-
-bool irgen::codegenStmt(Context &Ctx, Scope &Scp, WhileStmt *S) {
-  return false;
-}
-
-// MARK: - For statement
-
-bool irgen::codegenStmt(Context &Ctx, Scope &Scp, ForStmt *S) {
-  return false;
-}
-
-// MARK: - Default statement
-
-bool irgen::codegenStmt(Context &Ctx, Scope &Scp, Stmt *S) {
-  switch (S->getKind()) {
-    case StmtKind::Break:
-      return codegenStmt(Ctx, Scp, static_cast<BreakStmt *>(S));
-    case StmtKind::Return:
-      return codegenStmt(Ctx, Scp, static_cast<ReturnStmt *>(S));
-    case StmtKind::Range:
-      return codegenStmt(Ctx, Scp, static_cast<RangeStmt *>(S));
-    case StmtKind::Block:
-      return codegenStmt(Ctx, Scp, static_cast<BlockStmt *>(S));
-    case StmtKind::Func:
-      return codegenStmt(Ctx, Scp, static_cast<FuncStmt *>(S));
-    case StmtKind::For:
-      return codegenStmt(Ctx, Scp, static_cast<ForStmt *>(S));
-    case StmtKind::While:
-      return codegenStmt(Ctx, Scp, static_cast<WhileStmt *>(S));
-    case StmtKind::If:
-      return codegenStmt(Ctx, Scp, static_cast<IfStmt *>(S));
-    case StmtKind::Extern:
-      return true;
-    case StmtKind::Subscript:
-      llvm_unreachable("Not implemented yet");
-  }
-}
-
diff --git a/lib/IRGen/GenStmt.h b/lib/IRGen/GenStmt.h
deleted file mode 100644
index dcd07beb8256463d63c2231a49fba4ce6dae437c..0000000000000000000000000000000000000000
--- a/lib/IRGen/GenStmt.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//===--- GenStmt.h - Dusk IR statement generation ---------------*- 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_STMT_H
-#define DUSK_IRGEN_STMT_H
-
-#include "dusk/AST/Decl.h"
-#include "dusk/AST/Expr.h"
-#include "dusk/AST/Stmt.h"
-#include "dusk/AST/Pattern.h"
-#include "dusk/IRGen/Context.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Value.h"
-#include "llvm/IR/LLVMContext.h"
-
-
-namespace dusk {
-
-namespace irgen {
-
-bool codegenStmt(Context &Ctx, Scope &Scp, Stmt *S);
-bool codegenStmt(Context &Ctx, Scope &Scp, BreakStmt *S);
-bool codegenStmt(Context &Ctx, Scope &Scp, ReturnStmt *S);
-bool codegenStmt(Context &Ctx, Scope &Scp, BlockStmt *S);
-bool codegenStmt(Context &Ctx, Scope &Scp, IfStmt *S);
-bool codegenStmt(Context &Ctx, Scope &Scp, WhileStmt *S);
-bool codegenStmt(Context &Ctx, Scope &Scp, ForStmt *S);
-bool codegenStmt(Context &Ctx, Scope &Scp, FuncStmt *S);
-bool codegenStmt(Context &Ctx, Scope &Scp, ExternStmt *S);
-  
-  
-} // namespace irgen
-
-} // namespace dusk
-
-#endif /* DUSK_IRGEN_STMT_H */
-
diff --git a/lib/IRGen/IRGenFunc.cpp b/lib/IRGen/IRGenFunc.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..feb43e9e3708ae170d4afffb8df853da49350914
--- /dev/null
+++ b/lib/IRGen/IRGenFunc.cpp
@@ -0,0 +1,103 @@
+//===--- IRGenFunc.h - IR generation state for functions --------*- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IRGenFunc.h"
+
+#include "dusk/AST/Decl.h"
+#include "dusk/AST/Expr.h"
+#include "dusk/AST/Stmt.h"
+#include "dusk/AST/Pattern.h"
+#include "dusk/AST/Type.h"
+#include "dusk/AST/Decl.h"
+#include "dusk/AST/NameLookup.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Type.h"
+
+#include "GenExpr.h"
+#include <vector>
+
+using namespace dusk;
+using namespace irgen;
+
+IRGenFunc::IRGenFunc(IRGenModule &IRGM, llvm::IRBuilder<> &B,
+                     llvm::Function *F, FuncStmt *FN)
+    : IRGM(IRGM), Builder(B), Fn(F) {
+
+  Proto = static_cast<FuncDecl *>(FN->getPrototype());
+  HeaderBlock =
+      llvm::BasicBlock::Create(IRGM.LLVMContext, Fn->getName() + ".header", Fn);
+  BodyBlock =
+      llvm::BasicBlock::Create(IRGM.LLVMContext, Fn->getName() + ".body");
+  RetBlock = llvm::BasicBlock::Create(IRGM.LLVMContext, Fn->getName() + ".ret");
+  emitHeader();
+  Fn->getBasicBlockList().push_back(BodyBlock);
+  Builder.SetInsertPoint(BodyBlock);
+}
+
+IRGenFunc::~IRGenFunc() {
+  emitRet();
+}
+
+void IRGenFunc::emitHeader() {
+  IRGM.Lookup.push();
+  Builder.SetInsertPoint(HeaderBlock);
+  // Create a return value if necessary
+  if (!Fn->getReturnType()->isVoidTy())
+    RetValue = Builder.CreateAlloca(llvm::Type::getInt64Ty(IRGM.LLVMContext));
+  
+  unsigned idx = 0;
+  auto Args = Proto->getArgs()->getVars();
+  for (auto &Arg : Fn->args()) {
+    if (auto Addr = declare(Args[idx]))
+      Builder.CreateStore(&Arg, Addr);
+    else
+      llvm_unreachable("Redefinition of declaration");
+  }
+  Builder.CreateBr(BodyBlock);
+}
+
+void IRGenFunc::emitRet() {
+  for (auto &BB : Fn->getBasicBlockList()) {
+    if (BB.size() == 0) {
+      Builder.SetInsertPoint(&BB);
+      if (auto Succ = BB.getSingleSuccessor())
+        Builder.CreateBr(Succ);
+      else
+        Builder.CreateBr(RetBlock);
+    }
+  }
+  
+  Fn->getBasicBlockList().push_back(RetBlock);
+  Builder.SetInsertPoint(RetBlock);
+  if (RetValue.isValid()) {
+    auto Val = Builder.CreateLoad(RetValue);
+    Builder.CreateRet(Val);
+  } else {
+    Builder.CreateRetVoid();
+  }
+  IRGM.Lookup.pop();
+}
+
+void IRGenFunc::setRetVal(llvm::Value *V) {
+  Builder.CreateStore(V, RetValue);
+}
+
+Address IRGenFunc::declare(Decl *N) {
+  return IRGM.declareVal(N);
+}
+
+Address IRGenFunc::getVal(StringRef N) {
+  return IRGM.getVal(N);
+}
+
+llvm::Function *IRGenFunc::getFunc(StringRef N) {
+  return IRGM.getFunc(N);
+}
diff --git a/lib/IRGen/IRGenFunc.h b/lib/IRGen/IRGenFunc.h
new file mode 100644
index 0000000000000000000000000000000000000000..6382813a782ac778713fbe1d97829154210cd6e4
--- /dev/null
+++ b/lib/IRGen/IRGenFunc.h
@@ -0,0 +1,101 @@
+//===--- IRGenFunc.h - IR generation state for functions --------*- 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_FUNC_H
+#define DUSK_IRGEN_IRGEN_FUNC_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/IR/Value.h"
+#include "llvm/IR/IRBuilder.h"
+
+#include "Address.h"
+#include "IRGenModule.h"
+#include "LoopInfo.h"
+
+#include <stack>
+
+namespace llvm {
+class StringRef;
+class Function;
+class BasicBlock;
+class Value;
+}
+
+namespace dusk {
+class Decl;
+class FuncDecl;
+class FuncStmt;
+  
+namespace irgen {
+  
+class IRGenFunc {
+public:
+  /// Module which part is this function of.
+  IRGenModule &IRGM;
+  
+  /// Current IR builder
+  llvm::IRBuilder<> &Builder;
+  
+  /// Actual function.
+  llvm::Function *Fn;
+  
+  /// Function statement.
+  FuncDecl *Proto;
+
+  /// Loop stack encapsulation.
+  LoopInfoStack LoopStack;
+
+  IRGenFunc(IRGenModule &IRGM, llvm::IRBuilder<> &B, llvm::Function *Fn,
+            FuncStmt *F);
+
+  ~IRGenFunc();
+  
+  friend class Scope;
+private:
+  /// A block, where all function initialization happen. E.g. parameter
+  /// allocation and initialization.
+  llvm::BasicBlock *HeaderBlock;
+  
+  /// Main function body block.
+  llvm::BasicBlock *BodyBlock;
+  
+  /// A common return block.
+  llvm::BasicBlock *RetBlock;
+  
+  /// A temporary alloca, that holds a return value.
+  ///
+  /// \node This address is invalid if the function does not return a value.
+  Address RetValue;
+  
+public:
+  /// Returns function's header block
+  llvm::BasicBlock *getHeaderBlock() const { return HeaderBlock; }
+  /// Returns function's body block
+  llvm::BasicBlock *getBodyBlock() const { return BodyBlock; }
+  /// Returns function's return block
+  llvm::BasicBlock *getRetBlock() const { return RetBlock; }
+  
+  void setRetVal(llvm::Value *V);
+  Address declare(Decl *N);
+  Address getVal(StringRef N);
+  llvm::Function *getFunc(StringRef N);
+  
+private:
+  /// Emits function header block.
+  void emitHeader();
+  
+  /// Return function return block
+  void emitRet();
+};
+  
+} // namespace irgen
+} // namespace dusk
+
+#endif /* DUSK_IRGEN_IRGEN_FUNC_H */
+
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8de023c9869f0d36bfb7ada69e0d3d7acb9949cd
--- /dev/null
+++ b/lib/IRGen/IRGenModule.cpp
@@ -0,0 +1,80 @@
+//===--- IRGenModule.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 "IRGenModule.h"
+
+#include "dusk/AST/Decl.h"
+#include "dusk/AST/Type.h"
+#include "dusk/AST/ASTContext.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include <vector>
+
+using namespace dusk;
+using namespace irgen;
+
+IRGenModule::IRGenModule(ASTContext &Ctx, llvm::LLVMContext &LLVMCtx,
+                         llvm::Module *M, llvm::IRBuilder<> &B)
+    : Context(Ctx), LLVMContext(LLVMCtx), Module(M), Builder(B) {}
+
+Address IRGenModule::declareVal(Decl *D) {
+  auto Ty = llvm::Type::getInt64Ty(LLVMContext);
+  
+  if (Lookup.getDepth() == 0) {
+    if (Module->getGlobalVariable(D->getName()) != nullptr)
+      llvm_unreachable("Redefinition of a variable");
+    
+    return Module->getOrInsertGlobal(D->getName(), Ty);
+  } else {
+    Lookup.declareVar(D);
+    auto Addr = Builder.CreateAlloca(Ty);
+    Vals[D] = Addr;
+    return Addr;
+  }
+}
+
+Address IRGenModule::declareFunc(FuncDecl *D) {
+  if (Lookup.contains(D->getName()))
+    llvm_unreachable("Redefinition of a function");
+
+  auto FnTy = static_cast<FunctionType *>(D->getType());
+  auto Ty = llvm::Type::getInt64Ty(LLVMContext);
+  auto Args = std::vector<llvm::Type *>(D->getArgs()->count(), Ty);
+
+  // Resolve return type
+  llvm::Type *RetTy;
+  switch (FnTy->getRetType()->getKind()) {
+  case TypeKind::Int:
+    RetTy = llvm::Type::getInt64Ty(LLVMContext);
+    break;
+  case TypeKind::Void:
+    RetTy = llvm::Type::getVoidTy(LLVMContext);
+    break;
+  default:
+    llvm_unreachable("Unsupported return type");
+  }
+  auto Proto = llvm::FunctionType::get(RetTy, Args, false);
+  auto Fn = llvm::Function::Create(Proto, llvm::Function::ExternalLinkage,
+                                   D->getName(), Module);
+  Lookup.declareFunc(D);
+  return Fn;
+}
+
+Address IRGenModule::getVal(StringRef N) {
+  if (auto Val = Vals[Lookup.getVal(N)])
+    return Val;
+  return Module->getGlobalVariable(N);
+}
+
+llvm::Function *IRGenModule::getFunc(StringRef N) {
+  return Module->getFunction(N);
+}
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
new file mode 100644
index 0000000000000000000000000000000000000000..a11ec7ee71c565e07a12aacd704281e814ef637e
--- /dev/null
+++ b/lib/IRGen/IRGenModule.h
@@ -0,0 +1,65 @@
+//===--- IRGenModule.h - Module generation state ----------------*- 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_MODULE_H
+#define DUSK_IRGEN_IRGEN_MODULE_H
+
+#include "dusk/Basic/LLVM.h"
+#include "dusk/AST/NameLookup.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/IRBuilder.h"
+
+#include "Address.h"
+
+namespace llvm {
+class Constant;
+class Module;
+class Value;
+class Function;
+class LLVMContext;
+class StringRef;
+}
+
+namespace dusk {
+class Decl;
+class FuncDecl;
+class ASTContext;
+  
+namespace irgen {
+  
+/// Main class for IR emittion of global declarations.
+class IRGenModule {
+public:
+  ASTContext &Context;
+  llvm::LLVMContext &LLVMContext;
+  llvm::Module *Module;
+  llvm::IRBuilder<> &Builder;
+  
+  NameLookup Lookup;
+  llvm::DenseMap<Decl *, Address> Vals;
+
+  IRGenModule(ASTContext &Ctx, llvm::LLVMContext &LLVMCtx, llvm::Module *M,
+              llvm::IRBuilder<> &B);
+
+  /// Declares a global variable
+  Address declareVal(Decl *D);
+  /// Decalres a fuction.
+  Address declareFunc(FuncDecl *D);
+  
+  /// Returns value of declared variable.
+  Address getVal(StringRef N);
+  /// Returns declared function.
+  llvm::Function *getFunc(StringRef N);
+};
+  
+} // namespace irgen
+} // namespace dusk
+
+#endif /* DUSK_IRGEN_IRGEN_MODULE_H */
+
diff --git a/lib/IRGen/IRGenerator.cpp b/lib/IRGen/IRGenerator.cpp
index cc4b0df84475ddcd681c55eb40753efbf0334356..b47c26b0040b806fa10e9a8bb6d9ee9df8b279d1 100644
--- a/lib/IRGen/IRGenerator.cpp
+++ b/lib/IRGen/IRGenerator.cpp
@@ -9,54 +9,27 @@
 
 #include "dusk/AST/ASTVisitor.h"
 #include "dusk/AST/Scope.h"
+#include "dusk/AST/NameLookup.h"
 #include "dusk/IRGen/IRGenerator.h"
-#include "dusk/IRGen/Context.h"
 #include "llvm/IR/BasicBlock.h"
 
-#include "GenDecl.h"
 #include "GenExpr.h"
-#include "GenStmt.h"
+#include "IRGenModule.h"
+#include "GenModule.h"
 
 using namespace dusk;
 using namespace irgen;
 
 
 IRGenerator::IRGenerator(ASTContext &C, DiagnosticEngine &Diag)
-    : ASTCtx(C), Diag(Diag), Builder({Ctx}) {}
+    : Context(C), Diag(Diag), Builder({LLVMContext}) {}
 
 IRGenerator::~IRGenerator() {}
 
 llvm::Module *IRGenerator::perform() {
-  auto M = ASTCtx.getRootModule();
-  Module = std::make_unique<llvm::Module>(M->getName(), Ctx);
-  Context Ctx(this->Ctx, Module.get(), Builder);
-  Scope Scp;
-  declareFuncs(Ctx, M);
-  for (auto &N : M->getContents()) {
-    bool R = true;
-    if (auto D = dynamic_cast<Decl *>(N))
-      continue;
-    else if (auto E = dynamic_cast<Expr *>(N))
-      R = codegenExpr(Ctx, E) != nullptr;
-    else if (auto S = dynamic_cast<Stmt *>(N))
-      R = codegenStmt(Ctx, Scp, S);
-    else
-      llvm_unreachable("Unexpected node");
-
-    if (!R)
-      return nullptr;
-  }
+  auto M = Context.getRootModule();
+  Module = std::make_unique<llvm::Module>(M->getName(), LLVMContext);
+  IRGenModule IRGM(Context, LLVMContext, Module.get(), Builder);
+  genModule(IRGM);
   return Module.release();
 }
-
-bool IRGenerator::declareFuncs(Context &Ctx, ModuleDecl *M) {
-  for (auto N : M->getContents()) {
-    if (auto Fn = dynamic_cast<FuncStmt *>(N))
-      if (!codegenDecl(Ctx, Fn->getPrototype()))
-        return false;
-    if (auto Fn = dynamic_cast<ExternStmt *>(N))
-      if (!codegenDecl(Ctx, Fn->getPrototype()))
-        return false;
-  }
-  return true;
-}
diff --git a/lib/IRGen/LoopInfo.cpp b/lib/IRGen/LoopInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2df62cfb5df0aa358591e2bc80516d0d2d81c8c1
--- /dev/null
+++ b/lib/IRGen/LoopInfo.cpp
@@ -0,0 +1,38 @@
+//===---LoopInfo.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 "LoopInfo.h"
+
+#include "dusk/AST/Decl.h"
+#include "dusk/AST/Expr.h"
+#include "dusk/AST/Stmt.h"
+#include "dusk/AST/Pattern.h"
+#include "dusk/AST/Type.h"
+#include "llvm/IR/Value.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/BasicBlock.h"
+
+using namespace dusk;
+using namespace irgen;
+
+LoopInfo::LoopInfo() : Header(nullptr), EndBlock(nullptr) {}
+
+LoopInfo::LoopInfo(llvm::BasicBlock *H, llvm::BasicBlock *E)
+    : Header(H), EndBlock(E) {
+  assert(isValid() && "Constructing invalid loop info.");
+}
+
+void LoopInfoStack::push(llvm::BasicBlock *H, llvm::BasicBlock *E) {
+  Active.emplace(H, E);
+}
+
+void LoopInfoStack::pop() {
+  assert(Active.size() != 0 && "Cannot pop an empty stack.");
+  Active.pop();
+}
diff --git a/lib/IRGen/LoopInfo.h b/lib/IRGen/LoopInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..ad2c9f836925d47840c3a77d676ce946a56e4451
--- /dev/null
+++ b/lib/IRGen/LoopInfo.h
@@ -0,0 +1,82 @@
+//===--- LoopInfo.h - Loop information encapsulation ------------*- 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_GEN_CONTROL_H
+#define DUSK_IRGEN_GEN_CONTROL_H
+
+#include <stack>
+
+namespace llvm {
+  class BasicBlock;
+}
+
+namespace dusk {
+class Stmt;
+class IfStmt;
+class ForStmt;
+class WhileStmt;
+
+namespace irgen {
+class Context;
+
+/// A simple class, than encapsulates information about generated loops.
+class LoopInfo {
+  /// Loop header block used e.g. for condition and/or initial variable
+  /// allocations.
+  llvm::BasicBlock *Header;
+
+  /// Loop end block, used e.g. when break statement is encountered.
+  llvm::BasicBlock *EndBlock;
+
+public:
+  /// Creates an invalid loop info.
+  LoopInfo();
+
+  /// Creates a valid loop info.
+  LoopInfo(llvm::BasicBlock *H, llvm::BasicBlock *E);
+
+  /// Returns \c true if loop info is valid, \c false otherwise.
+  bool isValid() const { return Header != nullptr && EndBlock != nullptr; }
+
+  /// Returns loop header block.
+  llvm::BasicBlock *getHeader() const {
+    assert(isValid() && "Accessing invalid loop info");
+    return Header;
+  }
+
+  /// Returns loops end block.
+  llvm::BasicBlock *getEndBlock() const {
+    assert(isValid() && "Accessing invalid loop info");
+    return EndBlock;
+  }
+};
+
+/// Stack of loop information that are currently active.
+class LoopInfoStack {
+  /// Active loop information.
+  std::stack<LoopInfo> Active;
+
+public:
+  LoopInfoStack() = default;
+
+  /// Start a new loop.
+  void push(llvm::BasicBlock *H, llvm::BasicBlock *E);
+
+  /// End the top loop.
+  void pop();
+
+  /// Returns informatin about top level loop.
+  const LoopInfo &getInfo() const { return Active.top(); }
+};
+
+} // namespace irgen
+} // namesapce dusk
+
+#endif /* DUSK_IRGEN_GEN_CONTROL_H */
+
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 231e6e149310df27a6c09bd624d2d038f86cfe43..52ffd87b0d36699284dd06b2e332a0ed6afe62aa 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -1,5 +1,4 @@
 set(SOURCE
-    ${CMAKE_CURRENT_SOURCE_DIR}/Context.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Sema.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/TypeChecker.h
     ${CMAKE_CURRENT_SOURCE_DIR}/TypeChecker.cpp
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 7b93672ab6d824538dd570936cc2816c35f6dcf3..46b62e6ca6faef9e58bc37dabcc3fee8acaf4e6e 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -16,6 +16,7 @@
 #include "dusk/AST/Type.h"
 #include "dusk/AST/TypeRepr.h"
 #include "dusk/AST/Diagnostics.h"
+#include "dusk/AST/NameLookup.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/SmallVector.h"
 
@@ -28,11 +29,11 @@ namespace {
 
 class FwdDeclarator : public ASTWalker {
   Sema &S;
-  Context &Ctx;
+  NameLookup &Ctx;
   DiagnosticEngine &Diag;
 
 public:
-  FwdDeclarator(Sema &S, Context &C, DiagnosticEngine &D)
+  FwdDeclarator(Sema &S, NameLookup &C, DiagnosticEngine &D)
       : S(S), Ctx(C), Diag(D) {}
 
   virtual bool preWalk(Decl *D) override {
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index f96a16b56af263cd9eea2f709c8dbe9d99c90fbb..ada84599127d2ab92b87a1685271be02b65c7331 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -11,8 +11,8 @@
 
 #include "dusk/AST/Diagnostics.h"
 #include "dusk/AST/Scope.h"
+#include "dusk/AST/NameLookup.h"
 #include "dusk/Sema/Sema.h"
-#include "dusk/Sema/Context.h"
 
 using namespace dusk;
 using namespace sema;
diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp
index 4af883981b9772a80d9adfa5f1cd7675a44a656c..636d8a9424f120b95f38f98d0e46dac28bef12c0 100644
--- a/lib/Sema/TypeCheckExpr.cpp
+++ b/lib/Sema/TypeCheckExpr.cpp
@@ -10,7 +10,7 @@
 #include "TypeChecker.h"
 
 #include "dusk/AST/Diagnostics.h"
-#include "dusk/Sema/Context.h"
+#include "dusk/AST/NameLookup.h"
 
 using namespace dusk;
 using namespace sema;
diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp
index 31f153502348d24589ab4a21b8fd641922136cb1..d0a5a726cccecb669baf3ce82c79b8b52c9d8adf 100644
--- a/lib/Sema/TypeCheckPattern.cpp
+++ b/lib/Sema/TypeCheckPattern.cpp
@@ -11,8 +11,8 @@
 
 #include "dusk/AST/Diagnostics.h"
 #include "dusk/AST/Scope.h"
+#include "dusk/AST/NameLookup.h"
 #include "dusk/Sema/Sema.h"
-#include "dusk/Sema/Context.h"
 #include "llvm/ADT/SmallVector.h"
 #include <memory>
 
diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp
index d09737c3022d012b08d2b42ff45cef83a9924a26..37afedefdae43a6e971c9fa605244450369ebd99 100644
--- a/lib/Sema/TypeCheckStmt.cpp
+++ b/lib/Sema/TypeCheckStmt.cpp
@@ -11,7 +11,7 @@
 
 #include "dusk/AST/Diagnostics.h"
 #include "dusk/AST/Scope.h"
-#include "dusk/Sema/Context.h"
+#include "dusk/AST/NameLookup.h"
 
 using namespace dusk;
 using namespace sema;
diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp
index c3505ca48b18ac65931c8ce98dcb824203ac8c8b..fdb4763df1310f270d77252b6e30b90ddf324b6a 100644
--- a/lib/Sema/TypeChecker.cpp
+++ b/lib/Sema/TypeChecker.cpp
@@ -11,13 +11,13 @@
 
 #include "dusk/AST/Diagnostics.h"
 #include "dusk/AST/Scope.h"
+#include "dusk/AST/NameLookup.h"
 #include "dusk/Sema/Sema.h"
-#include "dusk/Sema/Context.h"
 
 using namespace dusk;
 using namespace sema;
 
-TypeChecker::TypeChecker(Sema &S, Context &C, ASTContext &Ctx,
+TypeChecker::TypeChecker(Sema &S, NameLookup &C, ASTContext &Ctx,
                          DiagnosticEngine &D)
     : S(S), DeclCtx(C), Ctx(Ctx), Diag(D) {
   Scp.push(Scope());
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index fd556e5e33796039444d8f60675b74e527b6567e..461d8def9eae021251538a3302fe41a2a4843fa3 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -24,14 +24,14 @@ class Type;
 class TypeRepr;
 class DiagnosticEngine;
 class Scope;
-  
+class NameLookup;
+
 namespace diag {
   enum DiagID : unsigned;
 }
   
 namespace sema {
 class Sema;
-class Context;
 
 /// Dusk language type checker.
 ///
@@ -39,13 +39,13 @@ class Context;
 /// while validating them.
 class TypeChecker : public ASTWalker {
   Sema &S;
-  Context &DeclCtx;
+  NameLookup &DeclCtx;
   ASTContext &Ctx;
   std::stack<Scope> Scp;
   DiagnosticEngine &Diag;
 
 public:
-  TypeChecker(Sema &S, Context &DC, ASTContext &Ctx, DiagnosticEngine &Diag);
+  TypeChecker(Sema &S, NameLookup &DC, ASTContext &Ctx, DiagnosticEngine &Diag);
 
   virtual bool preWalk(Decl *D) override;
   virtual bool postWalk(Decl *D) override;
diff --git a/test.cpp b/test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b28d983623a6b4fd63a8af654e1830150e01a7fb
--- /dev/null
+++ b/test.cpp
@@ -0,0 +1,30 @@
+#include <iostream>
+
+extern "C" {
+    int64_t inc(int64_t);
+    void isEven(int64_t);
+}
+
+#ifdef _WIN32
+#define DLLEXPORT __declspec(dllexport)
+#else
+#define DLLEXPORT
+#endif
+
+/// printd - printf that takes an integer prints it as "%lld\n", returning Void.
+extern "C" DLLEXPORT void println(int64_t X) {
+  std::cout << "being called externally " << X << std::endl;
+//   fprintf(stderr, "%lld\n", X);
+  return;
+}
+
+int main() {
+    int64_t i = 10000;
+    int64_t j = 5;
+    // std::cout << i << " " << inc(i) << std::endl;
+    // isEven(i);
+    isEven(j);
+    // std::cout << i << " is even "; isEven(i); std::cout << std::endl;
+    // std::cout << j << " is even "; isEven(j); std::cout << std::endl;
+    return 0;
+}