blob: 9f40d3d549f8dba1681cb7c690c4c08d3d1c995c [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
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -070041/* Write #ifdef's that ensure that the specified version is present. If we're at the final version,
42 * add a check on a flag that can be set for internal builds. This enables us to keep supporting
43 * old APIs in the runtime code.
44 */
Yang Ni12398d82015-09-18 14:57:07 -070045static void writeVersionGuardStart(GeneratedFile* file, VersionInfo info, unsigned int finalVersion) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070046 if (info.intSize == 32) {
47 *file << "#ifndef __LP64__\n";
48 } else if (info.intSize == 64) {
49 *file << "#ifdef __LP64__\n";
50 }
51
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -070052 ostringstream checkMaxVersion;
53 if (info.maxVersion > 0) {
54 checkMaxVersion << "(";
55 if (info.maxVersion == finalVersion) {
56 checkMaxVersion << "defined(RS_DECLARE_EXPIRED_APIS) || ";
57 }
58 checkMaxVersion << "RS_VERSION <= " << info.maxVersion << ")";
59 }
60
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070061 if (info.minVersion <= 1) {
62 // No minimum
63 if (info.maxVersion > 0) {
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -070064 *file << "#if !defined(RS_VERSION) || " << checkMaxVersion.str() << "\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070065 }
66 } else {
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -070067 *file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << info.minVersion << ")";
68 if (info.maxVersion > 0) {
69 *file << " && " << checkMaxVersion.str();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070070 }
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -070071 *file << ")\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070072 }
73}
74
75static void writeVersionGuardEnd(GeneratedFile* file, VersionInfo info) {
76 if (info.minVersion > 1 || info.maxVersion != 0) {
77 *file << "#endif\n";
78 }
79 if (info.intSize != 0) {
80 *file << "#endif\n";
81 }
82}
83
84static void writeComment(GeneratedFile* file, const string& name, const string& briefComment,
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -070085 const vector<string>& comment, bool addDeprecatedWarning,
86 bool closeBlock) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070087 if (briefComment.empty() && comment.size() == 0) {
88 return;
89 }
90 *file << "/*\n";
91 if (!briefComment.empty()) {
92 *file << " * " << name << ": " << briefComment << "\n";
93 *file << " *\n";
94 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -070095 if (addDeprecatedWarning) {
96 *file << " * DEPRECATED. Do not use.\n";
97 *file << " *\n";
98 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070099 for (size_t ct = 0; ct < comment.size(); ct++) {
100 string s = stripHtml(comment[ct]);
101 s = stringReplace(s, "@", "");
102 if (!s.empty()) {
103 *file << " * " << s << "\n";
104 } else {
105 *file << " *\n";
106 }
107 }
108 if (closeBlock) {
109 *file << " */\n";
110 }
111}
112
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700113static void writeConstantComment(GeneratedFile* file, const Constant& constant) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700114 const string name = constant.getName();
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700115 writeComment(file, name, constant.getSummary(), constant.getDescription(),
116 constant.deprecated(), true);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700117}
118
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700119static void writeConstantSpecification(GeneratedFile* file, const ConstantSpecification& spec) {
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700120 const Constant* constant = spec.getConstant();
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700121 VersionInfo info = spec.getVersionInfo();
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700122 writeVersionGuardStart(file, info, constant->getFinalVersion());
Verena Beckhamef0c4552016-02-19 18:54:43 +0000123
124 *file << "#if (defined(RS_VERSION) && (RS_VERSION >= UNRELEASED))\n";
125 *file << "extern const " << spec.getType() << " " << constant->getName() << ";\n";
126 *file << "#else\n";
127 *file << "#define " << constant->getName() << " " << spec.getValue() << "\n";
128 *file << "#endif\n\n";
129
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700130 writeVersionGuardEnd(file, info);
131}
132
133static void writeTypeSpecification(GeneratedFile* file, const TypeSpecification& spec) {
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700134 const Type* type = spec.getType();
135 const string& typeName = type->getName();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700136 const VersionInfo info = spec.getVersionInfo();
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700137 writeVersionGuardStart(file, info, type->getFinalVersion());
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700138
139 const string attribute =
140 makeAttributeTag(spec.getAttribute(), "", type->getDeprecatedApiLevel(),
141 type->getDeprecatedMessage());
142 *file << "typedef ";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700143 switch (spec.getKind()) {
144 case SIMPLE:
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700145 *file << spec.getSimpleType() << attribute;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700146 break;
Stephen Hinesca51c782015-08-25 23:43:34 -0700147 case RS_OBJECT:
148 *file << "struct " << typeName << " _RS_OBJECT_DECL" << attribute;
149 break;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700150 case ENUM: {
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700151 *file << "enum" << attribute << " ";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700152 const string name = spec.getEnumName();
153 if (!name.empty()) {
154 *file << name << " ";
155 }
156 *file << "{\n";
157
158 const vector<string>& values = spec.getValues();
159 const vector<string>& valueComments = spec.getValueComments();
160 const size_t last = values.size() - 1;
161 for (size_t i = 0; i <= last; i++) {
162 *file << " " << values[i];
163 if (i != last) {
164 *file << ",";
165 }
166 if (valueComments.size() > i && !valueComments[i].empty()) {
167 *file << " // " << valueComments[i];
168 }
169 *file << "\n";
170 }
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700171 *file << "}";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700172 break;
173 }
174 case STRUCT: {
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700175 *file << "struct" << attribute << " ";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700176 const string name = spec.getStructName();
177 if (!name.empty()) {
178 *file << name << " ";
179 }
180 *file << "{\n";
181
182 const vector<string>& fields = spec.getFields();
183 const vector<string>& fieldComments = spec.getFieldComments();
184 for (size_t i = 0; i < fields.size(); i++) {
185 *file << " " << fields[i] << ";";
186 if (fieldComments.size() > i && !fieldComments[i].empty()) {
187 *file << " // " << fieldComments[i];
188 }
189 *file << "\n";
190 }
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700191 *file << "}";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700192 break;
193 }
194 }
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700195 *file << " " << typeName << ";\n";
196
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700197 writeVersionGuardEnd(file, info);
198 *file << "\n";
199}
200
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700201static void writeTypeComment(GeneratedFile* file, const Type& type) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700202 const string name = type.getName();
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700203 writeComment(file, name, type.getSummary(), type.getDescription(), type.deprecated(), true);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700204}
205
206static void writeFunctionPermutation(GeneratedFile* file, const FunctionSpecification& spec,
207 const FunctionPermutation& permutation) {
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700208 Function* function = spec.getFunction();
209 writeVersionGuardStart(file, spec.getVersionInfo(), function->getFinalVersion());
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700210
211 // Write linkage info.
212 const auto inlineCodeLines = permutation.getInline();
213 if (inlineCodeLines.size() > 0) {
214 *file << "static inline ";
215 } else {
216 *file << "extern ";
217 }
218
219 // Write the return type.
220 auto ret = permutation.getReturn();
221 if (ret) {
222 *file << ret->rsType;
223 } else {
224 *file << "void";
225 }
226
Yang Ni12398d82015-09-18 14:57:07 -0700227 *file << makeAttributeTag(spec.getAttribute(), spec.isOverloadable() ? "overloadable" : "",
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700228 function->getDeprecatedApiLevel(), function->getDeprecatedMessage());
229 *file << "\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700230
231 // Write the function name.
232 *file << " " << permutation.getName() << "(";
233 const int offset = 4 + permutation.getName().size() + 1; // Size of above
234
235 // Write the arguments. We wrap on mulitple lines if a line gets too long.
236 int charsOnLine = offset;
237 bool hasGenerated = false;
238 for (auto p : permutation.getParams()) {
239 if (hasGenerated) {
240 *file << ",";
241 charsOnLine++;
242 }
243 ostringstream ps;
244 ps << p->rsType;
245 if (p->isOutParameter) {
246 ps << "*";
247 }
Yang Nifab69472015-11-10 15:41:03 -0800248 if (!p->specName.empty() && p->rsType != "...") {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700249 ps << " " << p->specName;
250 }
251 const string s = ps.str();
252 if (charsOnLine + s.size() >= 100) {
253 *file << "\n" << string(offset, ' ');
254 charsOnLine = offset;
255 } else if (hasGenerated) {
256 *file << " ";
257 charsOnLine++;
258 }
259 *file << s;
260 charsOnLine += s.size();
261 hasGenerated = true;
262 }
263 // In C, if no parameters, we need to output void, e.g. fn(void).
264 if (!hasGenerated) {
265 *file << "void";
266 }
267 *file << ")";
268
269 // Write the inline code, if any.
270 if (inlineCodeLines.size() > 0) {
271 *file << " {\n";
272 for (size_t ct = 0; ct < inlineCodeLines.size(); ct++) {
273 if (inlineCodeLines[ct].empty()) {
274 *file << "\n";
275 } else {
276 *file << " " << inlineCodeLines[ct] << "\n";
277 }
278 }
279 *file << "}\n";
280 } else {
281 *file << ";\n";
282 }
283
284 writeVersionGuardEnd(file, spec.getVersionInfo());
285 *file << "\n";
286}
287
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700288static void writeFunctionComment(GeneratedFile* file, const Function& function) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700289 // Write the generic documentation.
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700290 writeComment(file, function.getName(), function.getSummary(), function.getDescription(),
291 function.deprecated(), false);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700292
293 // Comment the parameters.
294 if (function.someParametersAreDocumented()) {
295 *file << " *\n";
296 *file << " * Parameters:\n";
297 for (auto p : function.getParameters()) {
298 if (!p->documentation.empty()) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700299 *file << " * " << p->name << ": " << p->documentation << "\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700300 }
301 }
302 }
303
304 // Comment the return type.
305 const string returnDoc = function.getReturnDocumentation();
306 if (!returnDoc.empty()) {
307 *file << " *\n";
308 *file << " * Returns: " << returnDoc << "\n";
309 }
310
311 *file << " */\n";
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700312}
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700313
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700314static void writeFunctionSpecification(GeneratedFile* file, const FunctionSpecification& spec) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700315 // Write all the variants.
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700316 for (auto permutation : spec.getPermutations()) {
317 writeFunctionPermutation(file, spec, *permutation);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700318 }
319}
320
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700321static bool writeHeaderFile(const string& directory, const SpecFile& specFile) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700322 const string headerFileName = specFile.getHeaderFileName();
323
324 // We generate one header file for each spec file.
325 GeneratedFile file;
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700326 if (!file.start(directory, headerFileName)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700327 return false;
328 }
329
330 // Write the comments that start the file.
331 file.writeNotices();
332 writeComment(&file, headerFileName, specFile.getBriefDescription(),
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700333 specFile.getFullDescription(), false, true);
334 file << "\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700335
336 // Write the ifndef that prevents the file from being included twice.
337 const string guard = makeGuardString(headerFileName);
338 file << "#ifndef " << guard << "\n";
339 file << "#define " << guard << "\n\n";
340
341 // Add lines that need to be put in "as is".
342 if (specFile.getVerbatimInclude().size() > 0) {
343 for (auto s : specFile.getVerbatimInclude()) {
344 file << s << "\n";
345 }
346 file << "\n";
347 }
348
349 /* Write the constants, types, and functions in the same order as
350 * encountered in the spec file.
351 */
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700352 set<Constant*> documentedConstants;
353 for (auto spec : specFile.getConstantSpecifications()) {
354 Constant* constant = spec->getConstant();
355 if (documentedConstants.find(constant) == documentedConstants.end()) {
356 documentedConstants.insert(constant);
357 writeConstantComment(&file, *constant);
358 }
359 writeConstantSpecification(&file, *spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700360 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700361 set<Type*> documentedTypes;
362 for (auto spec : specFile.getTypeSpecifications()) {
363 Type* type = spec->getType();
364 if (documentedTypes.find(type) == documentedTypes.end()) {
365 documentedTypes.insert(type);
366 writeTypeComment(&file, *type);
367 }
368 writeTypeSpecification(&file, *spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700369 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700370
371 set<Function*> documentedFunctions;
372 for (auto spec : specFile.getFunctionSpecifications()) {
Yang Ni12398d82015-09-18 14:57:07 -0700373 // Do not include internal APIs in the header files.
374 if (spec->isInternal()) {
375 continue;
376 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700377 Function* function = spec->getFunction();
378 if (documentedFunctions.find(function) == documentedFunctions.end()) {
379 documentedFunctions.insert(function);
380 writeFunctionComment(&file, *function);
381 }
382 writeFunctionSpecification(&file, *spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700383 }
384
385 file << "#endif // " << guard << "\n";
386 file.close();
387 return true;
388}
389
Jean-Luc Brouillet66fea242015-04-09 16:47:59 -0700390bool generateHeaderFiles(const string& directory) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700391 bool success = true;
392 for (auto specFile : systemSpecification.getSpecFiles()) {
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700393 if (!writeHeaderFile(directory, *specFile)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700394 success = false;
395 }
396 }
397 return success;
398}