blob: e32dc4c19e4f5c06f939b42edb72ceaec8a1ec0c [file] [log] [blame]
Andreas Huber5345ec22016-07-29 13:33:27 -07001#include "Coordinator.h"
2
3#include "AST.h"
Andreas Huber5345ec22016-07-29 13:33:27 -07004
5#include <android-base/logging.h>
6
Andreas Huber68f24592016-07-29 14:53:48 -07007extern android::status_t parseFile(android::AST *ast, const char *path);
Andreas Huber5345ec22016-07-29 13:33:27 -07008
9namespace android {
10
Andreas Huberdc981332016-07-29 15:46:54 -070011Coordinator::Coordinator(const std::string &interfacesPath)
12 : mInterfacesPath(interfacesPath) {
13}
14
Andreas Huber5345ec22016-07-29 13:33:27 -070015Coordinator::~Coordinator() {}
16
Andreas Huber68f24592016-07-29 14:53:48 -070017AST *Coordinator::parse(const FQName &fqName) {
18 CHECK(fqName.isFullyQualified());
19
Andreas Huber6e584b72016-07-29 16:14:07 -070020 // LOG(INFO) << "parsing " << fqName.string();
21
Andreas Huber68f24592016-07-29 14:53:48 -070022 ssize_t index = mCache.indexOfKey(fqName);
Andreas Huber5345ec22016-07-29 13:33:27 -070023 if (index >= 0) {
24 AST *ast = mCache.valueAt(index);
25
26 return ast;
27 }
28
Andreas Huber68f24592016-07-29 14:53:48 -070029 // Add this to the cache immediately, so we can discover circular imports.
30 mCache.add(fqName, NULL);
31
Andreas Huberdc981332016-07-29 15:46:54 -070032 const std::string packagePath = getPackagePath(fqName);
Andreas Huber68f24592016-07-29 14:53:48 -070033
34 if (fqName.name() != "types") {
35 // Any interface file implicitly imports its package's types.hal.
36 FQName typesName(fqName.package(), fqName.version(), "types");
37 (void)parse(typesName);
38
39 // fall through.
40 }
41
42 std::string path = packagePath;
43 path.append(fqName.name());
44 path.append(".hal");
Andreas Huber5345ec22016-07-29 13:33:27 -070045
46 AST *ast = new AST(this);
Andreas Huber68f24592016-07-29 14:53:48 -070047 status_t err = parseFile(ast, path.c_str());
Andreas Huber5345ec22016-07-29 13:33:27 -070048
Andreas Huber68f24592016-07-29 14:53:48 -070049 if (err != OK) {
Andreas Huber6e584b72016-07-29 16:14:07 -070050 // LOG(ERROR) << "parsing '" << path << "' FAILED.";
51
Andreas Huber68f24592016-07-29 14:53:48 -070052 delete ast;
53 ast = NULL;
54
55 return NULL;
56 }
57
Andreas Hubera2723d22016-07-29 15:36:07 -070058 if (ast->package().package() != fqName.package()
59 || ast->package().version() != fqName.version()) {
60 LOG(ERROR)
61 << "File at '" << path << "' does not match expected package "
62 << "and/or version.";
63
64 err = UNKNOWN_ERROR;
65 } else {
66 std::string ifaceName;
67 if (ast->isInterface(&ifaceName)) {
68 if (fqName.name() == "types") {
69 LOG(ERROR)
70 << "File at '" << path << "' declares an interface '"
71 << ifaceName
72 << "' instead of the expected types common to the package.";
73
74 err = UNKNOWN_ERROR;
75 } else if (ifaceName != fqName.name()) {
76 LOG(ERROR)
77 << "File at '" << path << "' does not declare interface type '"
78 << fqName.name()
79 << "'.";
80
81 err = UNKNOWN_ERROR;
82 }
83 } else if (fqName.name() != "types") {
84 LOG(ERROR)
85 << "File at '" << path << "' declares types rather than the "
86 << "expected interface type '" << fqName.name() << "'.";
87
88 err = UNKNOWN_ERROR;
89 }
90 }
91
92 if (err != OK) {
93 delete ast;
94 ast = NULL;
95
96 return NULL;
97 }
98
Andreas Huber68f24592016-07-29 14:53:48 -070099 mCache.add(fqName, ast);
Andreas Huber5345ec22016-07-29 13:33:27 -0700100
101 return ast;
102}
103
Andreas Huber881227d2016-08-02 14:20:21 -0700104std::string Coordinator::getPackagePath(
105 const FQName &fqName, bool relative) const {
Andreas Huber5345ec22016-07-29 13:33:27 -0700106 CHECK(!fqName.package().empty());
107 CHECK(!fqName.version().empty());
108 const char *const kPrefix = "android.hardware.";
109 CHECK_EQ(fqName.package().find(kPrefix), 0u);
110
111 const std::string packageSuffix = fqName.package().substr(strlen(kPrefix));
112
Andreas Huber881227d2016-08-02 14:20:21 -0700113 std::string packagePath;
114 if (!relative) {
115 packagePath = mInterfacesPath;
116 }
Andreas Huber5345ec22016-07-29 13:33:27 -0700117
118 size_t startPos = 0;
119 size_t dotPos;
120 while ((dotPos = packageSuffix.find('.', startPos)) != std::string::npos) {
121 packagePath.append(packageSuffix.substr(startPos, dotPos - startPos));
122 packagePath.append("/");
123
124 startPos = dotPos + 1;
125 }
126 CHECK_LT(startPos + 1, packageSuffix.length());
127 packagePath.append(packageSuffix.substr(startPos));
128 packagePath.append("/");
129
130 CHECK_EQ(fqName.version().find('@'), 0u);
131 packagePath.append(fqName.version().substr(1));
132 packagePath.append("/");
133
134 return packagePath;
135}
136
Andreas Huberfd4afab2016-08-03 13:02:57 -0700137Type *Coordinator::lookupType(const FQName &fqName) const {
Andreas Huber5345ec22016-07-29 13:33:27 -0700138 // Fully qualified.
Andreas Huber68f24592016-07-29 14:53:48 -0700139 CHECK(fqName.isFullyQualified());
Andreas Huber5345ec22016-07-29 13:33:27 -0700140
141 std::string topType;
142 size_t dotPos = fqName.name().find('.');
143 if (dotPos == std::string::npos) {
144 topType = fqName.name();
145 } else {
146 topType = fqName.name().substr(0, dotPos);
147 }
148
Andreas Huber68f24592016-07-29 14:53:48 -0700149 // Assuming {topType} is the name of an interface type, let's see if the
150 // associated {topType}.hal file was imported.
151 FQName ifaceName(fqName.package(), fqName.version(), topType);
152 ssize_t index = mCache.indexOfKey(ifaceName);
Andreas Huber5345ec22016-07-29 13:33:27 -0700153 if (index >= 0) {
154 AST *ast = mCache.valueAt(index);
Andreas Huber6e584b72016-07-29 16:14:07 -0700155 CHECK(ast != NULL);
156
Andreas Huber5345ec22016-07-29 13:33:27 -0700157 Type *type = ast->lookupTypeInternal(fqName.name());
158
159 if (type != NULL) {
Andreas Huberfd4afab2016-08-03 13:02:57 -0700160 return type->ref();
Andreas Huber5345ec22016-07-29 13:33:27 -0700161 }
162 }
163
Andreas Huber68f24592016-07-29 14:53:48 -0700164 FQName typesName(fqName.package(), fqName.version(), "types");
165 index = mCache.indexOfKey(typesName);
Andreas Huber5345ec22016-07-29 13:33:27 -0700166 if (index >= 0) {
167 AST *ast = mCache.valueAt(index);
Andreas Huber6e584b72016-07-29 16:14:07 -0700168 if (ast != NULL) {
169 // ast could be NULL if types.hal didn't exist, which is valid.
170 Type *type = ast->lookupTypeInternal(fqName.name());
Andreas Huber5345ec22016-07-29 13:33:27 -0700171
Andreas Huber6e584b72016-07-29 16:14:07 -0700172 if (type != NULL) {
Andreas Huberfd4afab2016-08-03 13:02:57 -0700173 return type->ref();
Andreas Huber6e584b72016-07-29 16:14:07 -0700174 }
Andreas Huber5345ec22016-07-29 13:33:27 -0700175 }
176 }
177
178 return NULL;
179}
180
Andreas Hubere61e3f72016-08-03 10:22:03 -0700181status_t Coordinator::forEachAST(for_each_cb cb) const {
182 for (size_t i = 0; i < mCache.size(); ++i) {
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700183 const AST *ast = mCache.valueAt(i);
184
185 if (!ast) {
186 // This could happen for an interface's "types.hal" AST.
187 continue;
188 }
189
190 status_t err = cb(ast);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700191
192 if (err != OK) {
193 return err;
194 }
195 }
196
197 return OK;
198}
199
Andreas Huber5345ec22016-07-29 13:33:27 -0700200} // namespace android
201