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