summaryrefslogtreecommitdiff
path: root/api/GenerateHeaderFiles.cpp
diff options
context:
space:
mode:
authorJean-Luc Brouillet <jeanluc@google.com>2015-03-13 13:51:24 -0700
committerJean-Luc Brouillet <jeanluc@google.com>2015-03-20 16:12:58 -0700
commitc5184e202ced435258adb2cfe2013570e7190954 (patch)
treeb3a118cd59c469c616c12c6a0d1bb2f4483f2781 /api/GenerateHeaderFiles.cpp
parentd7d44133b0d94ea2a2e0a1378d78b5ed0a17da7e (diff)
downloadrs-c5184e202ced435258adb2cfe2013570e7190954.tar.gz
Generate all APIs.
This CL expands the generator to create all the .rsh files, not just the core_math one. To do so, processing of types (simple, struct, enums) and constants was added. .spec files corresponding to each .rsh file was created. Documentation was added. This CL also generates HTML documentation files. This generation will soon be upgraded. To make the code easier to expand, I've done fairly extensive refactoring. In a subsequent CL, the APIs will be regrouped in different header files to simplify learning the APIs. In an other, the documentation generation will be futher improved and incorporated in the actual online help. Also removes rs_path & related functions. Change-Id: I2c88554c9c6a8625233772b89e055fc6c4ad5da5
Diffstat (limited to 'api/GenerateHeaderFiles.cpp')
-rw-r--r--api/GenerateHeaderFiles.cpp360
1 files changed, 360 insertions, 0 deletions
diff --git a/api/GenerateHeaderFiles.cpp b/api/GenerateHeaderFiles.cpp
new file mode 100644
index 00000000..4b2ecc70
--- /dev/null
+++ b/api/GenerateHeaderFiles.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <sstream>
+
+#include "Generator.h"
+#include "Specification.h"
+#include "Utilities.h"
+
+using namespace std;
+
+// Convert a file name into a string that can be used to guard the include file with #ifdef...
+static string makeGuardString(const string& filename) {
+ string s;
+ s.resize(15 + filename.size());
+ s = "RENDERSCRIPT_";
+ for (char c : filename) {
+ if (c == '.') {
+ s += '_';
+ } else {
+ s += toupper(c);
+ }
+ }
+ return s;
+}
+
+// Write #ifdef's that ensure that the specified version is present
+static void writeVersionGuardStart(GeneratedFile* file, VersionInfo info) {
+ if (info.intSize == 32) {
+ *file << "#ifndef __LP64__\n";
+ } else if (info.intSize == 64) {
+ *file << "#ifdef __LP64__\n";
+ }
+
+ if (info.minVersion <= 1) {
+ // No minimum
+ if (info.maxVersion > 0) {
+ *file << "#if !defined(RS_VERSION) || (RS_VERSION <= " << info.maxVersion << ")\n";
+ }
+ } else {
+ if (info.maxVersion == 0) {
+ // No maximum
+ *file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << info.minVersion << "))\n";
+ } else {
+ *file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << info.minVersion
+ << ") && (RS_VERSION <= " << info.maxVersion << "))\n";
+ }
+ }
+}
+
+static void writeVersionGuardEnd(GeneratedFile* file, VersionInfo info) {
+ if (info.minVersion > 1 || info.maxVersion != 0) {
+ *file << "#endif\n";
+ }
+ if (info.intSize != 0) {
+ *file << "#endif\n";
+ }
+}
+
+static void writeComment(GeneratedFile* file, const string& name, const string& briefComment,
+ const vector<string>& comment, bool closeBlock) {
+ if (briefComment.empty() && comment.size() == 0) {
+ return;
+ }
+ *file << "/*\n";
+ if (!briefComment.empty()) {
+ *file << " * " << name << ": " << briefComment << "\n";
+ *file << " *\n";
+ }
+ for (size_t ct = 0; ct < comment.size(); ct++) {
+ string s = stripHtml(comment[ct]);
+ s = stringReplace(s, "@", "");
+ if (!s.empty()) {
+ *file << " * " << s << "\n";
+ } else {
+ *file << " *\n";
+ }
+ }
+ if (closeBlock) {
+ *file << " */\n";
+ }
+}
+
+static void writeConstant(GeneratedFile* file, const Constant& constant) {
+ const string name = constant.getName();
+ writeComment(file, name, constant.getSummary(), constant.getDescription(), true);
+
+ for (auto spec : constant.getSpecifications()) {
+ VersionInfo info = spec->getVersionInfo();
+ writeVersionGuardStart(file, info);
+ *file << "#define " << name << " " << spec->getValue() << "\n";
+ writeVersionGuardEnd(file, info);
+ }
+ *file << "\n";
+}
+
+static void writeTypeSpecification(GeneratedFile* file, const string& typeName,
+ const TypeSpecification& spec) {
+ const VersionInfo info = spec.getVersionInfo();
+ writeVersionGuardStart(file, info);
+ switch (spec.getKind()) {
+ case SIMPLE:
+ *file << "typedef " << spec.getSimpleType() << " " << typeName << ";\n";
+ break;
+ case ENUM: {
+ *file << "typedef enum ";
+ const string name = spec.getEnumName();
+ if (!name.empty()) {
+ *file << name << " ";
+ }
+ *file << "{\n";
+
+ const vector<string>& values = spec.getValues();
+ const vector<string>& valueComments = spec.getValueComments();
+ const size_t last = values.size() - 1;
+ for (size_t i = 0; i <= last; i++) {
+ *file << " " << values[i];
+ if (i != last) {
+ *file << ",";
+ }
+ if (valueComments.size() > i && !valueComments[i].empty()) {
+ *file << " // " << valueComments[i];
+ }
+ *file << "\n";
+ }
+ *file << "} " << typeName << ";\n";
+ break;
+ }
+ case STRUCT: {
+ *file << "typedef struct ";
+ const string name = spec.getStructName();
+ if (!name.empty()) {
+ *file << name << " ";
+ }
+ *file << "{\n";
+
+ const vector<string>& fields = spec.getFields();
+ const vector<string>& fieldComments = spec.getFieldComments();
+ for (size_t i = 0; i < fields.size(); i++) {
+ *file << " " << fields[i] << ";";
+ if (fieldComments.size() > i && !fieldComments[i].empty()) {
+ *file << " // " << fieldComments[i];
+ }
+ *file << "\n";
+ }
+ *file << "} ";
+ const string attrib = spec.getAttrib();
+ if (!attrib.empty()) {
+ *file << attrib << " ";
+ }
+ *file << typeName << ";\n";
+ break;
+ }
+ }
+ writeVersionGuardEnd(file, info);
+ *file << "\n";
+}
+
+static void writeType(GeneratedFile* file, const Type& type) {
+ const string name = type.getName();
+ writeComment(file, name, type.getSummary(), type.getDescription(), true);
+
+ for (auto spec : type.getSpecifications()) {
+ writeTypeSpecification(file, name, *spec);
+ }
+ *file << "\n";
+}
+
+static void writeFunctionPermutation(GeneratedFile* file, const FunctionSpecification& spec,
+ const FunctionPermutation& permutation) {
+ writeVersionGuardStart(file, spec.getVersionInfo());
+
+ // Write linkage info.
+ const auto inlineCodeLines = permutation.getInline();
+ if (inlineCodeLines.size() > 0) {
+ *file << "static inline ";
+ } else {
+ *file << "extern ";
+ }
+
+ // Write the return type.
+ auto ret = permutation.getReturn();
+ if (ret) {
+ *file << ret->rsType;
+ } else {
+ *file << "void";
+ }
+
+ // Write the attribute.
+ *file << " __attribute__((";
+ const string attrib = spec.getAttribute();
+ if (attrib.empty()) {
+ *file << "overloadable";
+ } else if (attrib[0] == '=') {
+ /* If starts with an equal, we don't automatically add overloadable.
+ * This is because of the error we made defining rsUnpackColor8888().
+ */
+ *file << attrib.substr(1);
+ } else {
+ *file << attrib << ", overloadable";
+ }
+ *file << "))\n";
+
+ // Write the function name.
+ *file << " " << permutation.getName() << "(";
+ const int offset = 4 + permutation.getName().size() + 1; // Size of above
+
+ // Write the arguments. We wrap on mulitple lines if a line gets too long.
+ int charsOnLine = offset;
+ bool hasGenerated = false;
+ for (auto p : permutation.getParams()) {
+ if (hasGenerated) {
+ *file << ",";
+ charsOnLine++;
+ }
+ ostringstream ps;
+ ps << p->rsType;
+ if (p->isOutParameter) {
+ ps << "*";
+ }
+ if (!p->specName.empty()) {
+ ps << " " << p->specName;
+ }
+ const string s = ps.str();
+ if (charsOnLine + s.size() >= 100) {
+ *file << "\n" << string(offset, ' ');
+ charsOnLine = offset;
+ } else if (hasGenerated) {
+ *file << " ";
+ charsOnLine++;
+ }
+ *file << s;
+ charsOnLine += s.size();
+ hasGenerated = true;
+ }
+ // In C, if no parameters, we need to output void, e.g. fn(void).
+ if (!hasGenerated) {
+ *file << "void";
+ }
+ *file << ")";
+
+ // Write the inline code, if any.
+ if (inlineCodeLines.size() > 0) {
+ *file << " {\n";
+ for (size_t ct = 0; ct < inlineCodeLines.size(); ct++) {
+ if (inlineCodeLines[ct].empty()) {
+ *file << "\n";
+ } else {
+ *file << " " << inlineCodeLines[ct] << "\n";
+ }
+ }
+ *file << "}\n";
+ } else {
+ *file << ";\n";
+ }
+
+ writeVersionGuardEnd(file, spec.getVersionInfo());
+ *file << "\n";
+}
+
+static void writeFunction(GeneratedFile* file, const Function& function) {
+ // Write the generic documentation.
+ writeComment(file, function.getName(), function.getSummary(), function.getDescription(), false);
+
+ // Comment the parameters.
+ if (function.someParametersAreDocumented()) {
+ *file << " *\n";
+ *file << " * Parameters:\n";
+ for (auto p : function.getParameters()) {
+ if (!p->documentation.empty()) {
+ *file << " * " << p->name << " " << p->documentation << "\n";
+ }
+ }
+ }
+
+ // Comment the return type.
+ const string returnDoc = function.getReturnDocumentation();
+ if (!returnDoc.empty()) {
+ *file << " *\n";
+ *file << " * Returns: " << returnDoc << "\n";
+ }
+
+ *file << " */\n";
+
+ // Write all the variants.
+ for (auto spec : function.getSpecifications()) {
+ for (auto permutation : spec->getPermutations()) {
+ writeFunctionPermutation(file, *spec, *permutation);
+ }
+ }
+}
+
+static bool writeHeaderFile(const SpecFile& specFile) {
+ const string headerFileName = specFile.getHeaderFileName();
+
+ // We generate one header file for each spec file.
+ GeneratedFile file;
+ if (!file.start(headerFileName)) {
+ return false;
+ }
+
+ // Write the comments that start the file.
+ file.writeNotices();
+ writeComment(&file, headerFileName, specFile.getBriefDescription(),
+ specFile.getFullDescription(), true);
+
+ // Write the ifndef that prevents the file from being included twice.
+ const string guard = makeGuardString(headerFileName);
+ file << "#ifndef " << guard << "\n";
+ file << "#define " << guard << "\n\n";
+
+ // Add lines that need to be put in "as is".
+ if (specFile.getVerbatimInclude().size() > 0) {
+ for (auto s : specFile.getVerbatimInclude()) {
+ file << s << "\n";
+ }
+ file << "\n";
+ }
+
+ /* Write the constants, types, and functions in the same order as
+ * encountered in the spec file.
+ */
+ for (auto iter : specFile.getConstantsList()) {
+ writeConstant(&file, *iter);
+ }
+ for (auto iter : specFile.getTypesList()) {
+ writeType(&file, *iter);
+ }
+ for (auto iter : specFile.getFunctionsList()) {
+ writeFunction(&file, *iter);
+ }
+
+ file << "#endif // " << guard << "\n";
+ file.close();
+ return true;
+}
+
+bool GenerateHeaderFiles() {
+ bool success = true;
+ for (auto specFile : systemSpecification.getSpecFiles()) {
+ if (!writeHeaderFile(*specFile)) {
+ success = false;
+ }
+ }
+ return success;
+}