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;