| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "AST.h" |
| |
| #include "FunctionDeclaration.h" |
| #include "EnumVarDeclaration.h" |
| #include "Scope.h" |
| #include "Declaration.h" |
| #include "CompositeDeclaration.h" |
| #include "VarDeclaration.h" |
| #include "Define.h" |
| #include "Include.h" |
| #include "Note.h" |
| |
| #include <string> |
| #include <algorithm> |
| #include <stdlib.h> |
| #include <sys/dir.h> |
| #include <sys/stat.h> |
| |
| namespace android { |
| |
| AST::AST(const std::string &path, |
| const std::string &outputDir, |
| const std::string &package, |
| bool isOpenGl) |
| : mScanner(NULL), |
| mPath(path), |
| mOutputDir(outputDir), |
| mPackage(package), |
| mIsOpenGl(isOpenGl) |
| {} |
| |
| AST::~AST() { |
| delete mExpression; |
| |
| if(mDeclarations != NULL) { |
| for(auto* decl : *mDeclarations) { |
| delete decl; |
| } |
| } |
| delete mDeclarations; |
| |
| if(mInterfaces != NULL) { |
| for(auto* inter : *mInterfaces) { |
| delete inter; |
| } |
| } |
| delete mInterfaces; |
| |
| if(mIncludes != NULL) { |
| for(auto* incl : *mIncludes) { |
| delete incl; |
| } |
| } |
| delete mIncludes; |
| } |
| |
| void *AST::scanner() { |
| return mScanner; |
| } |
| |
| void AST::setScanner(void *scanner) { |
| mScanner = scanner; |
| } |
| |
| bool AST::isOpenGl() const { |
| return mIsOpenGl; |
| } |
| |
| const std::string& AST::getFilename() const { |
| return mPath; |
| } |
| |
| void AST::setDeclarations(std::vector<Declaration *> *declarations) { |
| // on the top level, no var declarations are allowed. |
| for(size_t i = 0; i < declarations->size(); i++) { |
| if(declarations->at(i)->decType() == VarDeclaration::type()) { |
| declarations->at(i) = new Note(declarations->at(i)); |
| } |
| } |
| |
| mDeclarations = declarations; |
| } |
| |
| void AST::setIncludes(std::vector<Include *> *includes) { |
| mIncludes = includes; |
| } |
| |
| Expression *AST::getExpression() const { |
| return mExpression; |
| } |
| void AST::setExpression(Expression *expression) { |
| mExpression = expression; |
| } |
| |
| const Scope<Define *> &AST::getDefinesScope() const { |
| return mDefinesScope; |
| } |
| |
| Scope<Define *> &AST::getDefinesScope() { |
| return mDefinesScope; |
| } |
| |
| void AST::processContents() { |
| CHECK(mDeclarations != NULL); |
| |
| for (auto &declaration : *mDeclarations) { |
| CHECK(declaration != NULL); |
| |
| declaration->processContents(*this); |
| } |
| |
| isolateInterfaces(); |
| isolateGlobalInterface(); |
| isolateIncludes(); |
| |
| isolateConstants(Expression::Type::U64); |
| isolateConstants(Expression::Type::S64); |
| isolateConstants(Expression::Type::U32); |
| isolateConstants(Expression::Type::S32); |
| } |
| |
| /* take interface-like structs out of the type file */ |
| void AST::isolateInterfaces() { |
| mInterfaces = new std::vector<CompositeDeclaration*>; |
| |
| auto it = mDeclarations->begin(); |
| while (it != mDeclarations->end()) { |
| if ((*it)->decType() == CompositeDeclaration::type() |
| && ((CompositeDeclaration *) (*it))->isInterface()) { |
| |
| mInterfaces->push_back((CompositeDeclaration *) *it); |
| it = mDeclarations->erase(it); |
| } else { |
| it++; |
| } |
| } |
| } |
| |
| /* take global function declarations out of the type file and into a new |
| * interface |
| */ |
| void AST::isolateGlobalInterface() { |
| auto globalFuns = new std::vector<Declaration*>; |
| |
| auto it = mDeclarations->begin(); |
| while (it != mDeclarations->end()) { |
| if ((*it)->decType() == FunctionDeclaration::type()) { |
| |
| globalFuns->push_back(*it); |
| it = mDeclarations->erase(it); |
| } else { |
| it++; |
| } |
| } |
| |
| if (!globalFuns->empty()) { |
| std::string path = mPackage.substr(0, mPackage.find_first_of('@')); |
| std::string name = path.substr(path.find_last_of('.') + 1); |
| |
| auto interface = new CompositeDeclaration( |
| Type::Qualifier::STRUCT, |
| name + "_global_t", |
| globalFuns); |
| |
| mInterfaces->push_back(interface); |
| } |
| } |
| |
| void AST::isolateIncludes() { |
| mIncludes = new std::vector<Include*>; |
| |
| auto it = mDeclarations->begin(); |
| while (it != mDeclarations->end()) { |
| if ((*it)->decType() == Include::type()) { |
| |
| mIncludes->push_back((Include *) *it); |
| it = mDeclarations->erase(it); |
| } else { |
| it++; |
| } |
| } |
| } |
| |
| void AST::isolateConstants(Expression::Type ofType) { |
| auto constants = new std::vector<Declaration*>; |
| |
| auto it = mDeclarations->begin(); |
| while (it != mDeclarations->end()) { |
| if ((*it)->decType() == Define::type() && |
| ((Define *)*it)->getExpressionType() == ofType) { |
| |
| Define* define = (Define *)*it; |
| |
| auto var = new EnumVarDeclaration(define->getName(), |
| define->getExpression()); |
| |
| define->setExpression(NULL); |
| |
| constants->push_back(var); |
| it = mDeclarations->erase(it); |
| |
| delete define; |
| } else { |
| it++; |
| } |
| } |
| |
| if (!constants->empty()) { |
| auto constEnum = new CompositeDeclaration( |
| Type::Qualifier::ENUM, |
| "Const" + Expression::getTypeDescription(ofType), |
| constants); |
| |
| constEnum->setEnumTypeName(Expression::getTypeName(ofType)); |
| |
| mDeclarations->insert(mDeclarations->begin(), constEnum); |
| } |
| } |
| |
| status_t AST::generateCode() const { |
| CHECK(mDeclarations != NULL); |
| |
| status_t err; |
| |
| for (auto &interface : *mInterfaces) { |
| err = generateFile(interface); |
| |
| if (err != OK) { |
| return err; |
| } |
| } |
| |
| err = generateTypesFile(); |
| |
| if (err != OK) { |
| return err; |
| } |
| |
| return OK; |
| } |
| |
| status_t AST::generateFile(CompositeDeclaration* declaration) const { |
| std::string fileName = declaration->getInterfaceName() + ".hal"; |
| |
| FILE *file = fopen((getFileDir() + fileName).c_str(), "w"); |
| |
| if(file == NULL) { |
| return -errno; |
| } |
| |
| Formatter out(file); // formatter closes out |
| |
| generatePackageLine(out); |
| generateIncludes(out); |
| |
| declaration->generateInterface(out); |
| |
| return OK; |
| } |
| |
| status_t AST::generateTypesFile() const { |
| if (mDeclarations->empty()) { |
| return OK; |
| } |
| |
| FILE *file = fopen((getFileDir() + "types.hal").c_str(), "w"); |
| |
| if(file == NULL) { |
| return -errno; |
| } |
| |
| Formatter out(file); // formatter closes out |
| |
| generatePackageLine(out); |
| generateIncludes(out); |
| |
| for (auto &declaration : *mDeclarations) { |
| declaration->generateCommentText(out); |
| declaration->generateSource(out); |
| out << "\n"; |
| } |
| |
| return OK; |
| } |
| |
| void AST::generateIncludes(Formatter &out) const { |
| for (auto &include : *mIncludes) { |
| include->generateSource(out); |
| out << "\n"; |
| } |
| } |
| |
| void AST::generatePackageLine(Formatter &out) const { |
| out << "package " |
| << mPackage |
| << ";\n\n"; |
| } |
| |
| bool MakeParentHierarchy(const std::string &path) { |
| static const mode_t kMode = 0755; |
| |
| size_t start = 1; // Ignore leading '/' |
| size_t slashPos; |
| while ((slashPos = path.find('/', start)) != std::string::npos) { |
| std::string partial = path.substr(0, slashPos); |
| |
| struct stat st; |
| if (stat(partial.c_str(), &st) < 0) { |
| if (errno != ENOENT) { |
| return false; |
| } |
| |
| int res = mkdir(partial.c_str(), kMode); |
| if (res < 0) { |
| return false; |
| } |
| } else if (!S_ISDIR(st.st_mode)) { |
| return false; |
| } |
| |
| start = slashPos + 1; |
| } |
| |
| return true; |
| } |
| |
| const std::string AST::getFileDir() const { |
| CHECK(MakeParentHierarchy(mOutputDir)); |
| return mOutputDir; |
| } |
| |
| } // namespace android |