blob: eb4c9dd868e43af42d0ae1eaaa7671b0498f6228 [file] [log] [blame]
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001/*
2 * Copyright (C) 2015 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 <iostream>
18#include <sstream>
19
20#include "Generator.h"
21#include "Specification.h"
22#include "Utilities.h"
23
24using namespace std;
25
26// Convert a file name into a string that can be used to guard the include file with #ifdef...
27static string makeGuardString(const string& filename) {
28 string s;
29 s.resize(15 + filename.size());
30 s = "RENDERSCRIPT_";
31 for (char c : filename) {
32 if (c == '.') {
33 s += '_';
34 } else {
35 s += toupper(c);
36 }
37 }
38 return s;
39}
40
41// Write #ifdef's that ensure that the specified version is present
42static void writeVersionGuardStart(GeneratedFile* file, VersionInfo info) {
43 if (info.intSize == 32) {
44 *file << "#ifndef __LP64__\n";
45 } else if (info.intSize == 64) {
46 *file << "#ifdef __LP64__\n";
47 }
48
49 if (info.minVersion <= 1) {
50 // No minimum
51 if (info.maxVersion > 0) {
52 *file << "#if !defined(RS_VERSION) || (RS_VERSION <= " << info.maxVersion << ")\n";
53 }
54 } else {
55 if (info.maxVersion == 0) {
56 // No maximum
57 *file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << info.minVersion << "))\n";
58 } else {
59 *file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << info.minVersion
60 << ") && (RS_VERSION <= " << info.maxVersion << "))\n";
61 }
62 }
63}
64
65static void writeVersionGuardEnd(GeneratedFile* file, VersionInfo info) {
66 if (info.minVersion > 1 || info.maxVersion != 0) {
67 *file << "#endif\n";
68 }
69 if (info.intSize != 0) {
70 *file << "#endif\n";
71 }
72}
73
74static void writeComment(GeneratedFile* file, const string& name, const string& briefComment,
75 const vector<string>& comment, bool closeBlock) {
76 if (briefComment.empty() && comment.size() == 0) {
77 return;
78 }
79 *file << "/*\n";
80 if (!briefComment.empty()) {
81 *file << " * " << name << ": " << briefComment << "\n";
82 *file << " *\n";
83 }
84 for (size_t ct = 0; ct < comment.size(); ct++) {
85 string s = stripHtml(comment[ct]);
86 s = stringReplace(s, "@", "");
87 if (!s.empty()) {
88 *file << " * " << s << "\n";
89 } else {
90 *file << " *\n";
91 }
92 }
93 if (closeBlock) {
94 *file << " */\n";
95 }
96}
97
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -070098static void writeConstantComment(GeneratedFile* file, const Constant& constant) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070099 const string name = constant.getName();
100 writeComment(file, name, constant.getSummary(), constant.getDescription(), true);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700101}
102
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700103static void writeConstantSpecification(GeneratedFile* file, const ConstantSpecification& spec) {
104 VersionInfo info = spec.getVersionInfo();
105 writeVersionGuardStart(file, info);
106 *file << "#define " << spec.getConstant()->getName() << " " << spec.getValue() << "\n\n";
107 writeVersionGuardEnd(file, info);
108}
109
110static void writeTypeSpecification(GeneratedFile* file, const TypeSpecification& spec) {
111 const string& typeName = spec.getType()->getName();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700112 const VersionInfo info = spec.getVersionInfo();
113 writeVersionGuardStart(file, info);
114 switch (spec.getKind()) {
115 case SIMPLE:
116 *file << "typedef " << spec.getSimpleType() << " " << typeName << ";\n";
117 break;
118 case ENUM: {
119 *file << "typedef enum ";
120 const string name = spec.getEnumName();
121 if (!name.empty()) {
122 *file << name << " ";
123 }
124 *file << "{\n";
125
126 const vector<string>& values = spec.getValues();
127 const vector<string>& valueComments = spec.getValueComments();
128 const size_t last = values.size() - 1;
129 for (size_t i = 0; i <= last; i++) {
130 *file << " " << values[i];
131 if (i != last) {
132 *file << ",";
133 }
134 if (valueComments.size() > i && !valueComments[i].empty()) {
135 *file << " // " << valueComments[i];
136 }
137 *file << "\n";
138 }
139 *file << "} " << typeName << ";\n";
140 break;
141 }
142 case STRUCT: {
143 *file << "typedef struct ";
144 const string name = spec.getStructName();
145 if (!name.empty()) {
146 *file << name << " ";
147 }
148 *file << "{\n";
149
150 const vector<string>& fields = spec.getFields();
151 const vector<string>& fieldComments = spec.getFieldComments();
152 for (size_t i = 0; i < fields.size(); i++) {
153 *file << " " << fields[i] << ";";
154 if (fieldComments.size() > i && !fieldComments[i].empty()) {
155 *file << " // " << fieldComments[i];
156 }
157 *file << "\n";
158 }
159 *file << "} ";
160 const string attrib = spec.getAttrib();
161 if (!attrib.empty()) {
162 *file << attrib << " ";
163 }
164 *file << typeName << ";\n";
165 break;
166 }
167 }
168 writeVersionGuardEnd(file, info);
169 *file << "\n";
170}
171
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700172static void writeTypeComment(GeneratedFile* file, const Type& type) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700173 const string name = type.getName();
174 writeComment(file, name, type.getSummary(), type.getDescription(), true);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700175}
176
177static void writeFunctionPermutation(GeneratedFile* file, const FunctionSpecification& spec,
178 const FunctionPermutation& permutation) {
179 writeVersionGuardStart(file, spec.getVersionInfo());
180
181 // Write linkage info.
182 const auto inlineCodeLines = permutation.getInline();
183 if (inlineCodeLines.size() > 0) {
184 *file << "static inline ";
185 } else {
186 *file << "extern ";
187 }
188
189 // Write the return type.
190 auto ret = permutation.getReturn();
191 if (ret) {
192 *file << ret->rsType;
193 } else {
194 *file << "void";
195 }
196
197 // Write the attribute.
198 *file << " __attribute__((";
199 const string attrib = spec.getAttribute();
200 if (attrib.empty()) {
201 *file << "overloadable";
202 } else if (attrib[0] == '=') {
203 /* If starts with an equal, we don't automatically add overloadable.
204 * This is because of the error we made defining rsUnpackColor8888().
205 */
206 *file << attrib.substr(1);
207 } else {
208 *file << attrib << ", overloadable";
209 }
210 *file << "))\n";
211
212 // Write the function name.
213 *file << " " << permutation.getName() << "(";
214 const int offset = 4 + permutation.getName().size() + 1; // Size of above
215
216 // Write the arguments. We wrap on mulitple lines if a line gets too long.
217 int charsOnLine = offset;
218 bool hasGenerated = false;
219 for (auto p : permutation.getParams()) {
220 if (hasGenerated) {
221 *file << ",";
222 charsOnLine++;
223 }
224 ostringstream ps;
225 ps << p->rsType;
226 if (p->isOutParameter) {
227 ps << "*";
228 }
229 if (!p->specName.empty()) {
230 ps << " " << p->specName;
231 }
232 const string s = ps.str();
233 if (charsOnLine + s.size() >= 100) {
234 *file << "\n" << string(offset, ' ');
235 charsOnLine = offset;
236 } else if (hasGenerated) {
237 *file << " ";
238 charsOnLine++;
239 }
240 *file << s;
241 charsOnLine += s.size();
242 hasGenerated = true;
243 }
244 // In C, if no parameters, we need to output void, e.g. fn(void).
245 if (!hasGenerated) {
246 *file << "void";
247 }
248 *file << ")";
249
250 // Write the inline code, if any.
251 if (inlineCodeLines.size() > 0) {
252 *file << " {\n";
253 for (size_t ct = 0; ct < inlineCodeLines.size(); ct++) {
254 if (inlineCodeLines[ct].empty()) {
255 *file << "\n";
256 } else {
257 *file << " " << inlineCodeLines[ct] << "\n";
258 }
259 }
260 *file << "}\n";
261 } else {
262 *file << ";\n";
263 }
264
265 writeVersionGuardEnd(file, spec.getVersionInfo());
266 *file << "\n";
267}
268
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700269static void writeFunctionComment(GeneratedFile* file, const Function& function) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700270 // Write the generic documentation.
271 writeComment(file, function.getName(), function.getSummary(), function.getDescription(), false);
272
273 // Comment the parameters.
274 if (function.someParametersAreDocumented()) {
275 *file << " *\n";
276 *file << " * Parameters:\n";
277 for (auto p : function.getParameters()) {
278 if (!p->documentation.empty()) {
279 *file << " * " << p->name << " " << p->documentation << "\n";
280 }
281 }
282 }
283
284 // Comment the return type.
285 const string returnDoc = function.getReturnDocumentation();
286 if (!returnDoc.empty()) {
287 *file << " *\n";
288 *file << " * Returns: " << returnDoc << "\n";
289 }
290
291 *file << " */\n";
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700292}
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700293
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700294static void writeFunctionSpecification(GeneratedFile* file, const FunctionSpecification& spec) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700295 // Write all the variants.
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700296 for (auto permutation : spec.getPermutations()) {
297 writeFunctionPermutation(file, spec, *permutation);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700298 }
299}
300
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700301static bool writeHeaderFile(const string& directory, const SpecFile& specFile) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700302 const string headerFileName = specFile.getHeaderFileName();
303
304 // We generate one header file for each spec file.
305 GeneratedFile file;
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700306 if (!file.start(directory, headerFileName)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700307 return false;
308 }
309
310 // Write the comments that start the file.
311 file.writeNotices();
312 writeComment(&file, headerFileName, specFile.getBriefDescription(),
313 specFile.getFullDescription(), true);
314
315 // Write the ifndef that prevents the file from being included twice.
316 const string guard = makeGuardString(headerFileName);
317 file << "#ifndef " << guard << "\n";
318 file << "#define " << guard << "\n\n";
319
320 // Add lines that need to be put in "as is".
321 if (specFile.getVerbatimInclude().size() > 0) {
322 for (auto s : specFile.getVerbatimInclude()) {
323 file << s << "\n";
324 }
325 file << "\n";
326 }
327
328 /* Write the constants, types, and functions in the same order as
329 * encountered in the spec file.
330 */
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700331 set<Constant*> documentedConstants;
332 for (auto spec : specFile.getConstantSpecifications()) {
333 Constant* constant = spec->getConstant();
334 if (documentedConstants.find(constant) == documentedConstants.end()) {
335 documentedConstants.insert(constant);
336 writeConstantComment(&file, *constant);
337 }
338 writeConstantSpecification(&file, *spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700339 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700340 set<Type*> documentedTypes;
341 for (auto spec : specFile.getTypeSpecifications()) {
342 Type* type = spec->getType();
343 if (documentedTypes.find(type) == documentedTypes.end()) {
344 documentedTypes.insert(type);
345 writeTypeComment(&file, *type);
346 }
347 writeTypeSpecification(&file, *spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700348 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700349
350 set<Function*> documentedFunctions;
351 for (auto spec : specFile.getFunctionSpecifications()) {
352 Function* function = spec->getFunction();
353 if (documentedFunctions.find(function) == documentedFunctions.end()) {
354 documentedFunctions.insert(function);
355 writeFunctionComment(&file, *function);
356 }
357 writeFunctionSpecification(&file, *spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700358 }
359
360 file << "#endif // " << guard << "\n";
361 file.close();
362 return true;
363}
364
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700365bool GenerateHeaderFiles(const string& directory) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700366 bool success = true;
367 for (auto specFile : systemSpecification.getSpecFiles()) {
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700368 if (!writeHeaderFile(directory, *specFile)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700369 success = false;
370 }
371 }
372 return success;
373}