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