Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 1 | #include "Coordinator.h" |
| 2 | |
| 3 | #include "AST.h" |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 4 | |
| 5 | #include <android-base/logging.h> |
| 6 | |
Andreas Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 7 | extern android::status_t parseFile(android::AST *ast, const char *path); |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 8 | |
| 9 | namespace android { |
| 10 | |
Andreas Huber | dc98133 | 2016-07-29 15:46:54 -0700 | [diff] [blame] | 11 | Coordinator::Coordinator(const std::string &interfacesPath) |
| 12 | : mInterfacesPath(interfacesPath) { |
| 13 | } |
| 14 | |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 15 | Coordinator::~Coordinator() {} |
| 16 | |
Andreas Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 17 | AST *Coordinator::parse(const FQName &fqName) { |
| 18 | CHECK(fqName.isFullyQualified()); |
| 19 | |
Andreas Huber | 6e584b7 | 2016-07-29 16:14:07 -0700 | [diff] [blame] | 20 | // LOG(INFO) << "parsing " << fqName.string(); |
| 21 | |
Andreas Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 22 | ssize_t index = mCache.indexOfKey(fqName); |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 23 | if (index >= 0) { |
| 24 | AST *ast = mCache.valueAt(index); |
| 25 | |
| 26 | return ast; |
| 27 | } |
| 28 | |
Andreas Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 29 | // Add this to the cache immediately, so we can discover circular imports. |
| 30 | mCache.add(fqName, NULL); |
| 31 | |
Andreas Huber | dc98133 | 2016-07-29 15:46:54 -0700 | [diff] [blame] | 32 | const std::string packagePath = getPackagePath(fqName); |
Andreas Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 33 | |
| 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 Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 45 | |
| 46 | AST *ast = new AST(this); |
Andreas Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 47 | status_t err = parseFile(ast, path.c_str()); |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 48 | |
Andreas Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 49 | if (err != OK) { |
Andreas Huber | 6e584b7 | 2016-07-29 16:14:07 -0700 | [diff] [blame] | 50 | // LOG(ERROR) << "parsing '" << path << "' FAILED."; |
| 51 | |
Andreas Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 52 | delete ast; |
| 53 | ast = NULL; |
| 54 | |
| 55 | return NULL; |
| 56 | } |
| 57 | |
Andreas Huber | a2723d2 | 2016-07-29 15:36:07 -0700 | [diff] [blame] | 58 | 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 Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 99 | mCache.add(fqName, ast); |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 100 | |
| 101 | return ast; |
| 102 | } |
| 103 | |
Andreas Huber | 881227d | 2016-08-02 14:20:21 -0700 | [diff] [blame] | 104 | std::string Coordinator::getPackagePath( |
| 105 | const FQName &fqName, bool relative) const { |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 106 | 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 Huber | 881227d | 2016-08-02 14:20:21 -0700 | [diff] [blame] | 113 | std::string packagePath; |
| 114 | if (!relative) { |
| 115 | packagePath = mInterfacesPath; |
| 116 | } |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 117 | |
| 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 Huber | fd4afab | 2016-08-03 13:02:57 -0700 | [diff] [blame] | 137 | Type *Coordinator::lookupType(const FQName &fqName) const { |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 138 | // Fully qualified. |
Andreas Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 139 | CHECK(fqName.isFullyQualified()); |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 140 | |
| 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 Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 149 | // 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 Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 153 | if (index >= 0) { |
| 154 | AST *ast = mCache.valueAt(index); |
Andreas Huber | 6e584b7 | 2016-07-29 16:14:07 -0700 | [diff] [blame] | 155 | CHECK(ast != NULL); |
| 156 | |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 157 | Type *type = ast->lookupTypeInternal(fqName.name()); |
| 158 | |
| 159 | if (type != NULL) { |
Andreas Huber | fd4afab | 2016-08-03 13:02:57 -0700 | [diff] [blame] | 160 | return type->ref(); |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 161 | } |
| 162 | } |
| 163 | |
Andreas Huber | 68f2459 | 2016-07-29 14:53:48 -0700 | [diff] [blame] | 164 | FQName typesName(fqName.package(), fqName.version(), "types"); |
| 165 | index = mCache.indexOfKey(typesName); |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 166 | if (index >= 0) { |
| 167 | AST *ast = mCache.valueAt(index); |
Andreas Huber | 6e584b7 | 2016-07-29 16:14:07 -0700 | [diff] [blame] | 168 | 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 Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 171 | |
Andreas Huber | 6e584b7 | 2016-07-29 16:14:07 -0700 | [diff] [blame] | 172 | if (type != NULL) { |
Andreas Huber | fd4afab | 2016-08-03 13:02:57 -0700 | [diff] [blame] | 173 | return type->ref(); |
Andreas Huber | 6e584b7 | 2016-07-29 16:14:07 -0700 | [diff] [blame] | 174 | } |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 175 | } |
| 176 | } |
| 177 | |
| 178 | return NULL; |
| 179 | } |
| 180 | |
Andreas Huber | e61e3f7 | 2016-08-03 10:22:03 -0700 | [diff] [blame] | 181 | status_t Coordinator::forEachAST(for_each_cb cb) const { |
| 182 | for (size_t i = 0; i < mCache.size(); ++i) { |
Andreas Huber | 6cb08cf | 2016-08-03 15:44:51 -0700 | [diff] [blame^] | 183 | 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 Huber | e61e3f7 | 2016-08-03 10:22:03 -0700 | [diff] [blame] | 191 | |
| 192 | if (err != OK) { |
| 193 | return err; |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | return OK; |
| 198 | } |
| 199 | |
Andreas Huber | 5345ec2 | 2016-07-29 13:33:27 -0700 | [diff] [blame] | 200 | } // namespace android |
| 201 | |