blob: 28e5231465ccb5813dba6fc56a32cc3bc63528dd [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[] = {
Jean-Luc Brouillet6119da92015-04-10 09:36:15 -070038 {"f16", "FLOAT_16", "half", "float", 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
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070055// The singleton of the collected information of all the spec files.
56SystemSpecification systemSpecification;
57
58// Returns the index in TYPES for the provided cType
59static int findCType(const string& cType) {
60 for (int i = 0; i < NUM_TYPES; i++) {
61 if (cType == TYPES[i].cType) {
62 return i;
63 }
64 }
65 return -1;
66}
67
68/* Converts a string like "u8, u16" to a vector of "ushort", "uint".
69 * For non-numerical types, we don't need to convert the abbreviation.
70 */
71static vector<string> convertToTypeVector(const string& input) {
72 // First convert the string to an array of strings.
73 vector<string> entries;
74 stringstream stream(input);
75 string entry;
76 while (getline(stream, entry, ',')) {
77 trimSpaces(&entry);
78 entries.push_back(entry);
79 }
80
81 /* Second, we look for present numerical types. We do it this way
82 * so the order of numerical types is always the same, no matter
83 * how specified in the spec file.
84 */
85 vector<string> result;
86 for (auto t : TYPES) {
87 for (auto i = entries.begin(); i != entries.end(); ++i) {
88 if (*i == t.specType) {
89 result.push_back(t.cType);
90 entries.erase(i);
91 break;
92 }
93 }
94 }
95
96 // Add the remaining; they are not numerical types.
97 for (auto s : entries) {
98 result.push_back(s);
99 }
100
101 return result;
102}
103
104void ParameterDefinition::parseParameterDefinition(const string& type, const string& name,
105 const string& testOption, int lineNumber,
106 bool isReturn, Scanner* scanner) {
107 rsType = type;
108 specName = name;
109
110 // Determine if this is an output.
111 isOutParameter = isReturn || charRemoved('*', &rsType);
112
Jean-Luc Brouillet66fea242015-04-09 16:47:59 -0700113 rsBaseType = rsType;
114 mVectorSize = "1";
115 /* If it's a vector type, we need to split the base type from the size.
116 * We know that's it's a vector type if the last character is a digit and
117 * the rest is an actual base type. We used to only verify the first part,
118 * which created a problem with rs_matrix2x2.
119 */
120 const int last = rsType.size() - 1;
121 const char lastChar = rsType[last];
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700122 if (lastChar >= '0' && lastChar <= '9') {
Jean-Luc Brouillet66fea242015-04-09 16:47:59 -0700123 const string trimmed = rsType.substr(0, last);
124 int i = findCType(trimmed);
125 if (i >= 0) {
126 rsBaseType = trimmed;
127 mVectorSize = lastChar;
128 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700129 }
Jean-Luc Brouillet66fea242015-04-09 16:47:59 -0700130 typeIndex = findCType(rsBaseType);
131
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700132 if (mVectorSize == "3") {
133 vectorWidth = "4";
134 } else {
135 vectorWidth = mVectorSize;
136 }
137
138 /* Create variable names to be used in the java and .rs files. Because x and
139 * y are reserved in .rs files, we prefix variable names with "in" or "out".
140 */
141 if (isOutParameter) {
142 variableName = "out";
143 if (!specName.empty()) {
144 variableName += capitalize(specName);
145 } else if (!isReturn) {
146 scanner->error(lineNumber) << "Should have a name.\n";
147 }
148 } else {
149 variableName = "in";
150 if (specName.empty()) {
151 scanner->error(lineNumber) << "Should have a name.\n";
152 }
153 variableName += capitalize(specName);
154 }
155 rsAllocName = "gAlloc" + capitalize(variableName);
156 javaAllocName = variableName;
157 javaArrayName = "array" + capitalize(javaAllocName);
158
159 // Process the option.
160 undefinedIfOutIsNan = false;
161 compatibleTypeIndex = -1;
162 if (!testOption.empty()) {
163 if (testOption.compare(0, 6, "range(") == 0) {
164 size_t pComma = testOption.find(',');
165 size_t pParen = testOption.find(')');
166 if (pComma == string::npos || pParen == string::npos) {
167 scanner->error(lineNumber) << "Incorrect range " << testOption << "\n";
168 } else {
169 minValue = testOption.substr(6, pComma - 6);
170 maxValue = testOption.substr(pComma + 1, pParen - pComma - 1);
171 }
172 } else if (testOption.compare(0, 6, "above(") == 0) {
173 size_t pParen = testOption.find(')');
174 if (pParen == string::npos) {
175 scanner->error(lineNumber) << "Incorrect testOption " << testOption << "\n";
176 } else {
177 smallerParameter = testOption.substr(6, pParen - 6);
178 }
179 } else if (testOption.compare(0, 11, "compatible(") == 0) {
180 size_t pParen = testOption.find(')');
181 if (pParen == string::npos) {
182 scanner->error(lineNumber) << "Incorrect testOption " << testOption << "\n";
183 } else {
184 compatibleTypeIndex = findCType(testOption.substr(11, pParen - 11));
185 }
186 } else if (testOption.compare(0, 11, "conditional") == 0) {
187 undefinedIfOutIsNan = true;
188 } else {
189 scanner->error(lineNumber) << "Unrecognized testOption " << testOption << "\n";
190 }
191 }
192
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700193 isFloatType = false;
194 if (typeIndex >= 0) {
195 javaBaseType = TYPES[typeIndex].javaType;
196 specType = TYPES[typeIndex].specType;
197 isFloatType = TYPES[typeIndex].exponentBits > 0;
198 }
199 if (!minValue.empty()) {
200 if (typeIndex < 0 || TYPES[typeIndex].kind != FLOATING_POINT) {
201 scanner->error(lineNumber) << "range(,) is only supported for floating point\n";
202 }
203 }
204}
205
Yang Ni12398d82015-09-18 14:57:07 -0700206bool VersionInfo::scan(Scanner* scanner, unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700207 if (scanner->findOptionalTag("version:")) {
208 const string s = scanner->getValue();
Yang Ni12398d82015-09-18 14:57:07 -0700209 if (s.compare(0, sizeof(kTagUnreleased), kTagUnreleased) == 0) {
210 // The API is still under development and does not have
211 // an official version number.
212 minVersion = maxVersion = kUnreleasedVersion;
213 } else {
214 sscanf(s.c_str(), "%u %u", &minVersion, &maxVersion);
215 if (minVersion && minVersion < MIN_API_LEVEL) {
216 scanner->error() << "Minimum version must >= 9\n";
217 }
218 if (minVersion == MIN_API_LEVEL) {
219 minVersion = 0;
220 }
221 if (maxVersion && maxVersion < MIN_API_LEVEL) {
222 scanner->error() << "Maximum version must >= 9\n";
223 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700224 }
225 }
226 if (scanner->findOptionalTag("size:")) {
227 sscanf(scanner->getValue().c_str(), "%i", &intSize);
228 }
Yang Ni12398d82015-09-18 14:57:07 -0700229
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700230 if (maxVersion > maxApiLevel) {
231 maxVersion = maxApiLevel;
232 }
Yang Ni12398d82015-09-18 14:57:07 -0700233
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700234 return minVersion == 0 || minVersion <= maxApiLevel;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700235}
236
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700237Definition::Definition(const std::string& name)
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700238 : mName(name), mDeprecatedApiLevel(0), mHidden(false), mFinalVersion(-1) {
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700239}
240
241void Definition::updateFinalVersion(const VersionInfo& info) {
242 /* We set it if:
243 * - We have never set mFinalVersion before, or
244 * - The max version is 0, which means we have not expired this API, or
245 * - We have a max that's later than what we currently have.
246 */
247 if (mFinalVersion < 0 || info.maxVersion == 0 ||
248 (mFinalVersion > 0 && info.maxVersion > mFinalVersion)) {
249 mFinalVersion = info.maxVersion;
250 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700251}
252
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700253void Definition::scanDocumentationTags(Scanner* scanner, bool firstOccurence,
254 const SpecFile* specFile) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700255 if (scanner->findOptionalTag("hidden:")) {
256 scanner->checkNoValue();
257 mHidden = true;
258 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700259 if (scanner->findOptionalTag("deprecated:")) {
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700260 string value = scanner->getValue();
261 size_t pComma = value.find(", ");
262 if (pComma != string::npos) {
263 mDeprecatedMessage = value.substr(pComma + 2);
264 value.erase(pComma);
265 }
266 sscanf(value.c_str(), "%i", &mDeprecatedApiLevel);
267 if (mDeprecatedApiLevel <= 0) {
268 scanner->error() << "deprecated entries should have a level > 0\n";
269 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700270 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700271 if (firstOccurence) {
272 if (scanner->findTag("summary:")) {
273 mSummary = scanner->getValue();
274 }
275 if (scanner->findTag("description:")) {
276 scanner->checkNoValue();
277 while (scanner->findOptionalTag("")) {
278 mDescription.push_back(scanner->getValue());
279 }
280 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700281 mUrl = specFile->getDetailedDocumentationUrl() + "#android_rs:" + mName;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700282 } else if (scanner->findOptionalTag("summary:")) {
283 scanner->error() << "Only the first specification should have a summary.\n";
284 }
285}
286
287Constant::~Constant() {
288 for (auto i : mSpecifications) {
289 delete i;
290 }
291}
292
293Type::~Type() {
294 for (auto i : mSpecifications) {
295 delete i;
296 }
297}
298
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700299Function::Function(const string& name) : Definition(name) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700300 mCapitalizedName = capitalize(mName);
301}
302
303Function::~Function() {
304 for (auto i : mSpecifications) {
305 delete i;
306 }
307}
308
309bool Function::someParametersAreDocumented() const {
310 for (auto p : mParameters) {
311 if (!p->documentation.empty()) {
312 return true;
313 }
314 }
315 return false;
316}
317
318void Function::addParameter(ParameterEntry* entry, Scanner* scanner) {
319 for (auto i : mParameters) {
320 if (i->name == entry->name) {
321 // It's a duplicate.
322 if (!entry->documentation.empty()) {
323 scanner->error(entry->lineNumber)
324 << "Only the first occurence of an arg should have the "
325 "documentation.\n";
326 }
327 return;
328 }
329 }
330 mParameters.push_back(entry);
331}
332
333void Function::addReturn(ParameterEntry* entry, Scanner* scanner) {
334 if (entry->documentation.empty()) {
335 return;
336 }
337 if (!mReturnDocumentation.empty()) {
338 scanner->error() << "ret: should be documented only for the first variant\n";
339 }
340 mReturnDocumentation = entry->documentation;
341}
342
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700343void ConstantSpecification::scanConstantSpecification(Scanner* scanner, SpecFile* specFile,
Yang Ni12398d82015-09-18 14:57:07 -0700344 unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700345 string name = scanner->getValue();
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700346 VersionInfo info;
347 if (!info.scan(scanner, maxApiLevel)) {
348 cout << "Skipping some " << name << " definitions.\n";
349 scanner->skipUntilTag("end:");
350 return;
351 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700352
353 bool created = false;
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700354 Constant* constant = systemSpecification.findOrCreateConstant(name, &created);
355 ConstantSpecification* spec = new ConstantSpecification(constant);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700356 constant->addSpecification(spec);
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700357 constant->updateFinalVersion(info);
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700358 specFile->addConstantSpecification(spec, created);
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700359 spec->mVersionInfo = info;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700360
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700361 if (scanner->findTag("value:")) {
362 spec->mValue = scanner->getValue();
363 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700364 constant->scanDocumentationTags(scanner, created, specFile);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700365
366 scanner->findTag("end:");
367}
368
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700369void TypeSpecification::scanTypeSpecification(Scanner* scanner, SpecFile* specFile,
Yang Ni12398d82015-09-18 14:57:07 -0700370 unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700371 string name = scanner->getValue();
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700372 VersionInfo info;
373 if (!info.scan(scanner, maxApiLevel)) {
374 cout << "Skipping some " << name << " definitions.\n";
375 scanner->skipUntilTag("end:");
376 return;
377 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700378
379 bool created = false;
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700380 Type* type = systemSpecification.findOrCreateType(name, &created);
381 TypeSpecification* spec = new TypeSpecification(type);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700382 type->addSpecification(spec);
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700383 type->updateFinalVersion(info);
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700384 specFile->addTypeSpecification(spec, created);
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700385 spec->mVersionInfo = info;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700386
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700387 if (scanner->findOptionalTag("simple:")) {
388 spec->mKind = SIMPLE;
389 spec->mSimpleType = scanner->getValue();
390 }
Stephen Hinesca51c782015-08-25 23:43:34 -0700391 if (scanner->findOptionalTag("rs_object:")) {
392 spec->mKind = RS_OBJECT;
393 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700394 if (scanner->findOptionalTag("struct:")) {
395 spec->mKind = STRUCT;
396 spec->mStructName = scanner->getValue();
397 while (scanner->findOptionalTag("field:")) {
398 string s = scanner->getValue();
399 string comment;
400 scanner->parseDocumentation(&s, &comment);
401 spec->mFields.push_back(s);
402 spec->mFieldComments.push_back(comment);
403 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700404 }
405 if (scanner->findOptionalTag("enum:")) {
406 spec->mKind = ENUM;
407 spec->mEnumName = scanner->getValue();
408 while (scanner->findOptionalTag("value:")) {
409 string s = scanner->getValue();
410 string comment;
411 scanner->parseDocumentation(&s, &comment);
412 spec->mValues.push_back(s);
413 spec->mValueComments.push_back(comment);
414 }
415 }
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700416 if (scanner->findOptionalTag("attrib:")) {
417 spec->mAttribute = scanner->getValue();
418 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700419 type->scanDocumentationTags(scanner, created, specFile);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700420
421 scanner->findTag("end:");
422}
423
424FunctionSpecification::~FunctionSpecification() {
425 for (auto i : mParameters) {
426 delete i;
427 }
428 delete mReturn;
429 for (auto i : mPermutations) {
430 delete i;
431 }
432}
433
434string FunctionSpecification::expandString(string s,
435 int replacementIndexes[MAX_REPLACEABLES]) const {
436 if (mReplaceables.size() > 0) {
437 s = stringReplace(s, "#1", mReplaceables[0][replacementIndexes[0]]);
438 }
439 if (mReplaceables.size() > 1) {
440 s = stringReplace(s, "#2", mReplaceables[1][replacementIndexes[1]]);
441 }
442 if (mReplaceables.size() > 2) {
443 s = stringReplace(s, "#3", mReplaceables[2][replacementIndexes[2]]);
444 }
445 if (mReplaceables.size() > 3) {
446 s = stringReplace(s, "#4", mReplaceables[3][replacementIndexes[3]]);
447 }
448 return s;
449}
450
451void FunctionSpecification::expandStringVector(const vector<string>& in,
452 int replacementIndexes[MAX_REPLACEABLES],
453 vector<string>* out) const {
454 out->clear();
455 for (vector<string>::const_iterator iter = in.begin(); iter != in.end(); iter++) {
456 out->push_back(expandString(*iter, replacementIndexes));
457 }
458}
459
460void FunctionSpecification::createPermutations(Function* function, Scanner* scanner) {
461 int start[MAX_REPLACEABLES];
462 int end[MAX_REPLACEABLES];
463 for (int i = 0; i < MAX_REPLACEABLES; i++) {
464 if (i < (int)mReplaceables.size()) {
465 start[i] = 0;
466 end[i] = mReplaceables[i].size();
467 } else {
468 start[i] = -1;
469 end[i] = 0;
470 }
471 }
472 int replacementIndexes[MAX_REPLACEABLES];
473 // TODO: These loops assume that MAX_REPLACEABLES is 4.
474 for (replacementIndexes[3] = start[3]; replacementIndexes[3] < end[3];
475 replacementIndexes[3]++) {
476 for (replacementIndexes[2] = start[2]; replacementIndexes[2] < end[2];
477 replacementIndexes[2]++) {
478 for (replacementIndexes[1] = start[1]; replacementIndexes[1] < end[1];
479 replacementIndexes[1]++) {
480 for (replacementIndexes[0] = start[0]; replacementIndexes[0] < end[0];
481 replacementIndexes[0]++) {
482 auto p = new FunctionPermutation(function, this, replacementIndexes, scanner);
483 mPermutations.push_back(p);
484 }
485 }
486 }
487 }
488}
489
490string FunctionSpecification::getName(int replacementIndexes[MAX_REPLACEABLES]) const {
491 return expandString(mUnexpandedName, replacementIndexes);
492}
493
494void FunctionSpecification::getReturn(int replacementIndexes[MAX_REPLACEABLES],
495 std::string* retType, int* lineNumber) const {
496 *retType = expandString(mReturn->type, replacementIndexes);
497 *lineNumber = mReturn->lineNumber;
498}
499
500void FunctionSpecification::getParam(size_t index, int replacementIndexes[MAX_REPLACEABLES],
501 std::string* type, std::string* name, std::string* testOption,
502 int* lineNumber) const {
503 ParameterEntry* p = mParameters[index];
504 *type = expandString(p->type, replacementIndexes);
505 *name = p->name;
506 *testOption = expandString(p->testOption, replacementIndexes);
507 *lineNumber = p->lineNumber;
508}
509
510void FunctionSpecification::getInlines(int replacementIndexes[MAX_REPLACEABLES],
511 std::vector<std::string>* inlines) const {
512 expandStringVector(mInline, replacementIndexes, inlines);
513}
514
515void FunctionSpecification::parseTest(Scanner* scanner) {
516 const string value = scanner->getValue();
517 if (value == "scalar" || value == "vector" || value == "noverify" || value == "custom" ||
518 value == "none") {
519 mTest = value;
520 } else if (value.compare(0, 7, "limited") == 0) {
521 mTest = "limited";
522 if (value.compare(7, 1, "(") == 0) {
523 size_t pParen = value.find(')');
524 if (pParen == string::npos) {
525 scanner->error() << "Incorrect test: \"" << value << "\"\n";
526 } else {
527 mPrecisionLimit = value.substr(8, pParen - 8);
528 }
529 }
530 } else {
531 scanner->error() << "Unrecognized test option: \"" << value << "\"\n";
532 }
533}
534
Yang Ni12398d82015-09-18 14:57:07 -0700535bool FunctionSpecification::hasTests(unsigned int versionOfTestFiles) const {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700536 if (mVersionInfo.maxVersion != 0 && mVersionInfo.maxVersion < versionOfTestFiles) {
537 return false;
538 }
539 if (mTest == "none") {
540 return false;
541 }
542 return true;
543}
544
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700545void FunctionSpecification::scanFunctionSpecification(Scanner* scanner, SpecFile* specFile,
Yang Ni12398d82015-09-18 14:57:07 -0700546 unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700547 // Some functions like convert have # part of the name. Truncate at that point.
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700548 const string& unexpandedName = scanner->getValue();
549 string name = unexpandedName;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700550 size_t p = name.find('#');
551 if (p != string::npos) {
552 if (p > 0 && name[p - 1] == '_') {
553 p--;
554 }
555 name.erase(p);
556 }
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700557 VersionInfo info;
558 if (!info.scan(scanner, maxApiLevel)) {
559 cout << "Skipping some " << name << " definitions.\n";
560 scanner->skipUntilTag("end:");
561 return;
562 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700563
564 bool created = false;
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700565 Function* function = systemSpecification.findOrCreateFunction(name, &created);
566 FunctionSpecification* spec = new FunctionSpecification(function);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700567 function->addSpecification(spec);
Jean-Luc Brouillet67923a92015-05-12 15:38:27 -0700568 function->updateFinalVersion(info);
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700569 specFile->addFunctionSpecification(spec, created);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700570
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700571 spec->mUnexpandedName = unexpandedName;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700572 spec->mTest = "scalar"; // default
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700573 spec->mVersionInfo = info;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700574
Yang Ni12398d82015-09-18 14:57:07 -0700575 if (scanner->findOptionalTag("internal:")) {
576 spec->mInternal = (scanner->getValue() == "true");
577 }
578 if (scanner->findOptionalTag("intrinsic:")) {
579 spec->mIntrinsic = (scanner->getValue() == "true");
580 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700581 if (scanner->findOptionalTag("attrib:")) {
582 spec->mAttribute = scanner->getValue();
583 }
584 if (scanner->findOptionalTag("w:")) {
585 vector<string> t;
586 if (scanner->getValue().find("1") != string::npos) {
587 t.push_back("");
588 }
589 if (scanner->getValue().find("2") != string::npos) {
590 t.push_back("2");
591 }
592 if (scanner->getValue().find("3") != string::npos) {
593 t.push_back("3");
594 }
595 if (scanner->getValue().find("4") != string::npos) {
596 t.push_back("4");
597 }
598 spec->mReplaceables.push_back(t);
599 }
600
601 while (scanner->findOptionalTag("t:")) {
602 spec->mReplaceables.push_back(convertToTypeVector(scanner->getValue()));
603 }
604
605 if (scanner->findTag("ret:")) {
606 ParameterEntry* p = scanner->parseArgString(true);
607 function->addReturn(p, scanner);
608 spec->mReturn = p;
609 }
610 while (scanner->findOptionalTag("arg:")) {
611 ParameterEntry* p = scanner->parseArgString(false);
612 function->addParameter(p, scanner);
613 spec->mParameters.push_back(p);
614 }
615
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700616 function->scanDocumentationTags(scanner, created, specFile);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700617
618 if (scanner->findOptionalTag("inline:")) {
619 scanner->checkNoValue();
620 while (scanner->findOptionalTag("")) {
621 spec->mInline.push_back(scanner->getValue());
622 }
623 }
624 if (scanner->findOptionalTag("test:")) {
625 spec->parseTest(scanner);
626 }
627
628 scanner->findTag("end:");
629
630 spec->createPermutations(function, scanner);
631}
632
633FunctionPermutation::FunctionPermutation(Function* func, FunctionSpecification* spec,
634 int replacementIndexes[MAX_REPLACEABLES], Scanner* scanner)
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700635 : mReturn(nullptr), mInputCount(0), mOutputCount(0) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700636 // We expand the strings now to make capitalization easier. The previous code preserved
637 // the #n
638 // markers just before emitting, which made capitalization difficult.
639 mName = spec->getName(replacementIndexes);
640 mNameTrunk = func->getName();
641 mTest = spec->getTest();
642 mPrecisionLimit = spec->getPrecisionLimit();
643 spec->getInlines(replacementIndexes, &mInline);
644
645 mHasFloatAnswers = false;
646 for (size_t i = 0; i < spec->getNumberOfParams(); i++) {
647 string type, name, testOption;
648 int lineNumber = 0;
649 spec->getParam(i, replacementIndexes, &type, &name, &testOption, &lineNumber);
650 ParameterDefinition* def = new ParameterDefinition();
651 def->parseParameterDefinition(type, name, testOption, lineNumber, false, scanner);
652 if (def->isOutParameter) {
653 mOutputCount++;
654 } else {
655 mInputCount++;
656 }
657
658 if (def->typeIndex < 0 && mTest != "none") {
659 scanner->error(lineNumber)
660 << "Could not find " << def->rsBaseType
661 << " while generating automated tests. Use test: none if not needed.\n";
662 }
663 if (def->isOutParameter && def->isFloatType) {
664 mHasFloatAnswers = true;
665 }
666 mParams.push_back(def);
667 }
668
669 string retType;
670 int lineNumber = 0;
671 spec->getReturn(replacementIndexes, &retType, &lineNumber);
672 if (!retType.empty()) {
673 mReturn = new ParameterDefinition();
674 mReturn->parseParameterDefinition(retType, "", "", lineNumber, true, scanner);
675 if (mReturn->isFloatType) {
676 mHasFloatAnswers = true;
677 }
678 mOutputCount++;
679 }
680}
681
682FunctionPermutation::~FunctionPermutation() {
683 for (auto i : mParams) {
684 delete i;
685 }
686 delete mReturn;
687}
688
689SpecFile::SpecFile(const string& specFileName) : mSpecFileName(specFileName) {
690 string core = mSpecFileName;
691 // Remove .spec
692 size_t l = core.length();
693 const char SPEC[] = ".spec";
694 const int SPEC_SIZE = sizeof(SPEC) - 1;
695 const int start = l - SPEC_SIZE;
696 if (start >= 0 && core.compare(start, SPEC_SIZE, SPEC) == 0) {
697 core.erase(start);
698 }
699
700 // The header file name should have the same base but with a ".rsh" extension.
701 mHeaderFileName = core + ".rsh";
Jean-Luc Brouilletd9935ee2015-04-03 17:27:02 -0700702 mDetailedDocumentationUrl = core + ".html";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700703}
704
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700705void SpecFile::addConstantSpecification(ConstantSpecification* spec, bool hasDocumentation) {
706 mConstantSpecificationsList.push_back(spec);
707 if (hasDocumentation) {
708 Constant* constant = spec->getConstant();
709 mDocumentedConstants.insert(pair<string, Constant*>(constant->getName(), constant));
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700710 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700711}
712
713void SpecFile::addTypeSpecification(TypeSpecification* spec, bool hasDocumentation) {
714 mTypeSpecificationsList.push_back(spec);
715 if (hasDocumentation) {
716 Type* type = spec->getType();
717 mDocumentedTypes.insert(pair<string, Type*>(type->getName(), type));
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700718 }
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700719}
720
721void SpecFile::addFunctionSpecification(FunctionSpecification* spec, bool hasDocumentation) {
722 mFunctionSpecificationsList.push_back(spec);
723 if (hasDocumentation) {
724 Function* function = spec->getFunction();
725 mDocumentedFunctions.insert(pair<string, Function*>(function->getName(), function));
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700726 }
727}
728
729// Read the specification, adding the definitions to the global functions map.
Yang Ni12398d82015-09-18 14:57:07 -0700730bool SpecFile::readSpecFile(unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700731 FILE* specFile = fopen(mSpecFileName.c_str(), "rt");
732 if (!specFile) {
733 cerr << "Error opening input file: " << mSpecFileName << "\n";
734 return false;
735 }
736
737 Scanner scanner(mSpecFileName, specFile);
738
739 // Scan the header that should start the file.
740 scanner.skipBlankEntries();
741 if (scanner.findTag("header:")) {
742 if (scanner.findTag("summary:")) {
743 mBriefDescription = scanner.getValue();
744 }
745 if (scanner.findTag("description:")) {
746 scanner.checkNoValue();
747 while (scanner.findOptionalTag("")) {
748 mFullDescription.push_back(scanner.getValue());
749 }
750 }
751 if (scanner.findOptionalTag("include:")) {
752 scanner.checkNoValue();
753 while (scanner.findOptionalTag("")) {
754 mVerbatimInclude.push_back(scanner.getValue());
755 }
756 }
757 scanner.findTag("end:");
758 }
759
760 while (1) {
761 scanner.skipBlankEntries();
762 if (scanner.atEnd()) {
763 break;
764 }
765 const string tag = scanner.getNextTag();
766 if (tag == "function:") {
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700767 FunctionSpecification::scanFunctionSpecification(&scanner, this, maxApiLevel);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700768 } else if (tag == "type:") {
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700769 TypeSpecification::scanTypeSpecification(&scanner, this, maxApiLevel);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700770 } else if (tag == "constant:") {
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700771 ConstantSpecification::scanConstantSpecification(&scanner, this, maxApiLevel);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700772 } else {
773 scanner.error() << "Expected function:, type:, or constant:. Found: " << tag << "\n";
774 return false;
775 }
776 }
777
778 fclose(specFile);
779 return scanner.getErrorCount() == 0;
780}
781
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700782SystemSpecification::~SystemSpecification() {
783 for (auto i : mConstants) {
784 delete i.second;
785 }
786 for (auto i : mTypes) {
787 delete i.second;
788 }
789 for (auto i : mFunctions) {
790 delete i.second;
791 }
792 for (auto i : mSpecFiles) {
793 delete i;
794 }
795}
796
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700797// Returns the named entry in the map. Creates it if it's not there.
798template <class T>
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700799T* findOrCreate(const string& name, map<string, T*>* map, bool* created) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700800 auto iter = map->find(name);
801 if (iter != map->end()) {
802 *created = false;
803 return iter->second;
804 }
805 *created = true;
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700806 T* f = new T(name);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700807 map->insert(pair<string, T*>(name, f));
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700808 return f;
809}
810
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700811Constant* SystemSpecification::findOrCreateConstant(const string& name, bool* created) {
812 return findOrCreate<Constant>(name, &mConstants, created);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700813}
814
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700815Type* SystemSpecification::findOrCreateType(const string& name, bool* created) {
816 return findOrCreate<Type>(name, &mTypes, created);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700817}
818
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700819Function* SystemSpecification::findOrCreateFunction(const string& name, bool* created) {
820 return findOrCreate<Function>(name, &mFunctions, created);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700821}
822
Yang Ni12398d82015-09-18 14:57:07 -0700823bool SystemSpecification::readSpecFile(const string& fileName, unsigned int maxApiLevel) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700824 SpecFile* spec = new SpecFile(fileName);
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700825 if (!spec->readSpecFile(maxApiLevel)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700826 cerr << fileName << ": Failed to parse.\n";
827 return false;
828 }
829 mSpecFiles.push_back(spec);
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700830 return true;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700831}
832
Jean-Luc Brouillet36090672015-04-07 15:15:53 -0700833
Yang Ni12398d82015-09-18 14:57:07 -0700834static void updateMaxApiLevel(const VersionInfo& info, unsigned int* maxApiLevel) {
835 if (info.minVersion == VersionInfo::kUnreleasedVersion) {
836 // Ignore development API level in consideration of max API level.
837 return;
838 }
Jean-Luc Brouillet36090672015-04-07 15:15:53 -0700839 *maxApiLevel = max(*maxApiLevel, max(info.minVersion, info.maxVersion));
840}
841
Yang Ni12398d82015-09-18 14:57:07 -0700842unsigned int SystemSpecification::getMaximumApiLevel() {
843 unsigned int maxApiLevel = 0;
Jean-Luc Brouillet36090672015-04-07 15:15:53 -0700844 for (auto i : mConstants) {
845 for (auto j: i.second->getSpecifications()) {
846 updateMaxApiLevel(j->getVersionInfo(), &maxApiLevel);
847 }
848 }
849 for (auto i : mTypes) {
850 for (auto j: i.second->getSpecifications()) {
851 updateMaxApiLevel(j->getVersionInfo(), &maxApiLevel);
852 }
853 }
854 for (auto i : mFunctions) {
855 for (auto j: i.second->getSpecifications()) {
856 updateMaxApiLevel(j->getVersionInfo(), &maxApiLevel);
857 }
858 }
859 return maxApiLevel;
860}
861
Yang Ni12398d82015-09-18 14:57:07 -0700862bool SystemSpecification::generateFiles(bool forVerification, unsigned int maxApiLevel) const {
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700863 bool success = generateHeaderFiles("scriptc") &&
864 generateDocumentation("docs", forVerification) &&
Jean-Luc Brouillet36090672015-04-07 15:15:53 -0700865 generateTestFiles("test", maxApiLevel) &&
866 generateStubsWhiteList("slangtest", maxApiLevel);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700867 if (success) {
868 cout << "Successfully processed " << mTypes.size() << " types, " << mConstants.size()
869 << " constants, and " << mFunctions.size() << " functions.\n";
870 }
871 return success;
872}
873
874string SystemSpecification::getHtmlAnchor(const string& name) const {
875 Definition* d = nullptr;
876 auto c = mConstants.find(name);
877 if (c != mConstants.end()) {
878 d = c->second;
879 } else {
880 auto t = mTypes.find(name);
881 if (t != mTypes.end()) {
882 d = t->second;
883 } else {
884 auto f = mFunctions.find(name);
885 if (f != mFunctions.end()) {
886 d = f->second;
887 } else {
888 return string();
889 }
890 }
891 }
892 ostringstream stream;
893 stream << "<a href='" << d->getUrl() << "'>" << name << "</a>";
894 return stream.str();
895}