blob: 3b794adc6721874ad629ce5cf473012a4102a8af [file] [log] [blame]
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001/*
2 * Copyright (C) 2013 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 <stdio.h>
18#include <cctype>
19#include <cstdlib>
20#include <fstream>
21#include <functional>
22#include <iostream>
23#include <memory>
24#include <sstream>
25#include <strings.h>
26
27#include "Generator.h"
28#include "Scanner.h"
29#include "Specification.h"
30#include "Utilities.h"
31
32using namespace std;
33
34// API level when RenderScript was added.
Yang Ni12398d82015-09-18 14:57:07 -070035const unsigned int MIN_API_LEVEL = 9;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070036
37const NumericalType TYPES[] = {
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -080038 {"f16", "FLOAT_16", "half", "short", FLOATING_POINT, 11, 5},
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070039 {"f32", "FLOAT_32", "float", "float", FLOATING_POINT, 24, 8},
40 {"f64", "FLOAT_64", "double", "double", FLOATING_POINT, 53, 11},
41 {"i8", "SIGNED_8", "char", "byte", SIGNED_INTEGER, 7, 0},
42 {"u8", "UNSIGNED_8", "uchar", "byte", UNSIGNED_INTEGER, 8, 0},
43 {"i16", "SIGNED_16", "short", "short", SIGNED_INTEGER, 15, 0},
44 {"u16", "UNSIGNED_16", "ushort", "short", UNSIGNED_INTEGER, 16, 0},
45 {"i32", "SIGNED_32", "int", "int", SIGNED_INTEGER, 31, 0},
46 {"u32", "UNSIGNED_32", "uint", "int", UNSIGNED_INTEGER, 32, 0},
47 {"i64", "SIGNED_64", "long", "long", SIGNED_INTEGER, 63, 0},
48 {"u64", "UNSIGNED_64", "ulong", "long", UNSIGNED_INTEGER, 64, 0},
49};
50
51const int NUM_TYPES = sizeof(TYPES) / sizeof(TYPES[0]);
52
Yang Ni12398d82015-09-18 14:57:07 -070053static const char kTagUnreleased[] = "UNRELEASED";
54
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -080055// Patterns that get substituted with C type or RS Data type names in function
56// names, arguments, return types, and inlines.
57static const string kCTypePatterns[] = {"#1", "#2", "#3", "#4"};
58static const string kRSTypePatterns[] = {"#RST_1", "#RST_2", "#RST_3", "#RST_4"};
59
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070060// The singleton of the collected information of all the spec files.
61SystemSpecification systemSpecification;
62
63// Returns the index in TYPES for the provided cType
64static int findCType(const string& cType) {
65 for (int i = 0; i < NUM_TYPES; i++) {
66 if (cType == TYPES[i].cType) {
67 return i;
68 }
69 }
70 return -1;
71}
72
73/* Converts a string like "u8, u16" to a vector of "ushort", "uint".
74 * For non-numerical types, we don't need to convert the abbreviation.
75 */
76static vector<string> convertToTypeVector(const string& input) {
77 // First convert the string to an array of strings.
78 vector<string> entries;
79 stringstream stream(input);
80 string entry;
81 while (getline(stream, entry, ',')) {
82 trimSpaces(&entry);
83 entries.push_back(entry);
84 }
85
86 /* Second, we look for present numerical types. We do it this way
87 * so the order of numerical types is always the same, no matter
88 * how specified in the spec file.
89 */
90 vector<string> result;
91 for (auto t : TYPES) {
92 for (auto i = entries.begin(); i != entries.end(); ++i) {
93 if (*i == t.specType) {
94 result.push_back(t.cType);
95 entries.erase(i);
96 break;
97 }
98 }
99 }
100
101 // Add the remaining; they are not numerical types.
102 for (auto s : entries) {
103 result.push_back(s);
104 }
105
106 return result;
107}
108
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -0800109// Returns true if each entry in typeVector is an RS numerical type
110static bool isRSTValid(const vector<string> &typeVector) {
111 for (auto type: typeVector) {
112 if (findCType(type) == -1)
113 return false;
114 }
115 return true;
116}
117
Dean De Leo9309a062015-11-25 13:37:05 +0000118void getVectorSizeAndBaseType(const string& type, string& vectorSize, string& baseType) {
119 vectorSize = "1";
120 baseType = type;
121
122 /* If it's a vector type, we need to split the base type from the size.
123 * We know that's it's a vector type if the last character is a digit and
124 * the rest is an actual base type. We used to only verify the first part,
125 * which created a problem with rs_matrix2x2.
126 */
127 const int last = type.size() - 1;
128 const char lastChar = type[last];
129 if (lastChar >= '0' && lastChar <= '9') {
130 const string trimmed = type.substr(0, last);
131 int i = findCType(trimmed);
132 if (i >= 0) {
133 baseType = trimmed;
134 vectorSize = lastChar;
135 }
136 }
137}
138
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700139void ParameterDefinition::parseParameterDefinition(const string& type, const string& name,
140 const string& testOption, int lineNumber,
141 bool isReturn, Scanner* scanner) {
142 rsType = type;
143 specName = name;
144
145 // Determine if this is an output.
146 isOutParameter = isReturn || charRemoved('*', &rsType);
147
Dean De Leo9309a062015-11-25 13:37:05 +0000148 getVectorSizeAndBaseType(rsType, mVectorSize, rsBaseType);
Jean-Luc Brouillet66fea242015-04-09 16:47:59 -0700149 typeIndex = findCType(rsBaseType);
150
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700151 if (mVectorSize == "3") {
152 vectorWidth = "4";
153 } else {
154 vectorWidth = mVectorSize;
155 }
156
157 /* Create variable names to be used in the java and .rs files. Because x and
158 * y are reserved in .rs files, we prefix variable names with "in" or "out".
159 */
160 if (isOutParameter) {
161 variableName = "out";
162 if (!specName.empty()) {
163 variableName += capitalize(specName);
164 } else if (!isReturn) {
165 scanner->error(lineNumber) << "Should have a name.\n";
166 }
167 } else {
168 variableName = "in";
169 if (specName.empty()) {
170 scanner->error(lineNumber) << "Should have a name.\n";
171 }
172 variableName += capitalize(specName);
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -0800173 doubleVariableName = variableName + "Double";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700174 }
175 rsAllocName = "gAlloc" + capitalize(variableName);
176 javaAllocName = variableName;
177 javaArrayName = "array" + capitalize(javaAllocName);
178
179 // Process the option.
180 undefinedIfOutIsNan = false;
181 compatibleTypeIndex = -1;
182 if (!testOption.empty()) {
183 if (testOption.compare(0, 6, "range(") == 0) {
184 size_t pComma = testOption.find(',');
185 size_t pParen = testOption.find(')');
186 if (pComma == string::npos || pParen == string::npos) {
187 scanner->error(lineNumber) << "Incorrect range " << testOption << "\n";
188 } else {
189 minValue = testOption.substr(6, pComma - 6);
190 maxValue = testOption.substr(pComma + 1, pParen - pComma - 1);
191 }
192 } else if (testOption.compare(0, 6, "above(") == 0) {
193 size_t pParen = testOption.find(')');
194 if (pParen == string::npos) {
195 scanner->error(lineNumber) << "Incorrect testOption " << testOption << "\n";
196 } else {
197 smallerParameter = testOption.substr(6, pParen - 6);
198 }
199 } else if (testOption.compare(0, 11, "compatible(") == 0) {
200 size_t pParen = testOption.find(')');
201 if (pParen == string::npos) {
202 scanner->error(lineNumber) << "Incorrect testOption " << testOption << "\n";
203 } else {
204 compatibleTypeIndex = findCType(testOption.substr(11, pParen - 11));
205 }
206 } else if (testOption.compare(0, 11, "conditional") == 0) {
207 undefinedIfOutIsNan = true;
208 } else {
209 scanner->error(lineNumber) << "Unrecognized testOption " << testOption << "\n";
210 }
211 }
212
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700213 isFloatType = false;
214 if (typeIndex >= 0) {
215 javaBaseType = TYPES[typeIndex].javaType;
216 specType = TYPES[typeIndex].specType;
217 isFloatType = TYPES[typeIndex].exponentBits > 0;
218 }
219 if (!minValue.empty()) {
220 if (typeIndex < 0 || TYPES[typeIndex].kind != FLOATING_POINT) {
221 scanner->error(lineNumber) << "range(,) is only supported for floating point\n";
222 }
223 }
224}
225
Yang Ni12398d82015-09-18 14:57:07 -0700226bool VersionInfo::scan(Scanner* scanner, unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700227 if (scanner->findOptionalTag("version:")) {
228 const string s = scanner->getValue();
Yang Ni12398d82015-09-18 14:57:07 -0700229 if (s.compare(0, sizeof(kTagUnreleased), kTagUnreleased) == 0) {
230 // The API is still under development and does not have
231 // an official version number.
232 minVersion = maxVersion = kUnreleasedVersion;
233 } else {
234 sscanf(s.c_str(), "%u %u", &minVersion, &maxVersion);
235 if (minVersion && minVersion < MIN_API_LEVEL) {
236 scanner->error() << "Minimum version must >= 9\n";
237 }
238 if (minVersion == MIN_API_LEVEL) {
239 minVersion = 0;
240 }
241 if (maxVersion && maxVersion < MIN_API_LEVEL) {
242 scanner->error() << "Maximum version must >= 9\n";
243 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700244 }
245 }
246 if (scanner->findOptionalTag("size:")) {
247 sscanf(scanner->getValue().c_str(), "%i", &intSize);
248 }
Yang Ni12398d82015-09-18 14:57:07 -0700249
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700250 if (maxVersion > maxApiLevel) {
251 maxVersion = maxApiLevel;
252 }
Yang Ni12398d82015-09-18 14:57:07 -0700253
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700254 return minVersion == 0 || minVersion <= maxApiLevel;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700255}
256
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700257Definition::Definition(const std::string& name)
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700258 : mName(name), mDeprecatedApiLevel(0), mHidden(false), mFinalVersion(-1) {
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700259}
260
261void Definition::updateFinalVersion(const VersionInfo& info) {
262 /* We set it if:
263 * - We have never set mFinalVersion before, or
264 * - The max version is 0, which means we have not expired this API, or
265 * - We have a max that's later than what we currently have.
266 */
267 if (mFinalVersion < 0 || info.maxVersion == 0 ||
268 (mFinalVersion > 0 && info.maxVersion > mFinalVersion)) {
269 mFinalVersion = info.maxVersion;
270 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700271}
272
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700273void Definition::scanDocumentationTags(Scanner* scanner, bool firstOccurence,
274 const SpecFile* specFile) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700275 if (scanner->findOptionalTag("hidden:")) {
276 scanner->checkNoValue();
277 mHidden = true;
278 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700279 if (scanner->findOptionalTag("deprecated:")) {
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700280 string value = scanner->getValue();
281 size_t pComma = value.find(", ");
282 if (pComma != string::npos) {
283 mDeprecatedMessage = value.substr(pComma + 2);
284 value.erase(pComma);
285 }
286 sscanf(value.c_str(), "%i", &mDeprecatedApiLevel);
287 if (mDeprecatedApiLevel <= 0) {
288 scanner->error() << "deprecated entries should have a level > 0\n";
289 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700290 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700291 if (firstOccurence) {
292 if (scanner->findTag("summary:")) {
293 mSummary = scanner->getValue();
294 }
295 if (scanner->findTag("description:")) {
296 scanner->checkNoValue();
297 while (scanner->findOptionalTag("")) {
298 mDescription.push_back(scanner->getValue());
299 }
300 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700301 mUrl = specFile->getDetailedDocumentationUrl() + "#android_rs:" + mName;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700302 } else if (scanner->findOptionalTag("summary:")) {
303 scanner->error() << "Only the first specification should have a summary.\n";
304 }
305}
306
307Constant::~Constant() {
308 for (auto i : mSpecifications) {
309 delete i;
310 }
311}
312
313Type::~Type() {
314 for (auto i : mSpecifications) {
315 delete i;
316 }
317}
318
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700319Function::Function(const string& name) : Definition(name) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700320 mCapitalizedName = capitalize(mName);
321}
322
323Function::~Function() {
324 for (auto i : mSpecifications) {
325 delete i;
326 }
327}
328
329bool Function::someParametersAreDocumented() const {
330 for (auto p : mParameters) {
331 if (!p->documentation.empty()) {
332 return true;
333 }
334 }
335 return false;
336}
337
338void Function::addParameter(ParameterEntry* entry, Scanner* scanner) {
339 for (auto i : mParameters) {
340 if (i->name == entry->name) {
341 // It's a duplicate.
342 if (!entry->documentation.empty()) {
343 scanner->error(entry->lineNumber)
344 << "Only the first occurence of an arg should have the "
345 "documentation.\n";
346 }
347 return;
348 }
349 }
350 mParameters.push_back(entry);
351}
352
353void Function::addReturn(ParameterEntry* entry, Scanner* scanner) {
354 if (entry->documentation.empty()) {
355 return;
356 }
357 if (!mReturnDocumentation.empty()) {
358 scanner->error() << "ret: should be documented only for the first variant\n";
359 }
360 mReturnDocumentation = entry->documentation;
361}
362
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700363void ConstantSpecification::scanConstantSpecification(Scanner* scanner, SpecFile* specFile,
Yang Ni12398d82015-09-18 14:57:07 -0700364 unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700365 string name = scanner->getValue();
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700366 VersionInfo info;
367 if (!info.scan(scanner, maxApiLevel)) {
368 cout << "Skipping some " << name << " definitions.\n";
369 scanner->skipUntilTag("end:");
370 return;
371 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700372
373 bool created = false;
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700374 Constant* constant = systemSpecification.findOrCreateConstant(name, &created);
375 ConstantSpecification* spec = new ConstantSpecification(constant);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700376 constant->addSpecification(spec);
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700377 constant->updateFinalVersion(info);
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700378 specFile->addConstantSpecification(spec, created);
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700379 spec->mVersionInfo = info;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700380
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700381 if (scanner->findTag("value:")) {
382 spec->mValue = scanner->getValue();
383 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700384 constant->scanDocumentationTags(scanner, created, specFile);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700385
386 scanner->findTag("end:");
387}
388
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700389void TypeSpecification::scanTypeSpecification(Scanner* scanner, SpecFile* specFile,
Yang Ni12398d82015-09-18 14:57:07 -0700390 unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700391 string name = scanner->getValue();
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700392 VersionInfo info;
393 if (!info.scan(scanner, maxApiLevel)) {
394 cout << "Skipping some " << name << " definitions.\n";
395 scanner->skipUntilTag("end:");
396 return;
397 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700398
399 bool created = false;
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700400 Type* type = systemSpecification.findOrCreateType(name, &created);
401 TypeSpecification* spec = new TypeSpecification(type);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700402 type->addSpecification(spec);
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700403 type->updateFinalVersion(info);
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700404 specFile->addTypeSpecification(spec, created);
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700405 spec->mVersionInfo = info;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700406
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700407 if (scanner->findOptionalTag("simple:")) {
408 spec->mKind = SIMPLE;
409 spec->mSimpleType = scanner->getValue();
410 }
Stephen Hinesca51c782015-08-25 23:43:34 -0700411 if (scanner->findOptionalTag("rs_object:")) {
412 spec->mKind = RS_OBJECT;
413 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700414 if (scanner->findOptionalTag("struct:")) {
415 spec->mKind = STRUCT;
416 spec->mStructName = scanner->getValue();
417 while (scanner->findOptionalTag("field:")) {
418 string s = scanner->getValue();
419 string comment;
420 scanner->parseDocumentation(&s, &comment);
421 spec->mFields.push_back(s);
422 spec->mFieldComments.push_back(comment);
423 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700424 }
425 if (scanner->findOptionalTag("enum:")) {
426 spec->mKind = ENUM;
427 spec->mEnumName = scanner->getValue();
428 while (scanner->findOptionalTag("value:")) {
429 string s = scanner->getValue();
430 string comment;
431 scanner->parseDocumentation(&s, &comment);
432 spec->mValues.push_back(s);
433 spec->mValueComments.push_back(comment);
434 }
435 }
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700436 if (scanner->findOptionalTag("attrib:")) {
437 spec->mAttribute = scanner->getValue();
438 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700439 type->scanDocumentationTags(scanner, created, specFile);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700440
441 scanner->findTag("end:");
442}
443
444FunctionSpecification::~FunctionSpecification() {
445 for (auto i : mParameters) {
446 delete i;
447 }
448 delete mReturn;
449 for (auto i : mPermutations) {
450 delete i;
451 }
452}
453
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -0800454string FunctionSpecification::expandRSTypeInString(const string &s,
455 const string &pattern,
456 const string &cTypeStr) const {
457 // Find index of numerical type corresponding to cTypeStr. The case where
458 // pattern is found in s but cTypeStr is not a numerical type is checked in
459 // checkRSTPatternValidity.
460 int typeIdx = findCType(cTypeStr);
461 if (typeIdx == -1) {
462 return s;
463 }
464 // If index exists, perform replacement.
465 return stringReplace(s, pattern, TYPES[typeIdx].rsDataType);
466}
467
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700468string FunctionSpecification::expandString(string s,
469 int replacementIndexes[MAX_REPLACEABLES]) const {
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -0800470
471
472 for (unsigned idx = 0; idx < mReplaceables.size(); idx ++) {
473 string toString = mReplaceables[idx][replacementIndexes[idx]];
474
475 // replace #RST_i patterns with RS datatype corresponding to toString
476 s = expandRSTypeInString(s, kRSTypePatterns[idx], toString);
477
478 // replace #i patterns with C type from mReplaceables
479 s = stringReplace(s, kCTypePatterns[idx], toString);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700480 }
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -0800481
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700482 return s;
483}
484
485void FunctionSpecification::expandStringVector(const vector<string>& in,
486 int replacementIndexes[MAX_REPLACEABLES],
487 vector<string>* out) const {
488 out->clear();
489 for (vector<string>::const_iterator iter = in.begin(); iter != in.end(); iter++) {
490 out->push_back(expandString(*iter, replacementIndexes));
491 }
492}
493
494void FunctionSpecification::createPermutations(Function* function, Scanner* scanner) {
495 int start[MAX_REPLACEABLES];
496 int end[MAX_REPLACEABLES];
497 for (int i = 0; i < MAX_REPLACEABLES; i++) {
498 if (i < (int)mReplaceables.size()) {
499 start[i] = 0;
500 end[i] = mReplaceables[i].size();
501 } else {
502 start[i] = -1;
503 end[i] = 0;
504 }
505 }
506 int replacementIndexes[MAX_REPLACEABLES];
507 // TODO: These loops assume that MAX_REPLACEABLES is 4.
508 for (replacementIndexes[3] = start[3]; replacementIndexes[3] < end[3];
509 replacementIndexes[3]++) {
510 for (replacementIndexes[2] = start[2]; replacementIndexes[2] < end[2];
511 replacementIndexes[2]++) {
512 for (replacementIndexes[1] = start[1]; replacementIndexes[1] < end[1];
513 replacementIndexes[1]++) {
514 for (replacementIndexes[0] = start[0]; replacementIndexes[0] < end[0];
515 replacementIndexes[0]++) {
516 auto p = new FunctionPermutation(function, this, replacementIndexes, scanner);
517 mPermutations.push_back(p);
518 }
519 }
520 }
521 }
522}
523
524string FunctionSpecification::getName(int replacementIndexes[MAX_REPLACEABLES]) const {
525 return expandString(mUnexpandedName, replacementIndexes);
526}
527
528void FunctionSpecification::getReturn(int replacementIndexes[MAX_REPLACEABLES],
529 std::string* retType, int* lineNumber) const {
530 *retType = expandString(mReturn->type, replacementIndexes);
531 *lineNumber = mReturn->lineNumber;
532}
533
534void FunctionSpecification::getParam(size_t index, int replacementIndexes[MAX_REPLACEABLES],
535 std::string* type, std::string* name, std::string* testOption,
536 int* lineNumber) const {
537 ParameterEntry* p = mParameters[index];
538 *type = expandString(p->type, replacementIndexes);
539 *name = p->name;
540 *testOption = expandString(p->testOption, replacementIndexes);
541 *lineNumber = p->lineNumber;
542}
543
544void FunctionSpecification::getInlines(int replacementIndexes[MAX_REPLACEABLES],
545 std::vector<std::string>* inlines) const {
546 expandStringVector(mInline, replacementIndexes, inlines);
547}
548
549void FunctionSpecification::parseTest(Scanner* scanner) {
550 const string value = scanner->getValue();
551 if (value == "scalar" || value == "vector" || value == "noverify" || value == "custom" ||
552 value == "none") {
553 mTest = value;
554 } else if (value.compare(0, 7, "limited") == 0) {
555 mTest = "limited";
556 if (value.compare(7, 1, "(") == 0) {
557 size_t pParen = value.find(')');
558 if (pParen == string::npos) {
559 scanner->error() << "Incorrect test: \"" << value << "\"\n";
560 } else {
561 mPrecisionLimit = value.substr(8, pParen - 8);
562 }
563 }
564 } else {
565 scanner->error() << "Unrecognized test option: \"" << value << "\"\n";
566 }
567}
568
Yang Ni12398d82015-09-18 14:57:07 -0700569bool FunctionSpecification::hasTests(unsigned int versionOfTestFiles) const {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700570 if (mVersionInfo.maxVersion != 0 && mVersionInfo.maxVersion < versionOfTestFiles) {
571 return false;
572 }
573 if (mTest == "none") {
574 return false;
575 }
576 return true;
577}
578
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -0800579void FunctionSpecification::checkRSTPatternValidity(const string &inlineStr, bool allow,
580 Scanner *scanner) {
581 for (int i = 0; i < MAX_REPLACEABLES; i ++) {
582 bool patternFound = inlineStr.find(kRSTypePatterns[i]) != string::npos;
583
584 if (patternFound) {
585 if (!allow) {
586 scanner->error() << "RST_i pattern not allowed here\n";
587 }
588 else if (mIsRSTAllowed[i] == false) {
589 scanner->error() << "Found pattern \"" << kRSTypePatterns[i]
590 << "\" in spec. But some entry in the corresponding"
591 << " parameter list cannot be translated to an RS type\n";
592 }
593 }
594 }
595}
596
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700597void FunctionSpecification::scanFunctionSpecification(Scanner* scanner, SpecFile* specFile,
Yang Ni12398d82015-09-18 14:57:07 -0700598 unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700599 // Some functions like convert have # part of the name. Truncate at that point.
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700600 const string& unexpandedName = scanner->getValue();
601 string name = unexpandedName;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700602 size_t p = name.find('#');
603 if (p != string::npos) {
604 if (p > 0 && name[p - 1] == '_') {
605 p--;
606 }
607 name.erase(p);
608 }
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700609 VersionInfo info;
610 if (!info.scan(scanner, maxApiLevel)) {
611 cout << "Skipping some " << name << " definitions.\n";
612 scanner->skipUntilTag("end:");
613 return;
614 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700615
616 bool created = false;
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700617 Function* function = systemSpecification.findOrCreateFunction(name, &created);
618 FunctionSpecification* spec = new FunctionSpecification(function);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700619 function->addSpecification(spec);
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700620 function->updateFinalVersion(info);
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700621 specFile->addFunctionSpecification(spec, created);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700622
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700623 spec->mUnexpandedName = unexpandedName;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700624 spec->mTest = "scalar"; // default
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700625 spec->mVersionInfo = info;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700626
Yang Ni12398d82015-09-18 14:57:07 -0700627 if (scanner->findOptionalTag("internal:")) {
628 spec->mInternal = (scanner->getValue() == "true");
629 }
630 if (scanner->findOptionalTag("intrinsic:")) {
631 spec->mIntrinsic = (scanner->getValue() == "true");
632 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700633 if (scanner->findOptionalTag("attrib:")) {
634 spec->mAttribute = scanner->getValue();
635 }
636 if (scanner->findOptionalTag("w:")) {
637 vector<string> t;
638 if (scanner->getValue().find("1") != string::npos) {
639 t.push_back("");
640 }
641 if (scanner->getValue().find("2") != string::npos) {
642 t.push_back("2");
643 }
644 if (scanner->getValue().find("3") != string::npos) {
645 t.push_back("3");
646 }
647 if (scanner->getValue().find("4") != string::npos) {
648 t.push_back("4");
649 }
650 spec->mReplaceables.push_back(t);
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -0800651 // RST_i pattern not applicable for width.
652 spec->mIsRSTAllowed.push_back(false);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700653 }
654
655 while (scanner->findOptionalTag("t:")) {
656 spec->mReplaceables.push_back(convertToTypeVector(scanner->getValue()));
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -0800657 spec->mIsRSTAllowed.push_back(isRSTValid(spec->mReplaceables.back()));
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700658 }
659
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -0800660 // Disallow RST_* pattern in function name
661 // FIXME the line number for this error would be wrong
662 spec->checkRSTPatternValidity(unexpandedName, false, scanner);
663
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700664 if (scanner->findTag("ret:")) {
665 ParameterEntry* p = scanner->parseArgString(true);
666 function->addReturn(p, scanner);
667 spec->mReturn = p;
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -0800668
669 // Disallow RST_* pattern in return type
670 spec->checkRSTPatternValidity(p->type, false, scanner);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700671 }
672 while (scanner->findOptionalTag("arg:")) {
673 ParameterEntry* p = scanner->parseArgString(false);
674 function->addParameter(p, scanner);
675 spec->mParameters.push_back(p);
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -0800676
677 // Disallow RST_* pattern in parameter type or testOption
678 spec->checkRSTPatternValidity(p->type, false, scanner);
679 spec->checkRSTPatternValidity(p->testOption, false, scanner);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700680 }
681
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700682 function->scanDocumentationTags(scanner, created, specFile);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700683
684 if (scanner->findOptionalTag("inline:")) {
685 scanner->checkNoValue();
686 while (scanner->findOptionalTag("")) {
687 spec->mInline.push_back(scanner->getValue());
Pirama Arumuga Nainar43d758c2015-11-13 12:54:42 -0800688
689 // Allow RST_* pattern in inline definitions
690 spec->checkRSTPatternValidity(spec->mInline.back(), true, scanner);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700691 }
692 }
693 if (scanner->findOptionalTag("test:")) {
694 spec->parseTest(scanner);
695 }
696
697 scanner->findTag("end:");
698
699 spec->createPermutations(function, scanner);
700}
701
702FunctionPermutation::FunctionPermutation(Function* func, FunctionSpecification* spec,
703 int replacementIndexes[MAX_REPLACEABLES], Scanner* scanner)
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700704 : mReturn(nullptr), mInputCount(0), mOutputCount(0) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700705 // We expand the strings now to make capitalization easier. The previous code preserved
706 // the #n
707 // markers just before emitting, which made capitalization difficult.
708 mName = spec->getName(replacementIndexes);
709 mNameTrunk = func->getName();
710 mTest = spec->getTest();
711 mPrecisionLimit = spec->getPrecisionLimit();
712 spec->getInlines(replacementIndexes, &mInline);
713
714 mHasFloatAnswers = false;
715 for (size_t i = 0; i < spec->getNumberOfParams(); i++) {
716 string type, name, testOption;
717 int lineNumber = 0;
718 spec->getParam(i, replacementIndexes, &type, &name, &testOption, &lineNumber);
719 ParameterDefinition* def = new ParameterDefinition();
720 def->parseParameterDefinition(type, name, testOption, lineNumber, false, scanner);
721 if (def->isOutParameter) {
722 mOutputCount++;
723 } else {
724 mInputCount++;
725 }
726
727 if (def->typeIndex < 0 && mTest != "none") {
728 scanner->error(lineNumber)
729 << "Could not find " << def->rsBaseType
730 << " while generating automated tests. Use test: none if not needed.\n";
731 }
732 if (def->isOutParameter && def->isFloatType) {
733 mHasFloatAnswers = true;
734 }
735 mParams.push_back(def);
736 }
737
738 string retType;
739 int lineNumber = 0;
740 spec->getReturn(replacementIndexes, &retType, &lineNumber);
741 if (!retType.empty()) {
742 mReturn = new ParameterDefinition();
743 mReturn->parseParameterDefinition(retType, "", "", lineNumber, true, scanner);
744 if (mReturn->isFloatType) {
745 mHasFloatAnswers = true;
746 }
747 mOutputCount++;
748 }
749}
750
751FunctionPermutation::~FunctionPermutation() {
752 for (auto i : mParams) {
753 delete i;
754 }
755 delete mReturn;
756}
757
758SpecFile::SpecFile(const string& specFileName) : mSpecFileName(specFileName) {
759 string core = mSpecFileName;
760 // Remove .spec
761 size_t l = core.length();
762 const char SPEC[] = ".spec";
763 const int SPEC_SIZE = sizeof(SPEC) - 1;
764 const int start = l - SPEC_SIZE;
765 if (start >= 0 && core.compare(start, SPEC_SIZE, SPEC) == 0) {
766 core.erase(start);
767 }
768
769 // The header file name should have the same base but with a ".rsh" extension.
770 mHeaderFileName = core + ".rsh";
Jean-Luc Brouilletd9935ee2015-04-03 17:27:02 -0700771 mDetailedDocumentationUrl = core + ".html";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700772}
773
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700774void SpecFile::addConstantSpecification(ConstantSpecification* spec, bool hasDocumentation) {
775 mConstantSpecificationsList.push_back(spec);
776 if (hasDocumentation) {
777 Constant* constant = spec->getConstant();
778 mDocumentedConstants.insert(pair<string, Constant*>(constant->getName(), constant));
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700779 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700780}
781
782void SpecFile::addTypeSpecification(TypeSpecification* spec, bool hasDocumentation) {
783 mTypeSpecificationsList.push_back(spec);
784 if (hasDocumentation) {
785 Type* type = spec->getType();
786 mDocumentedTypes.insert(pair<string, Type*>(type->getName(), type));
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700787 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700788}
789
790void SpecFile::addFunctionSpecification(FunctionSpecification* spec, bool hasDocumentation) {
791 mFunctionSpecificationsList.push_back(spec);
792 if (hasDocumentation) {
793 Function* function = spec->getFunction();
794 mDocumentedFunctions.insert(pair<string, Function*>(function->getName(), function));
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700795 }
796}
797
798// Read the specification, adding the definitions to the global functions map.
Yang Ni12398d82015-09-18 14:57:07 -0700799bool SpecFile::readSpecFile(unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700800 FILE* specFile = fopen(mSpecFileName.c_str(), "rt");
801 if (!specFile) {
802 cerr << "Error opening input file: " << mSpecFileName << "\n";
803 return false;
804 }
805
806 Scanner scanner(mSpecFileName, specFile);
807
808 // Scan the header that should start the file.
809 scanner.skipBlankEntries();
810 if (scanner.findTag("header:")) {
811 if (scanner.findTag("summary:")) {
812 mBriefDescription = scanner.getValue();
813 }
814 if (scanner.findTag("description:")) {
815 scanner.checkNoValue();
816 while (scanner.findOptionalTag("")) {
817 mFullDescription.push_back(scanner.getValue());
818 }
819 }
820 if (scanner.findOptionalTag("include:")) {
821 scanner.checkNoValue();
822 while (scanner.findOptionalTag("")) {
823 mVerbatimInclude.push_back(scanner.getValue());
824 }
825 }
826 scanner.findTag("end:");
827 }
828
829 while (1) {
830 scanner.skipBlankEntries();
831 if (scanner.atEnd()) {
832 break;
833 }
834 const string tag = scanner.getNextTag();
835 if (tag == "function:") {
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700836 FunctionSpecification::scanFunctionSpecification(&scanner, this, maxApiLevel);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700837 } else if (tag == "type:") {
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700838 TypeSpecification::scanTypeSpecification(&scanner, this, maxApiLevel);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700839 } else if (tag == "constant:") {
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700840 ConstantSpecification::scanConstantSpecification(&scanner, this, maxApiLevel);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700841 } else {
842 scanner.error() << "Expected function:, type:, or constant:. Found: " << tag << "\n";
843 return false;
844 }
845 }
846
847 fclose(specFile);
848 return scanner.getErrorCount() == 0;
849}
850
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700851SystemSpecification::~SystemSpecification() {
852 for (auto i : mConstants) {
853 delete i.second;
854 }
855 for (auto i : mTypes) {
856 delete i.second;
857 }
858 for (auto i : mFunctions) {
859 delete i.second;
860 }
861 for (auto i : mSpecFiles) {
862 delete i;
863 }
864}
865
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700866// Returns the named entry in the map. Creates it if it's not there.
867template <class T>
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700868T* findOrCreate(const string& name, map<string, T*>* map, bool* created) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700869 auto iter = map->find(name);
870 if (iter != map->end()) {
871 *created = false;
872 return iter->second;
873 }
874 *created = true;
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700875 T* f = new T(name);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700876 map->insert(pair<string, T*>(name, f));
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700877 return f;
878}
879
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700880Constant* SystemSpecification::findOrCreateConstant(const string& name, bool* created) {
881 return findOrCreate<Constant>(name, &mConstants, created);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700882}
883
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700884Type* SystemSpecification::findOrCreateType(const string& name, bool* created) {
885 return findOrCreate<Type>(name, &mTypes, created);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700886}
887
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700888Function* SystemSpecification::findOrCreateFunction(const string& name, bool* created) {
889 return findOrCreate<Function>(name, &mFunctions, created);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700890}
891
Yang Ni12398d82015-09-18 14:57:07 -0700892bool SystemSpecification::readSpecFile(const string& fileName, unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700893 SpecFile* spec = new SpecFile(fileName);
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700894 if (!spec->readSpecFile(maxApiLevel)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700895 cerr << fileName << ": Failed to parse.\n";
896 return false;
897 }
898 mSpecFiles.push_back(spec);
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700899 return true;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700900}
901
Jean-Luc Brouillet36090672015-04-07 15:15:53 -0700902
Yang Ni12398d82015-09-18 14:57:07 -0700903static void updateMaxApiLevel(const VersionInfo& info, unsigned int* maxApiLevel) {
904 if (info.minVersion == VersionInfo::kUnreleasedVersion) {
905 // Ignore development API level in consideration of max API level.
906 return;
907 }
Jean-Luc Brouillet36090672015-04-07 15:15:53 -0700908 *maxApiLevel = max(*maxApiLevel, max(info.minVersion, info.maxVersion));
909}
910
Yang Ni12398d82015-09-18 14:57:07 -0700911unsigned int SystemSpecification::getMaximumApiLevel() {
912 unsigned int maxApiLevel = 0;
Jean-Luc Brouillet36090672015-04-07 15:15:53 -0700913 for (auto i : mConstants) {
914 for (auto j: i.second->getSpecifications()) {
915 updateMaxApiLevel(j->getVersionInfo(), &maxApiLevel);
916 }
917 }
918 for (auto i : mTypes) {
919 for (auto j: i.second->getSpecifications()) {
920 updateMaxApiLevel(j->getVersionInfo(), &maxApiLevel);
921 }
922 }
923 for (auto i : mFunctions) {
924 for (auto j: i.second->getSpecifications()) {
925 updateMaxApiLevel(j->getVersionInfo(), &maxApiLevel);
926 }
927 }
928 return maxApiLevel;
929}
930
Yang Ni12398d82015-09-18 14:57:07 -0700931bool SystemSpecification::generateFiles(bool forVerification, unsigned int maxApiLevel) const {
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700932 bool success = generateHeaderFiles("scriptc") &&
933 generateDocumentation("docs", forVerification) &&
Jean-Luc Brouillet36090672015-04-07 15:15:53 -0700934 generateTestFiles("test", maxApiLevel) &&
935 generateStubsWhiteList("slangtest", maxApiLevel);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700936 if (success) {
937 cout << "Successfully processed " << mTypes.size() << " types, " << mConstants.size()
938 << " constants, and " << mFunctions.size() << " functions.\n";
939 }
940 return success;
941}
942
943string SystemSpecification::getHtmlAnchor(const string& name) const {
944 Definition* d = nullptr;
945 auto c = mConstants.find(name);
946 if (c != mConstants.end()) {
947 d = c->second;
948 } else {
949 auto t = mTypes.find(name);
950 if (t != mTypes.end()) {
951 d = t->second;
952 } else {
953 auto f = mFunctions.find(name);
954 if (f != mFunctions.end()) {
955 d = f->second;
956 } else {
957 return string();
958 }
959 }
960 }
961 ostringstream stream;
962 stream << "<a href='" << d->getUrl() << "'>" << name << "</a>";
963 return stream.str();
964}