Recursively parse imported .hal files and perform global type lookup.
diff --git a/AST.cpp b/AST.cpp
index 7610ba5..3a948c3 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -1,5 +1,6 @@
 #include "AST.h"
 
+#include "Coordinator.h"
 #include "Formatter.h"
 #include "FQName.h"
 #include "HandleType.h"
@@ -9,12 +10,11 @@
 #include <android-base/logging.h>
 #include <stdlib.h>
 
-extern void parseFile(android::AST *ast, const char *path);
-
 namespace android {
 
-AST::AST()
-    : mScanner(NULL),
+AST::AST(Coordinator *coordinator)
+    : mCoordinator(coordinator),
+      mScanner(NULL),
       mRootScope(new Scope("root")) {
     enterScope(mRootScope);
 }
@@ -27,14 +27,8 @@
     mRootScope = NULL;
 
     CHECK(mScanner == NULL);
-}
 
-// static
-AST *AST::Parse(const char *path) {
-    AST *ast = new AST;
-    parseFile(ast, path);
-
-    return ast;
+    // Ownership of "coordinator" was NOT transferred.
 }
 
 void *AST::scanner() {
@@ -58,13 +52,26 @@
     return true;
 }
 
-bool AST::addImport(const char * /* import */) {
-#if 0
-    CHECK(!importPath->empty());
+bool AST::addImport(const char *import) {
+    FQName fqName(import);
+    CHECK(fqName.isValid());
 
-    std::string leaf = importPath->itemAt(importPath->size() - 1);
-    scope()->addType(new RefType(leaf.c_str(), new HandleType));
-#endif
+    fqName.applyDefaults(mPackage.package(), mPackage.version());
+
+    LOG(INFO) << "importing " << fqName.debugString();
+    const std::string packagePath = Coordinator::GetPackagePath(fqName);
+
+    if (fqName.name().empty()) {
+        // TODO: Import the whole package.
+        CHECK(!"Should not be here");
+        return false;
+    }
+
+    std::string path = packagePath;
+    path.append(fqName.name());
+    path.append(".hal");
+
+    AST *importAST = mCoordinator->parse(path.c_str());
 
     return true;
 }
@@ -82,7 +89,7 @@
     return mScopePath.top();
 }
 
-Type *AST::lookupType(const char *name) {
+Type *AST::lookupType(const char *name) const {
     FQName fqName(name);
     CHECK(fqName.isValid());
 
@@ -105,9 +112,42 @@
 
     fqName.applyDefaults(mPackage.package(), mPackage.version());
 
-    LOG(INFO) << "lookupType now looking for " << fqName.debugString();
+    // LOG(INFO) << "lookupType now looking for " << fqName.debugString();
 
-    return NULL;
+    return mCoordinator->lookupType(fqName);
+}
+
+Type *AST::lookupTypeInternal(const std::string &namePath) const {
+    Scope *scope = mRootScope;
+
+    size_t startPos = 0;
+    for (;;) {
+        size_t dotPos = namePath.find('.', startPos);
+
+        std::string component;
+        if (dotPos == std::string::npos) {
+            component = namePath.substr(startPos);
+        } else {
+            component = namePath.substr(startPos, dotPos - startPos);
+        }
+
+        Type *type = scope->lookupType(component.c_str());
+
+        if (type == NULL) {
+            return NULL;
+        }
+
+        if (dotPos == std::string::npos) {
+            return type;
+        }
+
+        if (!type->isScope()) {
+            return NULL;
+        }
+
+        scope = static_cast<Scope *>(type);
+        startPos = dotPos + 1;
+    }
 }
 
 void AST::dump(Formatter &out) const {
diff --git a/AST.h b/AST.h
index 227d80c..f58bf7e 100644
--- a/AST.h
+++ b/AST.h
@@ -10,12 +10,13 @@
 
 namespace android {
 
+struct Coordinator;
 struct Formatter;
 struct Type;
 struct Scope;
 
 struct AST {
-    AST();
+    AST(Coordinator *coordinator);
     ~AST();
 
     static AST *Parse(const char *path);
@@ -30,11 +31,20 @@
     void *scanner();
     void setScanner(void *scanner);
 
-    Type *lookupType(const char *name);
+    // Look up a type by FQName, "pure" names, i.e. those without package
+    // or version are first looked up in the current scope chain.
+    // After that lookup proceeds to imports.
+    Type *lookupType(const char *name) const;
+
+    // Takes dot-separated path components to a type possibly inside this AST.
+    // Name resolution goes from root scope downwards, i.e. the path must be
+    // absolute.
+    Type *lookupTypeInternal(const std::string &namePath) const;
 
     void dump(Formatter &out) const;
 
 private:
+    Coordinator *mCoordinator;
     Vector<Scope *> mScopePath;
 
     void *mScanner;
diff --git a/Android.mk b/Android.mk
index bd73f65..ac3e3f4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -9,6 +9,7 @@
     ArrayType.cpp               \
     CompoundType.cpp            \
     Constant.cpp                \
+    Coordinator.cpp             \
     EnumType.cpp                \
     Formatter.cpp               \
     FQName.cpp                  \
diff --git a/Coordinator.cpp b/Coordinator.cpp
new file mode 100644
index 0000000..e8b4c83
--- /dev/null
+++ b/Coordinator.cpp
@@ -0,0 +1,111 @@
+#include "Coordinator.h"
+
+#include "AST.h"
+#include "RefType.h"
+
+#include <android-base/logging.h>
+
+extern void parseFile(android::AST *ast, const char *path);
+
+namespace android {
+
+Coordinator::Coordinator() {}
+Coordinator::~Coordinator() {}
+
+AST *Coordinator::parse(const char *path) {
+    ssize_t index = mCache.indexOfKey(path);
+    if (index >= 0) {
+        AST *ast = mCache.valueAt(index);
+
+        return ast;
+    }
+
+    mCache.add(path, NULL);
+
+    AST *ast = new AST(this);
+    parseFile(ast, path);
+
+    mCache.add(path, ast);
+
+    return ast;
+}
+
+// static
+std::string Coordinator::GetPackagePath(const FQName &fqName) {
+    CHECK(!fqName.package().empty());
+    CHECK(!fqName.version().empty());
+    const char *const kPrefix = "android.hardware.";
+    CHECK_EQ(fqName.package().find(kPrefix), 0u);
+
+    const std::string packageSuffix = fqName.package().substr(strlen(kPrefix));
+
+    std::string packagePath =
+        "/Volumes/Source/nyc-mr1-dev-lego/hardware/interfaces/";
+
+    size_t startPos = 0;
+    size_t dotPos;
+    while ((dotPos = packageSuffix.find('.', startPos)) != std::string::npos) {
+        packagePath.append(packageSuffix.substr(startPos, dotPos - startPos));
+        packagePath.append("/");
+
+        startPos = dotPos + 1;
+    }
+    CHECK_LT(startPos + 1, packageSuffix.length());
+    packagePath.append(packageSuffix.substr(startPos));
+    packagePath.append("/");
+
+    CHECK_EQ(fqName.version().find('@'), 0u);
+    packagePath.append(fqName.version().substr(1));
+    packagePath.append("/");
+
+    return packagePath;
+}
+
+Type *Coordinator::lookupType(const FQName &fqName) const {
+    // Fully qualified.
+    CHECK(!fqName.package().empty());
+    CHECK(!fqName.version().empty());
+    CHECK(!fqName.name().empty());
+
+    const std::string packagePath = GetPackagePath(fqName);
+
+    std::string topType;
+    size_t dotPos = fqName.name().find('.');
+    if (dotPos == std::string::npos) {
+        topType = fqName.name();
+    } else {
+        topType = fqName.name().substr(0, dotPos);
+    }
+
+    std::string path = packagePath;
+    path.append(topType);
+    path.append(".hal");
+
+    ssize_t index = mCache.indexOfKey(path);
+    if (index >= 0) {
+        AST *ast = mCache.valueAt(index);
+        Type *type = ast->lookupTypeInternal(fqName.name());
+
+        if (type != NULL) {
+            return new RefType(fqName.debugString().c_str(), type);
+        }
+    }
+
+    path = packagePath;
+    path.append("Types.hal");
+
+    index = mCache.indexOfKey(path);
+    if (index >= 0) {
+        AST *ast = mCache.valueAt(index);
+        Type *type = ast->lookupTypeInternal(fqName.name());
+
+        if (type != NULL) {
+            return new RefType(fqName.debugString().c_str(), type);
+        }
+    }
+
+    return NULL;
+}
+
+}  // namespace android
+
diff --git a/Coordinator.h b/Coordinator.h
new file mode 100644
index 0000000..54eaa7e
--- /dev/null
+++ b/Coordinator.h
@@ -0,0 +1,33 @@
+#ifndef COORDINATOR_H_
+
+#define COORDINATOR_H_
+
+#include <android-base/macros.h>
+#include <string>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+struct AST;
+struct FQName;
+struct Type;
+
+struct Coordinator {
+    Coordinator();
+    ~Coordinator();
+
+    AST *parse(const char *path);
+
+    Type *lookupType(const FQName &fqName) const;
+
+    static std::string GetPackagePath(const FQName &fqName);
+
+private:
+    KeyedVector<std::string, AST *> mCache;
+
+    DISALLOW_COPY_AND_ASSIGN(Coordinator);
+};
+
+}  // namespace android
+
+#endif  // COORDINATOR_H_
diff --git a/FQName.cpp b/FQName.cpp
index 5ad6a4b..0b241d6 100644
--- a/FQName.cpp
+++ b/FQName.cpp
@@ -87,7 +87,7 @@
 std::string FQName::debugString() const {
     CHECK(mValid);
 
-    std::string out = "FQName(";
+    std::string out;
     out.append(mPackage);
     out.append(mVersion);
     if (!mName.empty()) {
@@ -96,7 +96,6 @@
         }
         out.append(mName);
     }
-    out.append(")");
 
     return out;
 }
diff --git a/Scope.cpp b/Scope.cpp
index 73c6c83..b0b21fa 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -59,5 +59,9 @@
     }
 }
 
+bool Scope::isScope() const {
+    return true;
+}
+
 }  // namespace android
 
diff --git a/Scope.h b/Scope.h
index a7cf5ec..651bb83 100644
--- a/Scope.h
+++ b/Scope.h
@@ -20,6 +20,7 @@
     bool addConstant(Constant *constant);
 
     void dump(Formatter &out) const override;
+    bool isScope() const override;
 
 private:
     Vector<Type *> mTypes;
diff --git a/Type.cpp b/Type.cpp
index fd64343..5251f9d 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -5,5 +5,9 @@
 Type::Type() {}
 Type::~Type() {}
 
+bool Type::isScope() const {
+    return false;
+}
+
 }  // namespace android
 
diff --git a/Type.h b/Type.h
index 0fef750..edf669b 100644
--- a/Type.h
+++ b/Type.h
@@ -13,6 +13,7 @@
     virtual ~Type();
 
     virtual void dump(Formatter &out) const = 0;
+    virtual bool isScope() const;
 
 private:
     DISALLOW_COPY_AND_ASSIGN(Type);
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 6d1b286..c63448a 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -133,6 +133,10 @@
       {
           ast->addImport($3);
       }
+    | imports IMPORT IDENTIFIER ';'
+      {
+          ast->addImport($3);
+      }
     ;
 
 opt_extends
diff --git a/main.cpp b/main.cpp
index 770d97e..68240ae 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,5 +1,5 @@
 #include "AST.h"
-
+#include "Coordinator.h"
 #include "Formatter.h"
 #include "FQName.h"
 
@@ -8,8 +8,10 @@
 using namespace android;
 
 int main(int argc, const char *const argv[]) {
+    Coordinator coordinator;
+
     for (int i = 1; i < argc; ++i) {
-        AST *ast = AST::Parse(argv[i]);
+        AST *ast = coordinator.parse(argv[i]);
 
         Formatter out;