You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
348 lines
8.1 KiB
348 lines
8.1 KiB
/* |
|
* 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
|
|
|