xref: /aosp_15_r20/frameworks/rs/script_api/Specification.cpp (revision e1eccf28f96817838ad6867f7f39d2351ec11f56)
1*e1eccf28SAndroid Build Coastguard Worker /*
2*e1eccf28SAndroid Build Coastguard Worker  * Copyright (C) 2013 The Android Open Source Project
3*e1eccf28SAndroid Build Coastguard Worker  *
4*e1eccf28SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*e1eccf28SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*e1eccf28SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*e1eccf28SAndroid Build Coastguard Worker  *
8*e1eccf28SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*e1eccf28SAndroid Build Coastguard Worker  *
10*e1eccf28SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*e1eccf28SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*e1eccf28SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e1eccf28SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*e1eccf28SAndroid Build Coastguard Worker  * limitations under the License.
15*e1eccf28SAndroid Build Coastguard Worker  */
16*e1eccf28SAndroid Build Coastguard Worker 
17*e1eccf28SAndroid Build Coastguard Worker #include <stdio.h>
18*e1eccf28SAndroid Build Coastguard Worker #include <cctype>
19*e1eccf28SAndroid Build Coastguard Worker #include <cstdlib>
20*e1eccf28SAndroid Build Coastguard Worker #include <fstream>
21*e1eccf28SAndroid Build Coastguard Worker #include <functional>
22*e1eccf28SAndroid Build Coastguard Worker #include <iostream>
23*e1eccf28SAndroid Build Coastguard Worker #include <memory>
24*e1eccf28SAndroid Build Coastguard Worker #include <sstream>
25*e1eccf28SAndroid Build Coastguard Worker #include <strings.h>
26*e1eccf28SAndroid Build Coastguard Worker 
27*e1eccf28SAndroid Build Coastguard Worker #include "Generator.h"
28*e1eccf28SAndroid Build Coastguard Worker #include "Scanner.h"
29*e1eccf28SAndroid Build Coastguard Worker #include "Specification.h"
30*e1eccf28SAndroid Build Coastguard Worker #include "Utilities.h"
31*e1eccf28SAndroid Build Coastguard Worker 
32*e1eccf28SAndroid Build Coastguard Worker using namespace std;
33*e1eccf28SAndroid Build Coastguard Worker 
34*e1eccf28SAndroid Build Coastguard Worker // API level when RenderScript was added.
35*e1eccf28SAndroid Build Coastguard Worker const unsigned int MIN_API_LEVEL = 9;
36*e1eccf28SAndroid Build Coastguard Worker 
37*e1eccf28SAndroid Build Coastguard Worker const NumericalType TYPES[] = {
38*e1eccf28SAndroid Build Coastguard Worker             {"f16", "FLOAT_16", "half", "short", FLOATING_POINT, 11, 5},
39*e1eccf28SAndroid Build Coastguard Worker             {"f32", "FLOAT_32", "float", "float", FLOATING_POINT, 24, 8},
40*e1eccf28SAndroid Build Coastguard Worker             {"f64", "FLOAT_64", "double", "double", FLOATING_POINT, 53, 11},
41*e1eccf28SAndroid Build Coastguard Worker             {"i8", "SIGNED_8", "char", "byte", SIGNED_INTEGER, 7, 0},
42*e1eccf28SAndroid Build Coastguard Worker             {"u8", "UNSIGNED_8", "uchar", "byte", UNSIGNED_INTEGER, 8, 0},
43*e1eccf28SAndroid Build Coastguard Worker             {"i16", "SIGNED_16", "short", "short", SIGNED_INTEGER, 15, 0},
44*e1eccf28SAndroid Build Coastguard Worker             {"u16", "UNSIGNED_16", "ushort", "short", UNSIGNED_INTEGER, 16, 0},
45*e1eccf28SAndroid Build Coastguard Worker             {"i32", "SIGNED_32", "int", "int", SIGNED_INTEGER, 31, 0},
46*e1eccf28SAndroid Build Coastguard Worker             {"u32", "UNSIGNED_32", "uint", "int", UNSIGNED_INTEGER, 32, 0},
47*e1eccf28SAndroid Build Coastguard Worker             {"i64", "SIGNED_64", "long", "long", SIGNED_INTEGER, 63, 0},
48*e1eccf28SAndroid Build Coastguard Worker             {"u64", "UNSIGNED_64", "ulong", "long", UNSIGNED_INTEGER, 64, 0},
49*e1eccf28SAndroid Build Coastguard Worker };
50*e1eccf28SAndroid Build Coastguard Worker 
51*e1eccf28SAndroid Build Coastguard Worker const int NUM_TYPES = sizeof(TYPES) / sizeof(TYPES[0]);
52*e1eccf28SAndroid Build Coastguard Worker 
53*e1eccf28SAndroid Build Coastguard Worker static const char kTagUnreleased[] = "UNRELEASED";
54*e1eccf28SAndroid Build Coastguard Worker 
55*e1eccf28SAndroid Build Coastguard Worker // Patterns that get substituted with C type or RS Data type names in function
56*e1eccf28SAndroid Build Coastguard Worker // names, arguments, return types, and inlines.
57*e1eccf28SAndroid Build Coastguard Worker static const string kCTypePatterns[] = {"#1", "#2", "#3", "#4"};
58*e1eccf28SAndroid Build Coastguard Worker static const string kRSTypePatterns[] = {"#RST_1", "#RST_2", "#RST_3", "#RST_4"};
59*e1eccf28SAndroid Build Coastguard Worker 
60*e1eccf28SAndroid Build Coastguard Worker // The singleton of the collected information of all the spec files.
61*e1eccf28SAndroid Build Coastguard Worker SystemSpecification systemSpecification;
62*e1eccf28SAndroid Build Coastguard Worker 
63*e1eccf28SAndroid Build Coastguard Worker // Returns the index in TYPES for the provided cType
findCType(const string & cType)64*e1eccf28SAndroid Build Coastguard Worker static int findCType(const string& cType) {
65*e1eccf28SAndroid Build Coastguard Worker     for (int i = 0; i < NUM_TYPES; i++) {
66*e1eccf28SAndroid Build Coastguard Worker         if (cType == TYPES[i].cType) {
67*e1eccf28SAndroid Build Coastguard Worker             return i;
68*e1eccf28SAndroid Build Coastguard Worker         }
69*e1eccf28SAndroid Build Coastguard Worker     }
70*e1eccf28SAndroid Build Coastguard Worker     return -1;
71*e1eccf28SAndroid Build Coastguard Worker }
72*e1eccf28SAndroid Build Coastguard Worker 
73*e1eccf28SAndroid Build Coastguard Worker /* Converts a string like "u8, u16" to a vector of "ushort", "uint".
74*e1eccf28SAndroid Build Coastguard Worker  * For non-numerical types, we don't need to convert the abbreviation.
75*e1eccf28SAndroid Build Coastguard Worker  */
convertToTypeVector(const string & input)76*e1eccf28SAndroid Build Coastguard Worker static vector<string> convertToTypeVector(const string& input) {
77*e1eccf28SAndroid Build Coastguard Worker     // First convert the string to an array of strings.
78*e1eccf28SAndroid Build Coastguard Worker     vector<string> entries;
79*e1eccf28SAndroid Build Coastguard Worker     stringstream stream(input);
80*e1eccf28SAndroid Build Coastguard Worker     string entry;
81*e1eccf28SAndroid Build Coastguard Worker     while (getline(stream, entry, ',')) {
82*e1eccf28SAndroid Build Coastguard Worker         trimSpaces(&entry);
83*e1eccf28SAndroid Build Coastguard Worker         entries.push_back(entry);
84*e1eccf28SAndroid Build Coastguard Worker     }
85*e1eccf28SAndroid Build Coastguard Worker 
86*e1eccf28SAndroid Build Coastguard Worker     /* Second, we look for present numerical types. We do it this way
87*e1eccf28SAndroid Build Coastguard Worker      * so the order of numerical types is always the same, no matter
88*e1eccf28SAndroid Build Coastguard Worker      * how specified in the spec file.
89*e1eccf28SAndroid Build Coastguard Worker      */
90*e1eccf28SAndroid Build Coastguard Worker     vector<string> result;
91*e1eccf28SAndroid Build Coastguard Worker     for (auto t : TYPES) {
92*e1eccf28SAndroid Build Coastguard Worker         for (auto i = entries.begin(); i != entries.end(); ++i) {
93*e1eccf28SAndroid Build Coastguard Worker             if (*i == t.specType) {
94*e1eccf28SAndroid Build Coastguard Worker                 result.push_back(t.cType);
95*e1eccf28SAndroid Build Coastguard Worker                 entries.erase(i);
96*e1eccf28SAndroid Build Coastguard Worker                 break;
97*e1eccf28SAndroid Build Coastguard Worker             }
98*e1eccf28SAndroid Build Coastguard Worker         }
99*e1eccf28SAndroid Build Coastguard Worker     }
100*e1eccf28SAndroid Build Coastguard Worker 
101*e1eccf28SAndroid Build Coastguard Worker     // Add the remaining; they are not numerical types.
102*e1eccf28SAndroid Build Coastguard Worker     for (auto s : entries) {
103*e1eccf28SAndroid Build Coastguard Worker         result.push_back(s);
104*e1eccf28SAndroid Build Coastguard Worker     }
105*e1eccf28SAndroid Build Coastguard Worker 
106*e1eccf28SAndroid Build Coastguard Worker     return result;
107*e1eccf28SAndroid Build Coastguard Worker }
108*e1eccf28SAndroid Build Coastguard Worker 
109*e1eccf28SAndroid Build Coastguard Worker // Returns true if each entry in typeVector is an RS numerical type
isRSTValid(const vector<string> & typeVector)110*e1eccf28SAndroid Build Coastguard Worker static bool isRSTValid(const vector<string> &typeVector) {
111*e1eccf28SAndroid Build Coastguard Worker     for (auto type: typeVector) {
112*e1eccf28SAndroid Build Coastguard Worker         if (findCType(type) == -1)
113*e1eccf28SAndroid Build Coastguard Worker             return false;
114*e1eccf28SAndroid Build Coastguard Worker     }
115*e1eccf28SAndroid Build Coastguard Worker     return true;
116*e1eccf28SAndroid Build Coastguard Worker }
117*e1eccf28SAndroid Build Coastguard Worker 
getVectorSizeAndBaseType(const string & type,string & vectorSize,string & baseType)118*e1eccf28SAndroid Build Coastguard Worker void getVectorSizeAndBaseType(const string& type, string& vectorSize, string& baseType) {
119*e1eccf28SAndroid Build Coastguard Worker     vectorSize = "1";
120*e1eccf28SAndroid Build Coastguard Worker     baseType = type;
121*e1eccf28SAndroid Build Coastguard Worker 
122*e1eccf28SAndroid Build Coastguard Worker     /* If it's a vector type, we need to split the base type from the size.
123*e1eccf28SAndroid Build Coastguard Worker      * We know that's it's a vector type if the last character is a digit and
124*e1eccf28SAndroid Build Coastguard Worker      * the rest is an actual base type.   We used to only verify the first part,
125*e1eccf28SAndroid Build Coastguard Worker      * which created a problem with rs_matrix2x2.
126*e1eccf28SAndroid Build Coastguard Worker      */
127*e1eccf28SAndroid Build Coastguard Worker     const int last = type.size() - 1;
128*e1eccf28SAndroid Build Coastguard Worker     const char lastChar = type[last];
129*e1eccf28SAndroid Build Coastguard Worker     if (lastChar >= '0' && lastChar <= '9') {
130*e1eccf28SAndroid Build Coastguard Worker         const string trimmed = type.substr(0, last);
131*e1eccf28SAndroid Build Coastguard Worker         int i = findCType(trimmed);
132*e1eccf28SAndroid Build Coastguard Worker         if (i >= 0) {
133*e1eccf28SAndroid Build Coastguard Worker             baseType = trimmed;
134*e1eccf28SAndroid Build Coastguard Worker             vectorSize = lastChar;
135*e1eccf28SAndroid Build Coastguard Worker         }
136*e1eccf28SAndroid Build Coastguard Worker     }
137*e1eccf28SAndroid Build Coastguard Worker }
138*e1eccf28SAndroid Build Coastguard Worker 
parseParameterDefinition(const string & type,const string & name,const string & testOption,int lineNumber,bool isReturn,Scanner * scanner)139*e1eccf28SAndroid Build Coastguard Worker void ParameterDefinition::parseParameterDefinition(const string& type, const string& name,
140*e1eccf28SAndroid Build Coastguard Worker                                                    const string& testOption, int lineNumber,
141*e1eccf28SAndroid Build Coastguard Worker                                                    bool isReturn, Scanner* scanner) {
142*e1eccf28SAndroid Build Coastguard Worker     rsType = type;
143*e1eccf28SAndroid Build Coastguard Worker     specName = name;
144*e1eccf28SAndroid Build Coastguard Worker 
145*e1eccf28SAndroid Build Coastguard Worker     // Determine if this is an output.
146*e1eccf28SAndroid Build Coastguard Worker     isOutParameter = isReturn || charRemoved('*', &rsType);
147*e1eccf28SAndroid Build Coastguard Worker 
148*e1eccf28SAndroid Build Coastguard Worker     getVectorSizeAndBaseType(rsType, mVectorSize, rsBaseType);
149*e1eccf28SAndroid Build Coastguard Worker     typeIndex = findCType(rsBaseType);
150*e1eccf28SAndroid Build Coastguard Worker 
151*e1eccf28SAndroid Build Coastguard Worker     if (mVectorSize == "3") {
152*e1eccf28SAndroid Build Coastguard Worker         vectorWidth = "4";
153*e1eccf28SAndroid Build Coastguard Worker     } else {
154*e1eccf28SAndroid Build Coastguard Worker         vectorWidth = mVectorSize;
155*e1eccf28SAndroid Build Coastguard Worker     }
156*e1eccf28SAndroid Build Coastguard Worker 
157*e1eccf28SAndroid Build Coastguard Worker     /* Create variable names to be used in the java and .rs files.  Because x and
158*e1eccf28SAndroid Build Coastguard Worker      * y are reserved in .rs files, we prefix variable names with "in" or "out".
159*e1eccf28SAndroid Build Coastguard Worker      */
160*e1eccf28SAndroid Build Coastguard Worker     if (isOutParameter) {
161*e1eccf28SAndroid Build Coastguard Worker         variableName = "out";
162*e1eccf28SAndroid Build Coastguard Worker         if (!specName.empty()) {
163*e1eccf28SAndroid Build Coastguard Worker             variableName += capitalize(specName);
164*e1eccf28SAndroid Build Coastguard Worker         } else if (!isReturn) {
165*e1eccf28SAndroid Build Coastguard Worker             scanner->error(lineNumber) << "Should have a name.\n";
166*e1eccf28SAndroid Build Coastguard Worker         }
167*e1eccf28SAndroid Build Coastguard Worker         doubleVariableName = variableName + "Double";
168*e1eccf28SAndroid Build Coastguard Worker     } else {
169*e1eccf28SAndroid Build Coastguard Worker         variableName = "in";
170*e1eccf28SAndroid Build Coastguard Worker         if (specName.empty()) {
171*e1eccf28SAndroid Build Coastguard Worker             scanner->error(lineNumber) << "Should have a name.\n";
172*e1eccf28SAndroid Build Coastguard Worker         }
173*e1eccf28SAndroid Build Coastguard Worker         variableName += capitalize(specName);
174*e1eccf28SAndroid Build Coastguard Worker         doubleVariableName = variableName + "Double";
175*e1eccf28SAndroid Build Coastguard Worker     }
176*e1eccf28SAndroid Build Coastguard Worker     rsAllocName = "gAlloc" + capitalize(variableName);
177*e1eccf28SAndroid Build Coastguard Worker     javaAllocName = variableName;
178*e1eccf28SAndroid Build Coastguard Worker     javaArrayName = "array" + capitalize(javaAllocName);
179*e1eccf28SAndroid Build Coastguard Worker 
180*e1eccf28SAndroid Build Coastguard Worker     // Process the option.
181*e1eccf28SAndroid Build Coastguard Worker     undefinedIfOutIsNan = false;
182*e1eccf28SAndroid Build Coastguard Worker     compatibleTypeIndex = -1;
183*e1eccf28SAndroid Build Coastguard Worker     if (!testOption.empty()) {
184*e1eccf28SAndroid Build Coastguard Worker         if (testOption.compare(0, 6, "range(") == 0) {
185*e1eccf28SAndroid Build Coastguard Worker             size_t pComma = testOption.find(',');
186*e1eccf28SAndroid Build Coastguard Worker             size_t pParen = testOption.find(')');
187*e1eccf28SAndroid Build Coastguard Worker             if (pComma == string::npos || pParen == string::npos) {
188*e1eccf28SAndroid Build Coastguard Worker                 scanner->error(lineNumber) << "Incorrect range " << testOption << "\n";
189*e1eccf28SAndroid Build Coastguard Worker             } else {
190*e1eccf28SAndroid Build Coastguard Worker                 minValue = testOption.substr(6, pComma - 6);
191*e1eccf28SAndroid Build Coastguard Worker                 maxValue = testOption.substr(pComma + 1, pParen - pComma - 1);
192*e1eccf28SAndroid Build Coastguard Worker             }
193*e1eccf28SAndroid Build Coastguard Worker         } else if (testOption.compare(0, 6, "above(") == 0) {
194*e1eccf28SAndroid Build Coastguard Worker             size_t pParen = testOption.find(')');
195*e1eccf28SAndroid Build Coastguard Worker             if (pParen == string::npos) {
196*e1eccf28SAndroid Build Coastguard Worker                 scanner->error(lineNumber) << "Incorrect testOption " << testOption << "\n";
197*e1eccf28SAndroid Build Coastguard Worker             } else {
198*e1eccf28SAndroid Build Coastguard Worker                 smallerParameter = testOption.substr(6, pParen - 6);
199*e1eccf28SAndroid Build Coastguard Worker             }
200*e1eccf28SAndroid Build Coastguard Worker         } else if (testOption.compare(0, 11, "compatible(") == 0) {
201*e1eccf28SAndroid Build Coastguard Worker             size_t pParen = testOption.find(')');
202*e1eccf28SAndroid Build Coastguard Worker             if (pParen == string::npos) {
203*e1eccf28SAndroid Build Coastguard Worker                 scanner->error(lineNumber) << "Incorrect testOption " << testOption << "\n";
204*e1eccf28SAndroid Build Coastguard Worker             } else {
205*e1eccf28SAndroid Build Coastguard Worker                 compatibleTypeIndex = findCType(testOption.substr(11, pParen - 11));
206*e1eccf28SAndroid Build Coastguard Worker             }
207*e1eccf28SAndroid Build Coastguard Worker         } else if (testOption.compare(0, 11, "conditional") == 0) {
208*e1eccf28SAndroid Build Coastguard Worker             undefinedIfOutIsNan = true;
209*e1eccf28SAndroid Build Coastguard Worker         } else {
210*e1eccf28SAndroid Build Coastguard Worker             scanner->error(lineNumber) << "Unrecognized testOption " << testOption << "\n";
211*e1eccf28SAndroid Build Coastguard Worker         }
212*e1eccf28SAndroid Build Coastguard Worker     }
213*e1eccf28SAndroid Build Coastguard Worker 
214*e1eccf28SAndroid Build Coastguard Worker     isFloatType = false;
215*e1eccf28SAndroid Build Coastguard Worker     if (typeIndex >= 0) {
216*e1eccf28SAndroid Build Coastguard Worker         javaBaseType = TYPES[typeIndex].javaType;
217*e1eccf28SAndroid Build Coastguard Worker         specType = TYPES[typeIndex].specType;
218*e1eccf28SAndroid Build Coastguard Worker         isFloatType = TYPES[typeIndex].exponentBits > 0;
219*e1eccf28SAndroid Build Coastguard Worker     }
220*e1eccf28SAndroid Build Coastguard Worker     if (!minValue.empty()) {
221*e1eccf28SAndroid Build Coastguard Worker         if (typeIndex < 0 || TYPES[typeIndex].kind != FLOATING_POINT) {
222*e1eccf28SAndroid Build Coastguard Worker             scanner->error(lineNumber) << "range(,) is only supported for floating point\n";
223*e1eccf28SAndroid Build Coastguard Worker         }
224*e1eccf28SAndroid Build Coastguard Worker     }
225*e1eccf28SAndroid Build Coastguard Worker }
226*e1eccf28SAndroid Build Coastguard Worker 
scan(Scanner * scanner,unsigned int maxApiLevel)227*e1eccf28SAndroid Build Coastguard Worker bool VersionInfo::scan(Scanner* scanner, unsigned int maxApiLevel) {
228*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("version:")) {
229*e1eccf28SAndroid Build Coastguard Worker         const string s = scanner->getValue();
230*e1eccf28SAndroid Build Coastguard Worker         if (s.compare(0, sizeof(kTagUnreleased), kTagUnreleased) == 0) {
231*e1eccf28SAndroid Build Coastguard Worker             // The API is still under development and does not have
232*e1eccf28SAndroid Build Coastguard Worker             // an official version number.
233*e1eccf28SAndroid Build Coastguard Worker             minVersion = maxVersion = kUnreleasedVersion;
234*e1eccf28SAndroid Build Coastguard Worker         } else {
235*e1eccf28SAndroid Build Coastguard Worker             sscanf(s.c_str(), "%u %u", &minVersion, &maxVersion);
236*e1eccf28SAndroid Build Coastguard Worker             if (minVersion && minVersion < MIN_API_LEVEL) {
237*e1eccf28SAndroid Build Coastguard Worker                 scanner->error() << "Minimum version must >= 9\n";
238*e1eccf28SAndroid Build Coastguard Worker             }
239*e1eccf28SAndroid Build Coastguard Worker             if (minVersion == MIN_API_LEVEL) {
240*e1eccf28SAndroid Build Coastguard Worker                 minVersion = 0;
241*e1eccf28SAndroid Build Coastguard Worker             }
242*e1eccf28SAndroid Build Coastguard Worker             if (maxVersion && maxVersion < MIN_API_LEVEL) {
243*e1eccf28SAndroid Build Coastguard Worker                 scanner->error() << "Maximum version must >= 9\n";
244*e1eccf28SAndroid Build Coastguard Worker             }
245*e1eccf28SAndroid Build Coastguard Worker         }
246*e1eccf28SAndroid Build Coastguard Worker     }
247*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("size:")) {
248*e1eccf28SAndroid Build Coastguard Worker         sscanf(scanner->getValue().c_str(), "%i", &intSize);
249*e1eccf28SAndroid Build Coastguard Worker     }
250*e1eccf28SAndroid Build Coastguard Worker 
251*e1eccf28SAndroid Build Coastguard Worker     if (maxVersion > maxApiLevel) {
252*e1eccf28SAndroid Build Coastguard Worker         maxVersion = maxApiLevel;
253*e1eccf28SAndroid Build Coastguard Worker     }
254*e1eccf28SAndroid Build Coastguard Worker 
255*e1eccf28SAndroid Build Coastguard Worker     return minVersion == 0 || minVersion <= maxApiLevel;
256*e1eccf28SAndroid Build Coastguard Worker }
257*e1eccf28SAndroid Build Coastguard Worker 
Definition(const std::string & name)258*e1eccf28SAndroid Build Coastguard Worker Definition::Definition(const std::string& name)
259*e1eccf28SAndroid Build Coastguard Worker     : mName(name), mDeprecatedApiLevel(0), mHidden(false), mFinalVersion(-1) {
260*e1eccf28SAndroid Build Coastguard Worker }
261*e1eccf28SAndroid Build Coastguard Worker 
updateFinalVersion(const VersionInfo & info)262*e1eccf28SAndroid Build Coastguard Worker void Definition::updateFinalVersion(const VersionInfo& info) {
263*e1eccf28SAndroid Build Coastguard Worker     /* We set it if:
264*e1eccf28SAndroid Build Coastguard Worker      * - We have never set mFinalVersion before, or
265*e1eccf28SAndroid Build Coastguard Worker      * - The max version is 0, which means we have not expired this API, or
266*e1eccf28SAndroid Build Coastguard Worker      * - We have a max that's later than what we currently have.
267*e1eccf28SAndroid Build Coastguard Worker      */
268*e1eccf28SAndroid Build Coastguard Worker     if (mFinalVersion < 0 || info.maxVersion == 0 ||
269*e1eccf28SAndroid Build Coastguard Worker         (mFinalVersion > 0 &&
270*e1eccf28SAndroid Build Coastguard Worker          static_cast<int>(info.maxVersion) > mFinalVersion)) {
271*e1eccf28SAndroid Build Coastguard Worker         mFinalVersion = info.maxVersion;
272*e1eccf28SAndroid Build Coastguard Worker     }
273*e1eccf28SAndroid Build Coastguard Worker }
274*e1eccf28SAndroid Build Coastguard Worker 
scanDocumentationTags(Scanner * scanner,bool firstOccurence,const SpecFile * specFile)275*e1eccf28SAndroid Build Coastguard Worker void Definition::scanDocumentationTags(Scanner* scanner, bool firstOccurence,
276*e1eccf28SAndroid Build Coastguard Worker                                        const SpecFile* specFile) {
277*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("hidden:")) {
278*e1eccf28SAndroid Build Coastguard Worker         scanner->checkNoValue();
279*e1eccf28SAndroid Build Coastguard Worker         mHidden = true;
280*e1eccf28SAndroid Build Coastguard Worker     }
281*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("deprecated:")) {
282*e1eccf28SAndroid Build Coastguard Worker         string value = scanner->getValue();
283*e1eccf28SAndroid Build Coastguard Worker         size_t pComma = value.find(", ");
284*e1eccf28SAndroid Build Coastguard Worker         if (pComma != string::npos) {
285*e1eccf28SAndroid Build Coastguard Worker             mDeprecatedMessage = value.substr(pComma + 2);
286*e1eccf28SAndroid Build Coastguard Worker             value.erase(pComma);
287*e1eccf28SAndroid Build Coastguard Worker         }
288*e1eccf28SAndroid Build Coastguard Worker         sscanf(value.c_str(), "%i", &mDeprecatedApiLevel);
289*e1eccf28SAndroid Build Coastguard Worker         if (mDeprecatedApiLevel <= 0) {
290*e1eccf28SAndroid Build Coastguard Worker             scanner->error() << "deprecated entries should have a level > 0\n";
291*e1eccf28SAndroid Build Coastguard Worker         }
292*e1eccf28SAndroid Build Coastguard Worker     }
293*e1eccf28SAndroid Build Coastguard Worker     if (firstOccurence) {
294*e1eccf28SAndroid Build Coastguard Worker         if (scanner->findTag("summary:")) {
295*e1eccf28SAndroid Build Coastguard Worker             mSummary = scanner->getValue();
296*e1eccf28SAndroid Build Coastguard Worker         }
297*e1eccf28SAndroid Build Coastguard Worker         if (scanner->findTag("description:")) {
298*e1eccf28SAndroid Build Coastguard Worker             scanner->checkNoValue();
299*e1eccf28SAndroid Build Coastguard Worker             while (scanner->findOptionalTag("")) {
300*e1eccf28SAndroid Build Coastguard Worker                 mDescription.push_back(scanner->getValue());
301*e1eccf28SAndroid Build Coastguard Worker             }
302*e1eccf28SAndroid Build Coastguard Worker         }
303*e1eccf28SAndroid Build Coastguard Worker         mUrl = specFile->getDetailedDocumentationUrl() + "#android_rs:" + mName;
304*e1eccf28SAndroid Build Coastguard Worker     } else if (scanner->findOptionalTag("summary:")) {
305*e1eccf28SAndroid Build Coastguard Worker         scanner->error() << "Only the first specification should have a summary.\n";
306*e1eccf28SAndroid Build Coastguard Worker     }
307*e1eccf28SAndroid Build Coastguard Worker }
308*e1eccf28SAndroid Build Coastguard Worker 
~Constant()309*e1eccf28SAndroid Build Coastguard Worker Constant::~Constant() {
310*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mSpecifications) {
311*e1eccf28SAndroid Build Coastguard Worker         delete i;
312*e1eccf28SAndroid Build Coastguard Worker     }
313*e1eccf28SAndroid Build Coastguard Worker }
314*e1eccf28SAndroid Build Coastguard Worker 
~Type()315*e1eccf28SAndroid Build Coastguard Worker Type::~Type() {
316*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mSpecifications) {
317*e1eccf28SAndroid Build Coastguard Worker         delete i;
318*e1eccf28SAndroid Build Coastguard Worker     }
319*e1eccf28SAndroid Build Coastguard Worker }
320*e1eccf28SAndroid Build Coastguard Worker 
Function(const string & name)321*e1eccf28SAndroid Build Coastguard Worker Function::Function(const string& name) : Definition(name) {
322*e1eccf28SAndroid Build Coastguard Worker     mCapitalizedName = capitalize(mName);
323*e1eccf28SAndroid Build Coastguard Worker }
324*e1eccf28SAndroid Build Coastguard Worker 
~Function()325*e1eccf28SAndroid Build Coastguard Worker Function::~Function() {
326*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mSpecifications) {
327*e1eccf28SAndroid Build Coastguard Worker         delete i;
328*e1eccf28SAndroid Build Coastguard Worker     }
329*e1eccf28SAndroid Build Coastguard Worker }
330*e1eccf28SAndroid Build Coastguard Worker 
someParametersAreDocumented() const331*e1eccf28SAndroid Build Coastguard Worker bool Function::someParametersAreDocumented() const {
332*e1eccf28SAndroid Build Coastguard Worker     for (auto p : mParameters) {
333*e1eccf28SAndroid Build Coastguard Worker         if (!p->documentation.empty()) {
334*e1eccf28SAndroid Build Coastguard Worker             return true;
335*e1eccf28SAndroid Build Coastguard Worker         }
336*e1eccf28SAndroid Build Coastguard Worker     }
337*e1eccf28SAndroid Build Coastguard Worker     return false;
338*e1eccf28SAndroid Build Coastguard Worker }
339*e1eccf28SAndroid Build Coastguard Worker 
addParameter(ParameterEntry * entry,Scanner * scanner)340*e1eccf28SAndroid Build Coastguard Worker void Function::addParameter(ParameterEntry* entry, Scanner* scanner) {
341*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mParameters) {
342*e1eccf28SAndroid Build Coastguard Worker         if (i->name == entry->name) {
343*e1eccf28SAndroid Build Coastguard Worker             // It's a duplicate.
344*e1eccf28SAndroid Build Coastguard Worker             if (!entry->documentation.empty()) {
345*e1eccf28SAndroid Build Coastguard Worker                 scanner->error(entry->lineNumber)
346*e1eccf28SAndroid Build Coastguard Worker                             << "Only the first occurence of an arg should have the "
347*e1eccf28SAndroid Build Coastguard Worker                                "documentation.\n";
348*e1eccf28SAndroid Build Coastguard Worker             }
349*e1eccf28SAndroid Build Coastguard Worker             return;
350*e1eccf28SAndroid Build Coastguard Worker         }
351*e1eccf28SAndroid Build Coastguard Worker     }
352*e1eccf28SAndroid Build Coastguard Worker     mParameters.push_back(entry);
353*e1eccf28SAndroid Build Coastguard Worker }
354*e1eccf28SAndroid Build Coastguard Worker 
addReturn(ParameterEntry * entry,Scanner * scanner)355*e1eccf28SAndroid Build Coastguard Worker void Function::addReturn(ParameterEntry* entry, Scanner* scanner) {
356*e1eccf28SAndroid Build Coastguard Worker     if (entry->documentation.empty()) {
357*e1eccf28SAndroid Build Coastguard Worker         return;
358*e1eccf28SAndroid Build Coastguard Worker     }
359*e1eccf28SAndroid Build Coastguard Worker     if (!mReturnDocumentation.empty()) {
360*e1eccf28SAndroid Build Coastguard Worker         scanner->error() << "ret: should be documented only for the first variant\n";
361*e1eccf28SAndroid Build Coastguard Worker     }
362*e1eccf28SAndroid Build Coastguard Worker     mReturnDocumentation = entry->documentation;
363*e1eccf28SAndroid Build Coastguard Worker }
364*e1eccf28SAndroid Build Coastguard Worker 
scanConstantSpecification(Scanner * scanner,SpecFile * specFile,unsigned int maxApiLevel)365*e1eccf28SAndroid Build Coastguard Worker void ConstantSpecification::scanConstantSpecification(Scanner* scanner, SpecFile* specFile,
366*e1eccf28SAndroid Build Coastguard Worker                                                       unsigned int maxApiLevel) {
367*e1eccf28SAndroid Build Coastguard Worker     string name = scanner->getValue();
368*e1eccf28SAndroid Build Coastguard Worker     VersionInfo info;
369*e1eccf28SAndroid Build Coastguard Worker     if (!info.scan(scanner, maxApiLevel)) {
370*e1eccf28SAndroid Build Coastguard Worker         cout << "Skipping some " << name << " definitions.\n";
371*e1eccf28SAndroid Build Coastguard Worker         scanner->skipUntilTag("end:");
372*e1eccf28SAndroid Build Coastguard Worker         return;
373*e1eccf28SAndroid Build Coastguard Worker     }
374*e1eccf28SAndroid Build Coastguard Worker 
375*e1eccf28SAndroid Build Coastguard Worker     bool created = false;
376*e1eccf28SAndroid Build Coastguard Worker     Constant* constant = systemSpecification.findOrCreateConstant(name, &created);
377*e1eccf28SAndroid Build Coastguard Worker     ConstantSpecification* spec = new ConstantSpecification(constant);
378*e1eccf28SAndroid Build Coastguard Worker     constant->addSpecification(spec);
379*e1eccf28SAndroid Build Coastguard Worker     constant->updateFinalVersion(info);
380*e1eccf28SAndroid Build Coastguard Worker     specFile->addConstantSpecification(spec, created);
381*e1eccf28SAndroid Build Coastguard Worker     spec->mVersionInfo = info;
382*e1eccf28SAndroid Build Coastguard Worker 
383*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findTag("value:")) {
384*e1eccf28SAndroid Build Coastguard Worker         spec->mValue = scanner->getValue();
385*e1eccf28SAndroid Build Coastguard Worker     }
386*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findTag("type:")) {
387*e1eccf28SAndroid Build Coastguard Worker         spec->mType = scanner->getValue();
388*e1eccf28SAndroid Build Coastguard Worker     }
389*e1eccf28SAndroid Build Coastguard Worker     constant->scanDocumentationTags(scanner, created, specFile);
390*e1eccf28SAndroid Build Coastguard Worker 
391*e1eccf28SAndroid Build Coastguard Worker     scanner->findTag("end:");
392*e1eccf28SAndroid Build Coastguard Worker }
393*e1eccf28SAndroid Build Coastguard Worker 
scanTypeSpecification(Scanner * scanner,SpecFile * specFile,unsigned int maxApiLevel)394*e1eccf28SAndroid Build Coastguard Worker void TypeSpecification::scanTypeSpecification(Scanner* scanner, SpecFile* specFile,
395*e1eccf28SAndroid Build Coastguard Worker                                               unsigned int maxApiLevel) {
396*e1eccf28SAndroid Build Coastguard Worker     string name = scanner->getValue();
397*e1eccf28SAndroid Build Coastguard Worker     VersionInfo info;
398*e1eccf28SAndroid Build Coastguard Worker     if (!info.scan(scanner, maxApiLevel)) {
399*e1eccf28SAndroid Build Coastguard Worker         cout << "Skipping some " << name << " definitions.\n";
400*e1eccf28SAndroid Build Coastguard Worker         scanner->skipUntilTag("end:");
401*e1eccf28SAndroid Build Coastguard Worker         return;
402*e1eccf28SAndroid Build Coastguard Worker     }
403*e1eccf28SAndroid Build Coastguard Worker 
404*e1eccf28SAndroid Build Coastguard Worker     bool created = false;
405*e1eccf28SAndroid Build Coastguard Worker     Type* type = systemSpecification.findOrCreateType(name, &created);
406*e1eccf28SAndroid Build Coastguard Worker     TypeSpecification* spec = new TypeSpecification(type);
407*e1eccf28SAndroid Build Coastguard Worker     type->addSpecification(spec);
408*e1eccf28SAndroid Build Coastguard Worker     type->updateFinalVersion(info);
409*e1eccf28SAndroid Build Coastguard Worker     specFile->addTypeSpecification(spec, created);
410*e1eccf28SAndroid Build Coastguard Worker     spec->mVersionInfo = info;
411*e1eccf28SAndroid Build Coastguard Worker 
412*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("simple:")) {
413*e1eccf28SAndroid Build Coastguard Worker         spec->mKind = SIMPLE;
414*e1eccf28SAndroid Build Coastguard Worker         spec->mSimpleType = scanner->getValue();
415*e1eccf28SAndroid Build Coastguard Worker     }
416*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("rs_object:")) {
417*e1eccf28SAndroid Build Coastguard Worker         spec->mKind = RS_OBJECT;
418*e1eccf28SAndroid Build Coastguard Worker     }
419*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("struct:")) {
420*e1eccf28SAndroid Build Coastguard Worker         spec->mKind = STRUCT;
421*e1eccf28SAndroid Build Coastguard Worker         spec->mStructName = scanner->getValue();
422*e1eccf28SAndroid Build Coastguard Worker         while (scanner->findOptionalTag("field:")) {
423*e1eccf28SAndroid Build Coastguard Worker             string s = scanner->getValue();
424*e1eccf28SAndroid Build Coastguard Worker             string comment;
425*e1eccf28SAndroid Build Coastguard Worker             scanner->parseDocumentation(&s, &comment);
426*e1eccf28SAndroid Build Coastguard Worker             spec->mFields.push_back(s);
427*e1eccf28SAndroid Build Coastguard Worker             spec->mFieldComments.push_back(comment);
428*e1eccf28SAndroid Build Coastguard Worker         }
429*e1eccf28SAndroid Build Coastguard Worker     }
430*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("enum:")) {
431*e1eccf28SAndroid Build Coastguard Worker         spec->mKind = ENUM;
432*e1eccf28SAndroid Build Coastguard Worker         spec->mEnumName = scanner->getValue();
433*e1eccf28SAndroid Build Coastguard Worker         while (scanner->findOptionalTag("value:")) {
434*e1eccf28SAndroid Build Coastguard Worker             string s = scanner->getValue();
435*e1eccf28SAndroid Build Coastguard Worker             string comment;
436*e1eccf28SAndroid Build Coastguard Worker             scanner->parseDocumentation(&s, &comment);
437*e1eccf28SAndroid Build Coastguard Worker             spec->mValues.push_back(s);
438*e1eccf28SAndroid Build Coastguard Worker             spec->mValueComments.push_back(comment);
439*e1eccf28SAndroid Build Coastguard Worker         }
440*e1eccf28SAndroid Build Coastguard Worker     }
441*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("attrib:")) {
442*e1eccf28SAndroid Build Coastguard Worker         spec->mAttribute = scanner->getValue();
443*e1eccf28SAndroid Build Coastguard Worker     }
444*e1eccf28SAndroid Build Coastguard Worker     type->scanDocumentationTags(scanner, created, specFile);
445*e1eccf28SAndroid Build Coastguard Worker 
446*e1eccf28SAndroid Build Coastguard Worker     scanner->findTag("end:");
447*e1eccf28SAndroid Build Coastguard Worker }
448*e1eccf28SAndroid Build Coastguard Worker 
~FunctionSpecification()449*e1eccf28SAndroid Build Coastguard Worker FunctionSpecification::~FunctionSpecification() {
450*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mParameters) {
451*e1eccf28SAndroid Build Coastguard Worker         delete i;
452*e1eccf28SAndroid Build Coastguard Worker     }
453*e1eccf28SAndroid Build Coastguard Worker     delete mReturn;
454*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mPermutations) {
455*e1eccf28SAndroid Build Coastguard Worker         delete i;
456*e1eccf28SAndroid Build Coastguard Worker     }
457*e1eccf28SAndroid Build Coastguard Worker }
458*e1eccf28SAndroid Build Coastguard Worker 
expandRSTypeInString(const string & s,const string & pattern,const string & cTypeStr) const459*e1eccf28SAndroid Build Coastguard Worker string FunctionSpecification::expandRSTypeInString(const string &s,
460*e1eccf28SAndroid Build Coastguard Worker                                                    const string &pattern,
461*e1eccf28SAndroid Build Coastguard Worker                                                    const string &cTypeStr) const {
462*e1eccf28SAndroid Build Coastguard Worker     // Find index of numerical type corresponding to cTypeStr.  The case where
463*e1eccf28SAndroid Build Coastguard Worker     // pattern is found in s but cTypeStr is not a numerical type is checked in
464*e1eccf28SAndroid Build Coastguard Worker     // checkRSTPatternValidity.
465*e1eccf28SAndroid Build Coastguard Worker     int typeIdx = findCType(cTypeStr);
466*e1eccf28SAndroid Build Coastguard Worker     if (typeIdx == -1) {
467*e1eccf28SAndroid Build Coastguard Worker         return s;
468*e1eccf28SAndroid Build Coastguard Worker     }
469*e1eccf28SAndroid Build Coastguard Worker     // If index exists, perform replacement.
470*e1eccf28SAndroid Build Coastguard Worker     return stringReplace(s, pattern, TYPES[typeIdx].rsDataType);
471*e1eccf28SAndroid Build Coastguard Worker }
472*e1eccf28SAndroid Build Coastguard Worker 
expandString(string s,int replacementIndexes[MAX_REPLACEABLES]) const473*e1eccf28SAndroid Build Coastguard Worker string FunctionSpecification::expandString(string s,
474*e1eccf28SAndroid Build Coastguard Worker                                            int replacementIndexes[MAX_REPLACEABLES]) const {
475*e1eccf28SAndroid Build Coastguard Worker 
476*e1eccf28SAndroid Build Coastguard Worker 
477*e1eccf28SAndroid Build Coastguard Worker     for (unsigned idx = 0; idx < mReplaceables.size(); idx ++) {
478*e1eccf28SAndroid Build Coastguard Worker         string toString = mReplaceables[idx][replacementIndexes[idx]];
479*e1eccf28SAndroid Build Coastguard Worker 
480*e1eccf28SAndroid Build Coastguard Worker         // replace #RST_i patterns with RS datatype corresponding to toString
481*e1eccf28SAndroid Build Coastguard Worker         s = expandRSTypeInString(s, kRSTypePatterns[idx], toString);
482*e1eccf28SAndroid Build Coastguard Worker 
483*e1eccf28SAndroid Build Coastguard Worker         // replace #i patterns with C type from mReplaceables
484*e1eccf28SAndroid Build Coastguard Worker         s = stringReplace(s, kCTypePatterns[idx], toString);
485*e1eccf28SAndroid Build Coastguard Worker     }
486*e1eccf28SAndroid Build Coastguard Worker 
487*e1eccf28SAndroid Build Coastguard Worker     return s;
488*e1eccf28SAndroid Build Coastguard Worker }
489*e1eccf28SAndroid Build Coastguard Worker 
expandStringVector(const vector<string> & in,int replacementIndexes[MAX_REPLACEABLES],vector<string> * out) const490*e1eccf28SAndroid Build Coastguard Worker void FunctionSpecification::expandStringVector(const vector<string>& in,
491*e1eccf28SAndroid Build Coastguard Worker                                                int replacementIndexes[MAX_REPLACEABLES],
492*e1eccf28SAndroid Build Coastguard Worker                                                vector<string>* out) const {
493*e1eccf28SAndroid Build Coastguard Worker     out->clear();
494*e1eccf28SAndroid Build Coastguard Worker     for (vector<string>::const_iterator iter = in.begin(); iter != in.end(); iter++) {
495*e1eccf28SAndroid Build Coastguard Worker         out->push_back(expandString(*iter, replacementIndexes));
496*e1eccf28SAndroid Build Coastguard Worker     }
497*e1eccf28SAndroid Build Coastguard Worker }
498*e1eccf28SAndroid Build Coastguard Worker 
createPermutations(Function * function,Scanner * scanner)499*e1eccf28SAndroid Build Coastguard Worker void FunctionSpecification::createPermutations(Function* function, Scanner* scanner) {
500*e1eccf28SAndroid Build Coastguard Worker     int start[MAX_REPLACEABLES];
501*e1eccf28SAndroid Build Coastguard Worker     int end[MAX_REPLACEABLES];
502*e1eccf28SAndroid Build Coastguard Worker     for (int i = 0; i < MAX_REPLACEABLES; i++) {
503*e1eccf28SAndroid Build Coastguard Worker         if (i < (int)mReplaceables.size()) {
504*e1eccf28SAndroid Build Coastguard Worker             start[i] = 0;
505*e1eccf28SAndroid Build Coastguard Worker             end[i] = mReplaceables[i].size();
506*e1eccf28SAndroid Build Coastguard Worker         } else {
507*e1eccf28SAndroid Build Coastguard Worker             start[i] = -1;
508*e1eccf28SAndroid Build Coastguard Worker             end[i] = 0;
509*e1eccf28SAndroid Build Coastguard Worker         }
510*e1eccf28SAndroid Build Coastguard Worker     }
511*e1eccf28SAndroid Build Coastguard Worker     int replacementIndexes[MAX_REPLACEABLES];
512*e1eccf28SAndroid Build Coastguard Worker     // TODO: These loops assume that MAX_REPLACEABLES is 4.
513*e1eccf28SAndroid Build Coastguard Worker     for (replacementIndexes[3] = start[3]; replacementIndexes[3] < end[3];
514*e1eccf28SAndroid Build Coastguard Worker          replacementIndexes[3]++) {
515*e1eccf28SAndroid Build Coastguard Worker         for (replacementIndexes[2] = start[2]; replacementIndexes[2] < end[2];
516*e1eccf28SAndroid Build Coastguard Worker              replacementIndexes[2]++) {
517*e1eccf28SAndroid Build Coastguard Worker             for (replacementIndexes[1] = start[1]; replacementIndexes[1] < end[1];
518*e1eccf28SAndroid Build Coastguard Worker                  replacementIndexes[1]++) {
519*e1eccf28SAndroid Build Coastguard Worker                 for (replacementIndexes[0] = start[0]; replacementIndexes[0] < end[0];
520*e1eccf28SAndroid Build Coastguard Worker                      replacementIndexes[0]++) {
521*e1eccf28SAndroid Build Coastguard Worker                     auto p = new FunctionPermutation(function, this, replacementIndexes, scanner);
522*e1eccf28SAndroid Build Coastguard Worker                     mPermutations.push_back(p);
523*e1eccf28SAndroid Build Coastguard Worker                 }
524*e1eccf28SAndroid Build Coastguard Worker             }
525*e1eccf28SAndroid Build Coastguard Worker         }
526*e1eccf28SAndroid Build Coastguard Worker     }
527*e1eccf28SAndroid Build Coastguard Worker }
528*e1eccf28SAndroid Build Coastguard Worker 
getName(int replacementIndexes[MAX_REPLACEABLES]) const529*e1eccf28SAndroid Build Coastguard Worker string FunctionSpecification::getName(int replacementIndexes[MAX_REPLACEABLES]) const {
530*e1eccf28SAndroid Build Coastguard Worker     return expandString(mUnexpandedName, replacementIndexes);
531*e1eccf28SAndroid Build Coastguard Worker }
532*e1eccf28SAndroid Build Coastguard Worker 
getReturn(int replacementIndexes[MAX_REPLACEABLES],std::string * retType,int * lineNumber) const533*e1eccf28SAndroid Build Coastguard Worker void FunctionSpecification::getReturn(int replacementIndexes[MAX_REPLACEABLES],
534*e1eccf28SAndroid Build Coastguard Worker                                       std::string* retType, int* lineNumber) const {
535*e1eccf28SAndroid Build Coastguard Worker     *retType = expandString(mReturn->type, replacementIndexes);
536*e1eccf28SAndroid Build Coastguard Worker     *lineNumber = mReturn->lineNumber;
537*e1eccf28SAndroid Build Coastguard Worker }
538*e1eccf28SAndroid Build Coastguard Worker 
getParam(size_t index,int replacementIndexes[MAX_REPLACEABLES],std::string * type,std::string * name,std::string * testOption,int * lineNumber) const539*e1eccf28SAndroid Build Coastguard Worker void FunctionSpecification::getParam(size_t index, int replacementIndexes[MAX_REPLACEABLES],
540*e1eccf28SAndroid Build Coastguard Worker                                      std::string* type, std::string* name, std::string* testOption,
541*e1eccf28SAndroid Build Coastguard Worker                                      int* lineNumber) const {
542*e1eccf28SAndroid Build Coastguard Worker     ParameterEntry* p = mParameters[index];
543*e1eccf28SAndroid Build Coastguard Worker     *type = expandString(p->type, replacementIndexes);
544*e1eccf28SAndroid Build Coastguard Worker     *name = p->name;
545*e1eccf28SAndroid Build Coastguard Worker     *testOption = expandString(p->testOption, replacementIndexes);
546*e1eccf28SAndroid Build Coastguard Worker     *lineNumber = p->lineNumber;
547*e1eccf28SAndroid Build Coastguard Worker }
548*e1eccf28SAndroid Build Coastguard Worker 
getInlines(int replacementIndexes[MAX_REPLACEABLES],std::vector<std::string> * inlines) const549*e1eccf28SAndroid Build Coastguard Worker void FunctionSpecification::getInlines(int replacementIndexes[MAX_REPLACEABLES],
550*e1eccf28SAndroid Build Coastguard Worker                                        std::vector<std::string>* inlines) const {
551*e1eccf28SAndroid Build Coastguard Worker     expandStringVector(mInline, replacementIndexes, inlines);
552*e1eccf28SAndroid Build Coastguard Worker }
553*e1eccf28SAndroid Build Coastguard Worker 
parseTest(Scanner * scanner)554*e1eccf28SAndroid Build Coastguard Worker void FunctionSpecification::parseTest(Scanner* scanner) {
555*e1eccf28SAndroid Build Coastguard Worker     const string value = scanner->getValue();
556*e1eccf28SAndroid Build Coastguard Worker     if (value == "scalar" || value == "vector" || value == "noverify" || value == "custom" ||
557*e1eccf28SAndroid Build Coastguard Worker         value == "none") {
558*e1eccf28SAndroid Build Coastguard Worker         mTest = value;
559*e1eccf28SAndroid Build Coastguard Worker     } else if (value.compare(0, 7, "limited") == 0) {
560*e1eccf28SAndroid Build Coastguard Worker         mTest = "limited";
561*e1eccf28SAndroid Build Coastguard Worker         if (value.compare(7, 1, "(") == 0) {
562*e1eccf28SAndroid Build Coastguard Worker             size_t pParen = value.find(')');
563*e1eccf28SAndroid Build Coastguard Worker             if (pParen == string::npos) {
564*e1eccf28SAndroid Build Coastguard Worker                 scanner->error() << "Incorrect test: \"" << value << "\"\n";
565*e1eccf28SAndroid Build Coastguard Worker             } else {
566*e1eccf28SAndroid Build Coastguard Worker                 mPrecisionLimit = value.substr(8, pParen - 8);
567*e1eccf28SAndroid Build Coastguard Worker             }
568*e1eccf28SAndroid Build Coastguard Worker         }
569*e1eccf28SAndroid Build Coastguard Worker     } else {
570*e1eccf28SAndroid Build Coastguard Worker         scanner->error() << "Unrecognized test option: \"" << value << "\"\n";
571*e1eccf28SAndroid Build Coastguard Worker     }
572*e1eccf28SAndroid Build Coastguard Worker }
573*e1eccf28SAndroid Build Coastguard Worker 
hasTests(unsigned int versionOfTestFiles) const574*e1eccf28SAndroid Build Coastguard Worker bool FunctionSpecification::hasTests(unsigned int versionOfTestFiles) const {
575*e1eccf28SAndroid Build Coastguard Worker     if (mVersionInfo.maxVersion != 0 && mVersionInfo.maxVersion < versionOfTestFiles) {
576*e1eccf28SAndroid Build Coastguard Worker         return false;
577*e1eccf28SAndroid Build Coastguard Worker     }
578*e1eccf28SAndroid Build Coastguard Worker     if (mTest == "none") {
579*e1eccf28SAndroid Build Coastguard Worker         return false;
580*e1eccf28SAndroid Build Coastguard Worker     }
581*e1eccf28SAndroid Build Coastguard Worker     return true;
582*e1eccf28SAndroid Build Coastguard Worker }
583*e1eccf28SAndroid Build Coastguard Worker 
checkRSTPatternValidity(const string & inlineStr,bool allow,Scanner * scanner)584*e1eccf28SAndroid Build Coastguard Worker void FunctionSpecification::checkRSTPatternValidity(const string &inlineStr,  bool allow,
585*e1eccf28SAndroid Build Coastguard Worker                                                     Scanner *scanner) {
586*e1eccf28SAndroid Build Coastguard Worker     for (int i = 0; i < MAX_REPLACEABLES; i ++) {
587*e1eccf28SAndroid Build Coastguard Worker         bool patternFound = inlineStr.find(kRSTypePatterns[i]) != string::npos;
588*e1eccf28SAndroid Build Coastguard Worker 
589*e1eccf28SAndroid Build Coastguard Worker         if (patternFound) {
590*e1eccf28SAndroid Build Coastguard Worker             if (!allow) {
591*e1eccf28SAndroid Build Coastguard Worker                 scanner->error() << "RST_i pattern not allowed here\n";
592*e1eccf28SAndroid Build Coastguard Worker             }
593*e1eccf28SAndroid Build Coastguard Worker             else if (mIsRSTAllowed[i] == false) {
594*e1eccf28SAndroid Build Coastguard Worker                 scanner->error() << "Found pattern \"" << kRSTypePatterns[i]
595*e1eccf28SAndroid Build Coastguard Worker                     << "\" in spec.  But some entry in the corresponding"
596*e1eccf28SAndroid Build Coastguard Worker                     << " parameter list cannot be translated to an RS type\n";
597*e1eccf28SAndroid Build Coastguard Worker             }
598*e1eccf28SAndroid Build Coastguard Worker         }
599*e1eccf28SAndroid Build Coastguard Worker     }
600*e1eccf28SAndroid Build Coastguard Worker }
601*e1eccf28SAndroid Build Coastguard Worker 
scanFunctionSpecification(Scanner * scanner,SpecFile * specFile,unsigned int maxApiLevel)602*e1eccf28SAndroid Build Coastguard Worker void FunctionSpecification::scanFunctionSpecification(Scanner* scanner, SpecFile* specFile,
603*e1eccf28SAndroid Build Coastguard Worker                                                       unsigned int maxApiLevel) {
604*e1eccf28SAndroid Build Coastguard Worker     // Some functions like convert have # part of the name.  Truncate at that point.
605*e1eccf28SAndroid Build Coastguard Worker     const string& unexpandedName = scanner->getValue();
606*e1eccf28SAndroid Build Coastguard Worker     string name = unexpandedName;
607*e1eccf28SAndroid Build Coastguard Worker     size_t p = name.find('#');
608*e1eccf28SAndroid Build Coastguard Worker     if (p != string::npos) {
609*e1eccf28SAndroid Build Coastguard Worker         if (p > 0 && name[p - 1] == '_') {
610*e1eccf28SAndroid Build Coastguard Worker             p--;
611*e1eccf28SAndroid Build Coastguard Worker         }
612*e1eccf28SAndroid Build Coastguard Worker         name.erase(p);
613*e1eccf28SAndroid Build Coastguard Worker     }
614*e1eccf28SAndroid Build Coastguard Worker     VersionInfo info;
615*e1eccf28SAndroid Build Coastguard Worker     if (!info.scan(scanner, maxApiLevel)) {
616*e1eccf28SAndroid Build Coastguard Worker         cout << "Skipping some " << name << " definitions.\n";
617*e1eccf28SAndroid Build Coastguard Worker         scanner->skipUntilTag("end:");
618*e1eccf28SAndroid Build Coastguard Worker         return;
619*e1eccf28SAndroid Build Coastguard Worker     }
620*e1eccf28SAndroid Build Coastguard Worker 
621*e1eccf28SAndroid Build Coastguard Worker     bool created = false;
622*e1eccf28SAndroid Build Coastguard Worker     Function* function = systemSpecification.findOrCreateFunction(name, &created);
623*e1eccf28SAndroid Build Coastguard Worker     FunctionSpecification* spec = new FunctionSpecification(function);
624*e1eccf28SAndroid Build Coastguard Worker     function->addSpecification(spec);
625*e1eccf28SAndroid Build Coastguard Worker     function->updateFinalVersion(info);
626*e1eccf28SAndroid Build Coastguard Worker     specFile->addFunctionSpecification(spec, created);
627*e1eccf28SAndroid Build Coastguard Worker 
628*e1eccf28SAndroid Build Coastguard Worker     spec->mUnexpandedName = unexpandedName;
629*e1eccf28SAndroid Build Coastguard Worker     spec->mTest = "scalar";  // default
630*e1eccf28SAndroid Build Coastguard Worker     spec->mVersionInfo = info;
631*e1eccf28SAndroid Build Coastguard Worker 
632*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("internal:")) {
633*e1eccf28SAndroid Build Coastguard Worker         spec->mInternal = (scanner->getValue() == "true");
634*e1eccf28SAndroid Build Coastguard Worker     }
635*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("intrinsic:")) {
636*e1eccf28SAndroid Build Coastguard Worker         spec->mIntrinsic = (scanner->getValue() == "true");
637*e1eccf28SAndroid Build Coastguard Worker     }
638*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("attrib:")) {
639*e1eccf28SAndroid Build Coastguard Worker         spec->mAttribute = scanner->getValue();
640*e1eccf28SAndroid Build Coastguard Worker     }
641*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("w:")) {
642*e1eccf28SAndroid Build Coastguard Worker         vector<string> t;
643*e1eccf28SAndroid Build Coastguard Worker         if (scanner->getValue().find("1") != string::npos) {
644*e1eccf28SAndroid Build Coastguard Worker             t.push_back("");
645*e1eccf28SAndroid Build Coastguard Worker         }
646*e1eccf28SAndroid Build Coastguard Worker         if (scanner->getValue().find("2") != string::npos) {
647*e1eccf28SAndroid Build Coastguard Worker             t.push_back("2");
648*e1eccf28SAndroid Build Coastguard Worker         }
649*e1eccf28SAndroid Build Coastguard Worker         if (scanner->getValue().find("3") != string::npos) {
650*e1eccf28SAndroid Build Coastguard Worker             t.push_back("3");
651*e1eccf28SAndroid Build Coastguard Worker         }
652*e1eccf28SAndroid Build Coastguard Worker         if (scanner->getValue().find("4") != string::npos) {
653*e1eccf28SAndroid Build Coastguard Worker             t.push_back("4");
654*e1eccf28SAndroid Build Coastguard Worker         }
655*e1eccf28SAndroid Build Coastguard Worker         spec->mReplaceables.push_back(t);
656*e1eccf28SAndroid Build Coastguard Worker         // RST_i pattern not applicable for width.
657*e1eccf28SAndroid Build Coastguard Worker         spec->mIsRSTAllowed.push_back(false);
658*e1eccf28SAndroid Build Coastguard Worker     }
659*e1eccf28SAndroid Build Coastguard Worker 
660*e1eccf28SAndroid Build Coastguard Worker     while (scanner->findOptionalTag("t:")) {
661*e1eccf28SAndroid Build Coastguard Worker         spec->mReplaceables.push_back(convertToTypeVector(scanner->getValue()));
662*e1eccf28SAndroid Build Coastguard Worker         spec->mIsRSTAllowed.push_back(isRSTValid(spec->mReplaceables.back()));
663*e1eccf28SAndroid Build Coastguard Worker     }
664*e1eccf28SAndroid Build Coastguard Worker 
665*e1eccf28SAndroid Build Coastguard Worker     // Disallow RST_* pattern in function name
666*e1eccf28SAndroid Build Coastguard Worker     // FIXME the line number for this error would be wrong
667*e1eccf28SAndroid Build Coastguard Worker     spec->checkRSTPatternValidity(unexpandedName, false, scanner);
668*e1eccf28SAndroid Build Coastguard Worker 
669*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findTag("ret:")) {
670*e1eccf28SAndroid Build Coastguard Worker         ParameterEntry* p = scanner->parseArgString(true);
671*e1eccf28SAndroid Build Coastguard Worker         function->addReturn(p, scanner);
672*e1eccf28SAndroid Build Coastguard Worker         spec->mReturn = p;
673*e1eccf28SAndroid Build Coastguard Worker 
674*e1eccf28SAndroid Build Coastguard Worker         // Disallow RST_* pattern in return type
675*e1eccf28SAndroid Build Coastguard Worker         spec->checkRSTPatternValidity(p->type, false, scanner);
676*e1eccf28SAndroid Build Coastguard Worker     }
677*e1eccf28SAndroid Build Coastguard Worker     while (scanner->findOptionalTag("arg:")) {
678*e1eccf28SAndroid Build Coastguard Worker         ParameterEntry* p = scanner->parseArgString(false);
679*e1eccf28SAndroid Build Coastguard Worker         function->addParameter(p, scanner);
680*e1eccf28SAndroid Build Coastguard Worker         spec->mParameters.push_back(p);
681*e1eccf28SAndroid Build Coastguard Worker 
682*e1eccf28SAndroid Build Coastguard Worker         // Disallow RST_* pattern in parameter type or testOption
683*e1eccf28SAndroid Build Coastguard Worker         spec->checkRSTPatternValidity(p->type, false, scanner);
684*e1eccf28SAndroid Build Coastguard Worker         spec->checkRSTPatternValidity(p->testOption, false, scanner);
685*e1eccf28SAndroid Build Coastguard Worker     }
686*e1eccf28SAndroid Build Coastguard Worker 
687*e1eccf28SAndroid Build Coastguard Worker     function->scanDocumentationTags(scanner, created, specFile);
688*e1eccf28SAndroid Build Coastguard Worker 
689*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("inline:")) {
690*e1eccf28SAndroid Build Coastguard Worker         scanner->checkNoValue();
691*e1eccf28SAndroid Build Coastguard Worker         while (scanner->findOptionalTag("")) {
692*e1eccf28SAndroid Build Coastguard Worker             spec->mInline.push_back(scanner->getValue());
693*e1eccf28SAndroid Build Coastguard Worker 
694*e1eccf28SAndroid Build Coastguard Worker             // Allow RST_* pattern in inline definitions
695*e1eccf28SAndroid Build Coastguard Worker             spec->checkRSTPatternValidity(spec->mInline.back(), true, scanner);
696*e1eccf28SAndroid Build Coastguard Worker         }
697*e1eccf28SAndroid Build Coastguard Worker     }
698*e1eccf28SAndroid Build Coastguard Worker     if (scanner->findOptionalTag("test:")) {
699*e1eccf28SAndroid Build Coastguard Worker         spec->parseTest(scanner);
700*e1eccf28SAndroid Build Coastguard Worker     }
701*e1eccf28SAndroid Build Coastguard Worker 
702*e1eccf28SAndroid Build Coastguard Worker     scanner->findTag("end:");
703*e1eccf28SAndroid Build Coastguard Worker 
704*e1eccf28SAndroid Build Coastguard Worker     spec->createPermutations(function, scanner);
705*e1eccf28SAndroid Build Coastguard Worker }
706*e1eccf28SAndroid Build Coastguard Worker 
FunctionPermutation(Function * func,FunctionSpecification * spec,int replacementIndexes[MAX_REPLACEABLES],Scanner * scanner)707*e1eccf28SAndroid Build Coastguard Worker FunctionPermutation::FunctionPermutation(Function* func, FunctionSpecification* spec,
708*e1eccf28SAndroid Build Coastguard Worker                                          int replacementIndexes[MAX_REPLACEABLES], Scanner* scanner)
709*e1eccf28SAndroid Build Coastguard Worker     : mReturn(nullptr), mInputCount(0), mOutputCount(0) {
710*e1eccf28SAndroid Build Coastguard Worker     // We expand the strings now to make capitalization easier.  The previous code preserved
711*e1eccf28SAndroid Build Coastguard Worker     // the #n
712*e1eccf28SAndroid Build Coastguard Worker     // markers just before emitting, which made capitalization difficult.
713*e1eccf28SAndroid Build Coastguard Worker     mName = spec->getName(replacementIndexes);
714*e1eccf28SAndroid Build Coastguard Worker     mNameTrunk = func->getName();
715*e1eccf28SAndroid Build Coastguard Worker     mTest = spec->getTest();
716*e1eccf28SAndroid Build Coastguard Worker     mPrecisionLimit = spec->getPrecisionLimit();
717*e1eccf28SAndroid Build Coastguard Worker     spec->getInlines(replacementIndexes, &mInline);
718*e1eccf28SAndroid Build Coastguard Worker 
719*e1eccf28SAndroid Build Coastguard Worker     mHasFloatAnswers = false;
720*e1eccf28SAndroid Build Coastguard Worker     for (size_t i = 0; i < spec->getNumberOfParams(); i++) {
721*e1eccf28SAndroid Build Coastguard Worker         string type, name, testOption;
722*e1eccf28SAndroid Build Coastguard Worker         int lineNumber = 0;
723*e1eccf28SAndroid Build Coastguard Worker         spec->getParam(i, replacementIndexes, &type, &name, &testOption, &lineNumber);
724*e1eccf28SAndroid Build Coastguard Worker         ParameterDefinition* def = new ParameterDefinition();
725*e1eccf28SAndroid Build Coastguard Worker         def->parseParameterDefinition(type, name, testOption, lineNumber, false, scanner);
726*e1eccf28SAndroid Build Coastguard Worker         if (def->isOutParameter) {
727*e1eccf28SAndroid Build Coastguard Worker             mOutputCount++;
728*e1eccf28SAndroid Build Coastguard Worker         } else {
729*e1eccf28SAndroid Build Coastguard Worker             mInputCount++;
730*e1eccf28SAndroid Build Coastguard Worker         }
731*e1eccf28SAndroid Build Coastguard Worker 
732*e1eccf28SAndroid Build Coastguard Worker         if (def->typeIndex < 0 && mTest != "none") {
733*e1eccf28SAndroid Build Coastguard Worker             scanner->error(lineNumber)
734*e1eccf28SAndroid Build Coastguard Worker                         << "Could not find " << def->rsBaseType
735*e1eccf28SAndroid Build Coastguard Worker                         << " while generating automated tests.  Use test: none if not needed.\n";
736*e1eccf28SAndroid Build Coastguard Worker         }
737*e1eccf28SAndroid Build Coastguard Worker         if (def->isOutParameter && def->isFloatType) {
738*e1eccf28SAndroid Build Coastguard Worker             mHasFloatAnswers = true;
739*e1eccf28SAndroid Build Coastguard Worker         }
740*e1eccf28SAndroid Build Coastguard Worker         mParams.push_back(def);
741*e1eccf28SAndroid Build Coastguard Worker     }
742*e1eccf28SAndroid Build Coastguard Worker 
743*e1eccf28SAndroid Build Coastguard Worker     string retType;
744*e1eccf28SAndroid Build Coastguard Worker     int lineNumber = 0;
745*e1eccf28SAndroid Build Coastguard Worker     spec->getReturn(replacementIndexes, &retType, &lineNumber);
746*e1eccf28SAndroid Build Coastguard Worker     if (!retType.empty()) {
747*e1eccf28SAndroid Build Coastguard Worker         mReturn = new ParameterDefinition();
748*e1eccf28SAndroid Build Coastguard Worker         mReturn->parseParameterDefinition(retType, "", "", lineNumber, true, scanner);
749*e1eccf28SAndroid Build Coastguard Worker         if (mReturn->isFloatType) {
750*e1eccf28SAndroid Build Coastguard Worker             mHasFloatAnswers = true;
751*e1eccf28SAndroid Build Coastguard Worker         }
752*e1eccf28SAndroid Build Coastguard Worker         mOutputCount++;
753*e1eccf28SAndroid Build Coastguard Worker     }
754*e1eccf28SAndroid Build Coastguard Worker }
755*e1eccf28SAndroid Build Coastguard Worker 
~FunctionPermutation()756*e1eccf28SAndroid Build Coastguard Worker FunctionPermutation::~FunctionPermutation() {
757*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mParams) {
758*e1eccf28SAndroid Build Coastguard Worker         delete i;
759*e1eccf28SAndroid Build Coastguard Worker     }
760*e1eccf28SAndroid Build Coastguard Worker     delete mReturn;
761*e1eccf28SAndroid Build Coastguard Worker }
762*e1eccf28SAndroid Build Coastguard Worker 
SpecFile(const string & specFileName)763*e1eccf28SAndroid Build Coastguard Worker SpecFile::SpecFile(const string& specFileName) : mSpecFileName(specFileName) {
764*e1eccf28SAndroid Build Coastguard Worker     string core = mSpecFileName;
765*e1eccf28SAndroid Build Coastguard Worker     // Remove .spec
766*e1eccf28SAndroid Build Coastguard Worker     size_t l = core.length();
767*e1eccf28SAndroid Build Coastguard Worker     const char SPEC[] = ".spec";
768*e1eccf28SAndroid Build Coastguard Worker     const int SPEC_SIZE = sizeof(SPEC) - 1;
769*e1eccf28SAndroid Build Coastguard Worker     const int start = l - SPEC_SIZE;
770*e1eccf28SAndroid Build Coastguard Worker     if (start >= 0 && core.compare(start, SPEC_SIZE, SPEC) == 0) {
771*e1eccf28SAndroid Build Coastguard Worker         core.erase(start);
772*e1eccf28SAndroid Build Coastguard Worker     }
773*e1eccf28SAndroid Build Coastguard Worker 
774*e1eccf28SAndroid Build Coastguard Worker     // The header file name should have the same base but with a ".rsh" extension.
775*e1eccf28SAndroid Build Coastguard Worker     mHeaderFileName = core + ".rsh";
776*e1eccf28SAndroid Build Coastguard Worker     mDetailedDocumentationUrl = core + ".html";
777*e1eccf28SAndroid Build Coastguard Worker }
778*e1eccf28SAndroid Build Coastguard Worker 
addConstantSpecification(ConstantSpecification * spec,bool hasDocumentation)779*e1eccf28SAndroid Build Coastguard Worker void SpecFile::addConstantSpecification(ConstantSpecification* spec, bool hasDocumentation) {
780*e1eccf28SAndroid Build Coastguard Worker     mConstantSpecificationsList.push_back(spec);
781*e1eccf28SAndroid Build Coastguard Worker     if (hasDocumentation) {
782*e1eccf28SAndroid Build Coastguard Worker         Constant* constant = spec->getConstant();
783*e1eccf28SAndroid Build Coastguard Worker         mDocumentedConstants.insert(pair<string, Constant*>(constant->getName(), constant));
784*e1eccf28SAndroid Build Coastguard Worker     }
785*e1eccf28SAndroid Build Coastguard Worker }
786*e1eccf28SAndroid Build Coastguard Worker 
addTypeSpecification(TypeSpecification * spec,bool hasDocumentation)787*e1eccf28SAndroid Build Coastguard Worker void SpecFile::addTypeSpecification(TypeSpecification* spec, bool hasDocumentation) {
788*e1eccf28SAndroid Build Coastguard Worker     mTypeSpecificationsList.push_back(spec);
789*e1eccf28SAndroid Build Coastguard Worker     if (hasDocumentation) {
790*e1eccf28SAndroid Build Coastguard Worker         Type* type = spec->getType();
791*e1eccf28SAndroid Build Coastguard Worker         mDocumentedTypes.insert(pair<string, Type*>(type->getName(), type));
792*e1eccf28SAndroid Build Coastguard Worker     }
793*e1eccf28SAndroid Build Coastguard Worker }
794*e1eccf28SAndroid Build Coastguard Worker 
addFunctionSpecification(FunctionSpecification * spec,bool hasDocumentation)795*e1eccf28SAndroid Build Coastguard Worker void SpecFile::addFunctionSpecification(FunctionSpecification* spec, bool hasDocumentation) {
796*e1eccf28SAndroid Build Coastguard Worker     mFunctionSpecificationsList.push_back(spec);
797*e1eccf28SAndroid Build Coastguard Worker     if (hasDocumentation) {
798*e1eccf28SAndroid Build Coastguard Worker         Function* function = spec->getFunction();
799*e1eccf28SAndroid Build Coastguard Worker         mDocumentedFunctions.insert(pair<string, Function*>(function->getName(), function));
800*e1eccf28SAndroid Build Coastguard Worker     }
801*e1eccf28SAndroid Build Coastguard Worker }
802*e1eccf28SAndroid Build Coastguard Worker 
803*e1eccf28SAndroid Build Coastguard Worker // Read the specification, adding the definitions to the global functions map.
readSpecFile(unsigned int maxApiLevel)804*e1eccf28SAndroid Build Coastguard Worker bool SpecFile::readSpecFile(unsigned int maxApiLevel) {
805*e1eccf28SAndroid Build Coastguard Worker     FILE* specFile = fopen(mSpecFileName.c_str(), "rte");
806*e1eccf28SAndroid Build Coastguard Worker     if (!specFile) {
807*e1eccf28SAndroid Build Coastguard Worker         cerr << "Error opening input file: " << mSpecFileName << "\n";
808*e1eccf28SAndroid Build Coastguard Worker         return false;
809*e1eccf28SAndroid Build Coastguard Worker     }
810*e1eccf28SAndroid Build Coastguard Worker 
811*e1eccf28SAndroid Build Coastguard Worker     Scanner scanner(mSpecFileName, specFile);
812*e1eccf28SAndroid Build Coastguard Worker 
813*e1eccf28SAndroid Build Coastguard Worker     // Scan the header that should start the file.
814*e1eccf28SAndroid Build Coastguard Worker     scanner.skipBlankEntries();
815*e1eccf28SAndroid Build Coastguard Worker     if (scanner.findTag("header:")) {
816*e1eccf28SAndroid Build Coastguard Worker         if (scanner.findTag("summary:")) {
817*e1eccf28SAndroid Build Coastguard Worker             mBriefDescription = scanner.getValue();
818*e1eccf28SAndroid Build Coastguard Worker         }
819*e1eccf28SAndroid Build Coastguard Worker         if (scanner.findTag("description:")) {
820*e1eccf28SAndroid Build Coastguard Worker             scanner.checkNoValue();
821*e1eccf28SAndroid Build Coastguard Worker             while (scanner.findOptionalTag("")) {
822*e1eccf28SAndroid Build Coastguard Worker                 mFullDescription.push_back(scanner.getValue());
823*e1eccf28SAndroid Build Coastguard Worker             }
824*e1eccf28SAndroid Build Coastguard Worker         }
825*e1eccf28SAndroid Build Coastguard Worker         if (scanner.findOptionalTag("include:")) {
826*e1eccf28SAndroid Build Coastguard Worker             scanner.checkNoValue();
827*e1eccf28SAndroid Build Coastguard Worker             while (scanner.findOptionalTag("")) {
828*e1eccf28SAndroid Build Coastguard Worker                 mVerbatimInclude.push_back(scanner.getValue());
829*e1eccf28SAndroid Build Coastguard Worker             }
830*e1eccf28SAndroid Build Coastguard Worker         }
831*e1eccf28SAndroid Build Coastguard Worker         scanner.findTag("end:");
832*e1eccf28SAndroid Build Coastguard Worker     }
833*e1eccf28SAndroid Build Coastguard Worker 
834*e1eccf28SAndroid Build Coastguard Worker     while (1) {
835*e1eccf28SAndroid Build Coastguard Worker         scanner.skipBlankEntries();
836*e1eccf28SAndroid Build Coastguard Worker         if (scanner.atEnd()) {
837*e1eccf28SAndroid Build Coastguard Worker             break;
838*e1eccf28SAndroid Build Coastguard Worker         }
839*e1eccf28SAndroid Build Coastguard Worker         const string tag = scanner.getNextTag();
840*e1eccf28SAndroid Build Coastguard Worker         if (tag == "function:") {
841*e1eccf28SAndroid Build Coastguard Worker             FunctionSpecification::scanFunctionSpecification(&scanner, this, maxApiLevel);
842*e1eccf28SAndroid Build Coastguard Worker         } else if (tag == "type:") {
843*e1eccf28SAndroid Build Coastguard Worker             TypeSpecification::scanTypeSpecification(&scanner, this, maxApiLevel);
844*e1eccf28SAndroid Build Coastguard Worker         } else if (tag == "constant:") {
845*e1eccf28SAndroid Build Coastguard Worker             ConstantSpecification::scanConstantSpecification(&scanner, this, maxApiLevel);
846*e1eccf28SAndroid Build Coastguard Worker         } else {
847*e1eccf28SAndroid Build Coastguard Worker             scanner.error() << "Expected function:, type:, or constant:.  Found: " << tag << "\n";
848*e1eccf28SAndroid Build Coastguard Worker             return false;
849*e1eccf28SAndroid Build Coastguard Worker         }
850*e1eccf28SAndroid Build Coastguard Worker     }
851*e1eccf28SAndroid Build Coastguard Worker 
852*e1eccf28SAndroid Build Coastguard Worker     fclose(specFile);
853*e1eccf28SAndroid Build Coastguard Worker     return scanner.getErrorCount() == 0;
854*e1eccf28SAndroid Build Coastguard Worker }
855*e1eccf28SAndroid Build Coastguard Worker 
~SystemSpecification()856*e1eccf28SAndroid Build Coastguard Worker SystemSpecification::~SystemSpecification() {
857*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mConstants) {
858*e1eccf28SAndroid Build Coastguard Worker         delete i.second;
859*e1eccf28SAndroid Build Coastguard Worker     }
860*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mTypes) {
861*e1eccf28SAndroid Build Coastguard Worker         delete i.second;
862*e1eccf28SAndroid Build Coastguard Worker     }
863*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mFunctions) {
864*e1eccf28SAndroid Build Coastguard Worker         delete i.second;
865*e1eccf28SAndroid Build Coastguard Worker     }
866*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mSpecFiles) {
867*e1eccf28SAndroid Build Coastguard Worker         delete i;
868*e1eccf28SAndroid Build Coastguard Worker     }
869*e1eccf28SAndroid Build Coastguard Worker }
870*e1eccf28SAndroid Build Coastguard Worker 
871*e1eccf28SAndroid Build Coastguard Worker // Returns the named entry in the map.  Creates it if it's not there.
872*e1eccf28SAndroid Build Coastguard Worker template <class T>
findOrCreate(const string & name,map<string,T * > * map,bool * created)873*e1eccf28SAndroid Build Coastguard Worker T* findOrCreate(const string& name, map<string, T*>* map, bool* created) {
874*e1eccf28SAndroid Build Coastguard Worker     auto iter = map->find(name);
875*e1eccf28SAndroid Build Coastguard Worker     if (iter != map->end()) {
876*e1eccf28SAndroid Build Coastguard Worker         *created = false;
877*e1eccf28SAndroid Build Coastguard Worker         return iter->second;
878*e1eccf28SAndroid Build Coastguard Worker     }
879*e1eccf28SAndroid Build Coastguard Worker     *created = true;
880*e1eccf28SAndroid Build Coastguard Worker     T* f = new T(name);
881*e1eccf28SAndroid Build Coastguard Worker     map->insert(pair<string, T*>(name, f));
882*e1eccf28SAndroid Build Coastguard Worker     return f;
883*e1eccf28SAndroid Build Coastguard Worker }
884*e1eccf28SAndroid Build Coastguard Worker 
findOrCreateConstant(const string & name,bool * created)885*e1eccf28SAndroid Build Coastguard Worker Constant* SystemSpecification::findOrCreateConstant(const string& name, bool* created) {
886*e1eccf28SAndroid Build Coastguard Worker     return findOrCreate<Constant>(name, &mConstants, created);
887*e1eccf28SAndroid Build Coastguard Worker }
888*e1eccf28SAndroid Build Coastguard Worker 
findOrCreateType(const string & name,bool * created)889*e1eccf28SAndroid Build Coastguard Worker Type* SystemSpecification::findOrCreateType(const string& name, bool* created) {
890*e1eccf28SAndroid Build Coastguard Worker     return findOrCreate<Type>(name, &mTypes, created);
891*e1eccf28SAndroid Build Coastguard Worker }
892*e1eccf28SAndroid Build Coastguard Worker 
findOrCreateFunction(const string & name,bool * created)893*e1eccf28SAndroid Build Coastguard Worker Function* SystemSpecification::findOrCreateFunction(const string& name, bool* created) {
894*e1eccf28SAndroid Build Coastguard Worker     return findOrCreate<Function>(name, &mFunctions, created);
895*e1eccf28SAndroid Build Coastguard Worker }
896*e1eccf28SAndroid Build Coastguard Worker 
readSpecFile(const string & fileName,unsigned int maxApiLevel)897*e1eccf28SAndroid Build Coastguard Worker bool SystemSpecification::readSpecFile(const string& fileName, unsigned int maxApiLevel) {
898*e1eccf28SAndroid Build Coastguard Worker     SpecFile* spec = new SpecFile(fileName);
899*e1eccf28SAndroid Build Coastguard Worker     if (!spec->readSpecFile(maxApiLevel)) {
900*e1eccf28SAndroid Build Coastguard Worker         cerr << fileName << ": Failed to parse.\n";
901*e1eccf28SAndroid Build Coastguard Worker         return false;
902*e1eccf28SAndroid Build Coastguard Worker     }
903*e1eccf28SAndroid Build Coastguard Worker     mSpecFiles.push_back(spec);
904*e1eccf28SAndroid Build Coastguard Worker     return true;
905*e1eccf28SAndroid Build Coastguard Worker }
906*e1eccf28SAndroid Build Coastguard Worker 
907*e1eccf28SAndroid Build Coastguard Worker 
updateMaxApiLevel(const VersionInfo & info,unsigned int * maxApiLevel)908*e1eccf28SAndroid Build Coastguard Worker static void updateMaxApiLevel(const VersionInfo& info, unsigned int* maxApiLevel) {
909*e1eccf28SAndroid Build Coastguard Worker     if (info.minVersion == VersionInfo::kUnreleasedVersion) {
910*e1eccf28SAndroid Build Coastguard Worker         // Ignore development API level in consideration of max API level.
911*e1eccf28SAndroid Build Coastguard Worker         return;
912*e1eccf28SAndroid Build Coastguard Worker     }
913*e1eccf28SAndroid Build Coastguard Worker     *maxApiLevel = max(*maxApiLevel, max(info.minVersion, info.maxVersion));
914*e1eccf28SAndroid Build Coastguard Worker }
915*e1eccf28SAndroid Build Coastguard Worker 
getMaximumApiLevel()916*e1eccf28SAndroid Build Coastguard Worker unsigned int SystemSpecification::getMaximumApiLevel() {
917*e1eccf28SAndroid Build Coastguard Worker     unsigned int maxApiLevel = 0;
918*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mConstants) {
919*e1eccf28SAndroid Build Coastguard Worker         for (auto j: i.second->getSpecifications()) {
920*e1eccf28SAndroid Build Coastguard Worker             updateMaxApiLevel(j->getVersionInfo(), &maxApiLevel);
921*e1eccf28SAndroid Build Coastguard Worker         }
922*e1eccf28SAndroid Build Coastguard Worker     }
923*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mTypes) {
924*e1eccf28SAndroid Build Coastguard Worker         for (auto j: i.second->getSpecifications()) {
925*e1eccf28SAndroid Build Coastguard Worker             updateMaxApiLevel(j->getVersionInfo(), &maxApiLevel);
926*e1eccf28SAndroid Build Coastguard Worker         }
927*e1eccf28SAndroid Build Coastguard Worker     }
928*e1eccf28SAndroid Build Coastguard Worker     for (auto i : mFunctions) {
929*e1eccf28SAndroid Build Coastguard Worker         for (auto j: i.second->getSpecifications()) {
930*e1eccf28SAndroid Build Coastguard Worker             updateMaxApiLevel(j->getVersionInfo(), &maxApiLevel);
931*e1eccf28SAndroid Build Coastguard Worker         }
932*e1eccf28SAndroid Build Coastguard Worker     }
933*e1eccf28SAndroid Build Coastguard Worker     return maxApiLevel;
934*e1eccf28SAndroid Build Coastguard Worker }
935*e1eccf28SAndroid Build Coastguard Worker 
generateFiles(unsigned int maxApiLevel) const936*e1eccf28SAndroid Build Coastguard Worker bool SystemSpecification::generateFiles(unsigned int maxApiLevel) const {
937*e1eccf28SAndroid Build Coastguard Worker     bool success = generateHeaderFiles("include") &&
938*e1eccf28SAndroid Build Coastguard Worker                    generateDocumentation("docs") &&
939*e1eccf28SAndroid Build Coastguard Worker                    generateTestFiles("test", maxApiLevel) &&
940*e1eccf28SAndroid Build Coastguard Worker                    generateRSFunctionsList("slangtest", maxApiLevel);
941*e1eccf28SAndroid Build Coastguard Worker     if (success) {
942*e1eccf28SAndroid Build Coastguard Worker         cout << "Successfully processed " << mTypes.size() << " types, " << mConstants.size()
943*e1eccf28SAndroid Build Coastguard Worker              << " constants, and " << mFunctions.size() << " functions.\n";
944*e1eccf28SAndroid Build Coastguard Worker     }
945*e1eccf28SAndroid Build Coastguard Worker     return success;
946*e1eccf28SAndroid Build Coastguard Worker }
947*e1eccf28SAndroid Build Coastguard Worker 
getHtmlAnchor(const string & name) const948*e1eccf28SAndroid Build Coastguard Worker string SystemSpecification::getHtmlAnchor(const string& name) const {
949*e1eccf28SAndroid Build Coastguard Worker     Definition* d = nullptr;
950*e1eccf28SAndroid Build Coastguard Worker     auto c = mConstants.find(name);
951*e1eccf28SAndroid Build Coastguard Worker     if (c != mConstants.end()) {
952*e1eccf28SAndroid Build Coastguard Worker         d = c->second;
953*e1eccf28SAndroid Build Coastguard Worker     } else {
954*e1eccf28SAndroid Build Coastguard Worker         auto t = mTypes.find(name);
955*e1eccf28SAndroid Build Coastguard Worker         if (t != mTypes.end()) {
956*e1eccf28SAndroid Build Coastguard Worker             d = t->second;
957*e1eccf28SAndroid Build Coastguard Worker         } else {
958*e1eccf28SAndroid Build Coastguard Worker             auto f = mFunctions.find(name);
959*e1eccf28SAndroid Build Coastguard Worker             if (f != mFunctions.end()) {
960*e1eccf28SAndroid Build Coastguard Worker                 d = f->second;
961*e1eccf28SAndroid Build Coastguard Worker             } else {
962*e1eccf28SAndroid Build Coastguard Worker                 return string();
963*e1eccf28SAndroid Build Coastguard Worker             }
964*e1eccf28SAndroid Build Coastguard Worker         }
965*e1eccf28SAndroid Build Coastguard Worker     }
966*e1eccf28SAndroid Build Coastguard Worker     ostringstream stream;
967*e1eccf28SAndroid Build Coastguard Worker     stream << "<a href='" << d->getUrl() << "'>" << name << "</a>";
968*e1eccf28SAndroid Build Coastguard Worker     return stream.str();
969*e1eccf28SAndroid Build Coastguard Worker }
970