1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "AST.h"
18 
19 #include "FunctionDeclaration.h"
20 #include "EnumVarDeclaration.h"
21 #include "Scope.h"
22 #include "Declaration.h"
23 #include "CompositeDeclaration.h"
24 #include "VarDeclaration.h"
25 #include "Define.h"
26 #include "Include.h"
27 #include "Note.h"
28 
29 #include <string>
30 #include <algorithm>
31 #include <stdlib.h>
32 #include <sys/stat.h>
33 
34 namespace android {
35 
AST(const std::string & path,const std::string & outputDir,const std::string & package,bool isOpenGl)36 AST::AST(const std::string &path,
37          const std::string &outputDir,
38          const std::string &package,
39          bool isOpenGl)
40     : mScanner(nullptr),
41       mPath(path),
42       mOutputDir(outputDir),
43       mPackage(package),
44       mIsOpenGl(isOpenGl)
45     {}
46 
~AST()47 AST::~AST() {
48     delete mExpression;
49 
50     if(mDeclarations != nullptr) {
51         for(auto* decl : *mDeclarations) {
52             delete decl;
53         }
54     }
55     delete mDeclarations;
56 
57     if(mInterfaces != nullptr) {
58         for(auto* inter : *mInterfaces) {
59             delete inter;
60         }
61     }
62     delete mInterfaces;
63 
64     if(mIncludes != nullptr) {
65         for(auto* incl : *mIncludes) {
66             delete incl;
67         }
68     }
69     delete mIncludes;
70 }
71 
scanner()72 void *AST::scanner() {
73     return mScanner;
74 }
75 
setScanner(void * scanner)76 void AST::setScanner(void *scanner) {
77     mScanner = scanner;
78 }
79 
isOpenGl() const80 bool AST::isOpenGl() const {
81     return mIsOpenGl;
82 }
83 
getFilename() const84 const std::string& AST::getFilename() const {
85     return mPath;
86 }
87 
setDeclarations(std::vector<Declaration * > * declarations)88 void AST::setDeclarations(std::vector<Declaration *> *declarations) {
89     // on the top level, no var declarations are allowed.
90     for(size_t i = 0; i < declarations->size(); i++) {
91         if(declarations->at(i)->decType() == VarDeclaration::type()) {
92             declarations->at(i) = new Note(declarations->at(i));
93         }
94     }
95 
96     mDeclarations = declarations;
97 }
98 
setIncludes(std::vector<Include * > * includes)99 void AST::setIncludes(std::vector<Include *> *includes) {
100     mIncludes = includes;
101 }
102 
getExpression() const103 Expression *AST::getExpression() const {
104     return mExpression;
105 }
setExpression(Expression * expression)106 void AST::setExpression(Expression *expression) {
107     mExpression = expression;
108 }
109 
getDefinesScope() const110 const Scope<Define *> &AST::getDefinesScope() const {
111     return mDefinesScope;
112 }
113 
getDefinesScope()114 Scope<Define *> &AST::getDefinesScope() {
115     return mDefinesScope;
116 }
117 
processContents()118 void AST::processContents() {
119     CHECK(mDeclarations != nullptr);
120 
121     for (auto &declaration : *mDeclarations) {
122         CHECK(declaration != nullptr);
123 
124         declaration->processContents(*this);
125     }
126 
127     isolateInterfaces();
128     isolateGlobalInterface();
129     isolateIncludes();
130 
131     isolateConstants(Expression::Type::U64);
132     isolateConstants(Expression::Type::S64);
133     isolateConstants(Expression::Type::U32);
134     isolateConstants(Expression::Type::S32);
135 }
136 
137 /* take interface-like structs out of the type file */
isolateInterfaces()138 void AST::isolateInterfaces() {
139     mInterfaces = new std::vector<CompositeDeclaration*>;
140 
141     auto it = mDeclarations->begin();
142     while (it != mDeclarations->end()) {
143         if ((*it)->decType() == CompositeDeclaration::type()
144             && ((CompositeDeclaration *) (*it))->isInterface()) {
145 
146             mInterfaces->push_back((CompositeDeclaration *) *it);
147             it = mDeclarations->erase(it);
148         } else {
149             it++;
150         }
151     }
152 }
153 
154 /* take global function declarations out of the type file and into a new
155  * interface
156  */
isolateGlobalInterface()157 void AST::isolateGlobalInterface() {
158     auto globalFuns = new std::vector<Declaration*>;
159 
160     auto it = mDeclarations->begin();
161     while (it != mDeclarations->end()) {
162         if ((*it)->decType() == FunctionDeclaration::type()) {
163 
164             globalFuns->push_back(*it);
165             it = mDeclarations->erase(it);
166         } else {
167             it++;
168         }
169     }
170 
171     if (!globalFuns->empty()) {
172         std::string path = mPackage.substr(0, mPackage.find_first_of('@'));
173         std::string name = path.substr(path.find_last_of('.') + 1);
174 
175         auto interface = new CompositeDeclaration(
176             Type::Qualifier::STRUCT,
177             name + "_global_t",
178             globalFuns);
179 
180         mInterfaces->push_back(interface);
181     }
182 }
183 
isolateIncludes()184 void AST::isolateIncludes() {
185     mIncludes = new std::vector<Include*>;
186 
187     auto it = mDeclarations->begin();
188     while (it != mDeclarations->end()) {
189         if ((*it)->decType() == Include::type()) {
190 
191             mIncludes->push_back((Include *) *it);
192             it = mDeclarations->erase(it);
193         } else {
194             it++;
195         }
196     }
197 }
198 
isolateConstants(Expression::Type ofType)199 void AST::isolateConstants(Expression::Type ofType) {
200     auto constants = new std::vector<Declaration*>;
201 
202     auto it = mDeclarations->begin();
203     while (it != mDeclarations->end()) {
204         if ((*it)->decType() == Define::type() &&
205             ((Define *)*it)->getExpressionType() == ofType) {
206 
207             Define* define = (Define *)*it;
208 
209             auto var = new EnumVarDeclaration(define->getName(),
210                                               define->getExpression());
211 
212             define->setExpression(nullptr);
213 
214             constants->push_back(var);
215             it = mDeclarations->erase(it);
216 
217             delete define;
218         } else {
219             it++;
220         }
221     }
222 
223     if (!constants->empty()) {
224         auto constEnum = new CompositeDeclaration(
225             Type::Qualifier::ENUM,
226             "Const" + Expression::getTypeDescription(ofType),
227             constants);
228 
229         constEnum->setEnumTypeName(Expression::getTypeName(ofType));
230 
231         mDeclarations->insert(mDeclarations->begin(), constEnum);
232     }
233 }
234 
generateCode() const235 status_t AST::generateCode() const {
236     CHECK(mDeclarations != nullptr);
237 
238     status_t err;
239 
240     for (auto &interface : *mInterfaces) {
241         err = generateFile(interface);
242 
243         if (err != OK) {
244             return err;
245         }
246     }
247 
248     err = generateTypesFile();
249 
250     if (err != OK) {
251         return err;
252     }
253 
254     return OK;
255 }
256 
generateFile(CompositeDeclaration * declaration) const257 status_t AST::generateFile(CompositeDeclaration* declaration) const {
258     std::string fileName = declaration->getInterfaceName() + ".hal";
259 
260     FILE *file = fopen((getFileDir() + fileName).c_str(), "w");
261 
262     if(file == nullptr) {
263         return -errno;
264     }
265 
266     Formatter out(file); // formatter closes out
267 
268     generatePackageLine(out);
269     generateIncludes(out);
270 
271     declaration->generateInterface(out);
272 
273     return OK;
274 }
275 
generateTypesFile() const276 status_t AST::generateTypesFile() const {
277     if (mDeclarations->empty()) {
278         return OK;
279     }
280 
281     FILE *file = fopen((getFileDir() + "types.hal").c_str(), "w");
282 
283     if(file == nullptr) {
284         return -errno;
285     }
286 
287     Formatter out(file); // formatter closes out
288 
289     generatePackageLine(out);
290     generateIncludes(out);
291 
292     for (auto &declaration : *mDeclarations) {
293         declaration->generateCommentText(out);
294         declaration->generateSource(out);
295         out << "\n";
296     }
297 
298     return OK;
299 }
300 
generateIncludes(Formatter & out) const301 void AST::generateIncludes(Formatter &out) const {
302     for (auto &include : *mIncludes) {
303         include->generateSource(out);
304         out << "\n";
305     }
306 }
307 
generatePackageLine(Formatter & out) const308 void AST::generatePackageLine(Formatter &out) const {
309     out << "package "
310         << mPackage
311         << ";\n\n";
312 }
313 
MakeParentHierarchy(const std::string & path)314 bool MakeParentHierarchy(const std::string &path) {
315     static const mode_t kMode = 0755;
316 
317     size_t start = 1;  // Ignore leading '/'
318     size_t slashPos;
319     while ((slashPos = path.find('/', start)) != std::string::npos) {
320         std::string partial = path.substr(0, slashPos);
321 
322         struct stat st;
323         if (stat(partial.c_str(), &st) < 0) {
324             if (errno != ENOENT) {
325                 return false;
326             }
327 
328             int res = mkdir(partial.c_str(), kMode);
329             if (res < 0) {
330                 return false;
331             }
332         } else if (!S_ISDIR(st.st_mode)) {
333             return false;
334         }
335 
336         start = slashPos + 1;
337     }
338 
339     return true;
340 }
341 
getFileDir() const342 const std::string AST::getFileDir() const {
343     CHECK(MakeParentHierarchy(mOutputDir));
344     return mOutputDir;
345 }
346 
347 } // namespace android
348