Specification.h revision c5184e202ced435258adb2cfe2013570e7190954
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#ifndef ANDROID_RS_API_GENERATOR_SPECIFICATION_H 18#define ANDROID_RS_API_GENERATOR_SPECIFICATION_H 19 20// See Generator.cpp for documentation of the .spec file format. 21 22#include <fstream> 23#include <list> 24#include <map> 25#include <string> 26#include <vector> 27 28class Constant; 29class ConstantSpecification; 30class Function; 31class FunctionPermutation; 32class FunctionSpecification; 33class SpecFile; 34class Specification; 35class Scanner; 36class SystemSpecification; 37class Type; 38class TypeSpecification; 39 40enum NumberKind { SIGNED_INTEGER, UNSIGNED_INTEGER, FLOATING_POINT }; 41 42// Table of type equivalences. 43struct NumericalType { 44 const char* specType; // Name found in the .spec file 45 const char* rsDataType; // RS data type 46 const char* cType; // Type in a C file 47 const char* javaType; // Type in a Java file 48 NumberKind kind; 49 /* For integers, number of bits of the number, excluding the sign bit. 50 * For floats, number of implied bits of the mantissa. 51 */ 52 int significantBits; 53 // For floats, number of bits of the exponent. 0 for integer types. 54 int exponentBits; 55}; 56 57/* Corresponds to one parameter line in a .spec file. These will be parsed when 58 * we instantiate the FunctionPermutation(s) that correspond to one FunctionSpecification. 59 */ 60struct ParameterEntry { 61 std::string type; 62 std::string name; 63 /* Optional information on how to generate test values for this parameter. Can be: 64 * - range(low, high): Generates values between these two limits only. 65 * - above(other_parameter): The values must be greater than those of the named parameter. 66 * Used for clamp. 67 * - compatible(type): The values must also be fully representable in the specified type. 68 * - conditional: Don't verify this value the function return NaN. 69 */ 70 std::string testOption; 71 std::string documentation; 72 int lineNumber; 73}; 74 75/* Information about a parameter to a function. The values of all the fields should only be set by 76 * parseParameterDefinition. 77 */ 78struct ParameterDefinition { 79 std::string rsType; // The Renderscript type, e.g. "uint3" 80 std::string rsBaseType; // As above but without the number, e.g. "uint" 81 std::string javaBaseType; // The type we need to declare in Java, e.g. "unsigned int" 82 std::string specType; // The type found in the spec, e.g. "f16" 83 bool isFloatType; // True if it's a floating point value 84 /* The number of entries in the vector. It should be either "1", "2", "3", or "4". It's also 85 * "1" for scalars. 86 */ 87 std::string mVectorSize; 88 /* The space the vector takes in an array. It's the same as the vector size, except for size 89 * "3", where the width is "4". 90 */ 91 std::string vectorWidth; 92 93 std::string specName; // e.g. x, as found in the spec file 94 std::string variableName; // e.g. inX, used both in .rs and .java 95 std::string rsAllocName; // e.g. gAllocInX 96 std::string javaAllocName; // e.g. inX 97 std::string javaArrayName; // e.g. arrayInX 98 99 // If non empty, the mininum and maximum values to be used when generating the test data. 100 std::string minValue; 101 std::string maxValue; 102 /* If non empty, contains the name of another parameter that should be smaller or equal to this 103 * parameter, i.e. value(smallerParameter) <= value(this). This is used when testing clamp. 104 */ 105 std::string smallerParameter; 106 107 bool isOutParameter; // True if this parameter returns data from the script. 108 bool undefinedIfOutIsNan; // If true, we don't validate if 'out' is NaN. 109 110 int typeIndex; // Index in the TYPES array. Negative if not found in the array. 111 int compatibleTypeIndex; // Index in TYPES for which the test data must also fit. 112 113 /* Fill this object from the type, name, and testOption. 114 * isReturn is true if we're processing the "return:" 115 */ 116 void parseParameterDefinition(const std::string& type, const std::string& name, 117 const std::string& testOption, int lineNumber, bool isReturn, 118 Scanner* scanner); 119}; 120 121struct VersionInfo { 122 /* The range of versions a specification applies to. Zero if there's no restriction, 123 * so an API that became available at 12 and is still valid would have min:12 max:0. 124 * If non zero, both versions should be at least 9, the API level that introduced 125 * RenderScript. 126 */ 127 int minVersion; 128 int maxVersion; 129 // Either 0, 32 or 64. If 0, this definition is valid for both 32 and 64 bits. 130 int intSize; 131 132 VersionInfo() : minVersion(0), maxVersion(0), intSize(0) {} 133 void scan(Scanner* scanner); 134}; 135 136// We have three type of definitions 137class Definition { 138protected: 139 std::string mName; 140 std::string mSpecFileName; 141 142 bool mHidden; // True if it should not be documented 143 std::string mSummary; // A one-line description 144 std::vector<std::string> mDescription; // The comments to be included in the header 145 std::string mUrl; // The URL of the detailed documentation 146 147public: 148 Definition(const std::string& name, SpecFile* specFile); 149 150 std::string getName() const { return mName; } 151 std::string getSpecFileName() const { return mSpecFileName; } 152 153 bool hidden() const { return mHidden; } 154 std::string getSummary() const { return mSummary; } 155 const std::vector<std::string>& getDescription() const { return mDescription; } 156 std::string getUrl() const { return mUrl; } 157 158 void scanDocumentationTags(Scanner* scanner, bool firstOccurence); 159}; 160 161/* Represents a constant, like M_PI. This is a grouping of the version specific specifications. 162 * We'll only have one instance of Constant for each name. 163 */ 164class Constant : public Definition { 165private: 166 std::vector<ConstantSpecification*> mSpecifications; // Owned 167 168public: 169 Constant(const std::string& name, SpecFile* specFile) : Definition(name, specFile) {} 170 ~Constant(); 171 172 const std::vector<ConstantSpecification*> getSpecifications() const { return mSpecifications; } 173 // This method should only be called by the scanning code. 174 void addSpecification(ConstantSpecification* spec) { mSpecifications.push_back(spec); } 175}; 176 177/* Represents a type, like "float4". This is a grouping of the version specific specifications. 178 * We'll only have one instance of Type for each name. 179 */ 180class Type : public Definition { 181private: 182 std::vector<TypeSpecification*> mSpecifications; // Owned 183 184public: 185 Type(const std::string& name, SpecFile* specFile) : Definition(name, specFile) {} 186 ~Type(); 187 188 const std::vector<TypeSpecification*> getSpecifications() const { return mSpecifications; } 189 // This method should only be called by the scanning code. 190 void addSpecification(TypeSpecification* spec) { mSpecifications.push_back(spec); } 191}; 192 193/* Represents a function, like "clamp". Even though the spec file contains many entries for clamp, 194 * we'll only have one clamp instance. 195 */ 196class Function : public Definition { 197private: 198 // mName in the base class contains the lower case name, e.g. native_log 199 std::string mCapitalizedName; // The capitalized name, e.g. NativeLog 200 201 // The unique parameters between all the specifications. NOT OWNED. 202 std::vector<ParameterEntry*> mParameters; 203 std::string mReturnDocumentation; 204 205 std::vector<FunctionSpecification*> mSpecifications; // Owned 206 207public: 208 Function(const std::string& name, SpecFile* specFile); 209 ~Function(); 210 211 std::string getCapitalizedName() const { return mCapitalizedName; } 212 const std::vector<ParameterEntry*>& getParameters() const { return mParameters; } 213 std::string getReturnDocumentation() const { return mReturnDocumentation; } 214 const std::vector<FunctionSpecification*> getSpecifications() const { return mSpecifications; } 215 216 bool someParametersAreDocumented() const; 217 218 // The following methods should only be called by the scanning code. 219 void addParameter(ParameterEntry* entry, Scanner* scanner); 220 void addReturn(ParameterEntry* entry, Scanner* scanner); 221 void addSpecification(FunctionSpecification* spec) { mSpecifications.push_back(spec); } 222}; 223 224/* Base class for TypeSpecification, ConstantSpecification, and FunctionSpecification. 225 * A specification can be specific to a range of RenderScript version or 32bits vs 64 bits. 226 * This base class contains code to parse and store this version information. 227 */ 228class Specification { 229protected: 230 VersionInfo mVersionInfo; 231 void scanVersionInfo(Scanner* scanner); 232 233public: 234 VersionInfo getVersionInfo() const { return mVersionInfo; } 235}; 236 237/* Defines one of the many variations of a constant. There's a one to one correspondance between 238 * ConstantSpecification objects and entries in the spec file. 239 */ 240class ConstantSpecification : public Specification { 241private: 242 std::string mValue; // E.g. "3.1415" 243public: 244 std::string getValue() const { return mValue; } 245 246 // Parse a constant specification and add it to specFile. 247 static void scanConstantSpecification(Scanner* scanner, SpecFile* specFile); 248}; 249 250enum TypeKind { 251 SIMPLE, 252 STRUCT, 253 ENUM, 254}; 255 256/* Defines one of the many variations of a type. There's a one to one correspondance between 257 * TypeSpecification objects and entries in the spec file. 258 */ 259class TypeSpecification : public Specification { 260private: 261 TypeKind mKind; // The kind of type specification 262 263 // If mKind is SIMPLE: 264 std::string mSimpleType; // The definition of the type 265 266 // If mKind is STRUCT: 267 std::string mStructName; // The name found after the struct keyword 268 std::vector<std::string> mFields; // One entry per struct field 269 std::vector<std::string> mFieldComments; // One entry per struct field 270 std::string mAttrib; // Some structures may have attributes 271 272 // If mKind is ENUM: 273 std::string mEnumName; // The name found after the enum keyword 274 std::vector<std::string> mValues; // One entry per enum value 275 std::vector<std::string> mValueComments; // One entry per enum value 276public: 277 TypeKind getKind() const { return mKind; } 278 std::string getSimpleType() const { return mSimpleType; } 279 std::string getStructName() const { return mStructName; } 280 const std::vector<std::string>& getFields() const { return mFields; } 281 const std::vector<std::string>& getFieldComments() const { return mFieldComments; } 282 std::string getAttrib() const { return mAttrib; } 283 std::string getEnumName() const { return mEnumName; } 284 const std::vector<std::string>& getValues() const { return mValues; } 285 const std::vector<std::string>& getValueComments() const { return mValueComments; } 286 287 // Parse a type specification and add it to specFile. 288 static void scanTypeSpecification(Scanner* scanner, SpecFile* specFile); 289}; 290 291// Maximum number of placeholders (like #1, #2) in function specifications. 292const int MAX_REPLACEABLES = 4; 293 294/* Defines one of the many variations of the function. There's a one to one correspondance between 295 * FunctionSpecification objects and entries in the spec file. Some of the strings that are parts 296 * of a FunctionSpecification can include placeholders, which are "#1", "#2", "#3", and "#4". We'll 297 * replace these by values before generating the files. 298 */ 299class FunctionSpecification : public Specification { 300private: 301 /* How to test. One of: 302 * "scalar": Generate test code that checks entries of each vector indepently. E.g. for 303 * sin(float3), the test code will call the CoreMathVerfier.computeSin 3 times. 304 * "limited": Like "scalar" but we don't generate extreme values. This is not currently 305 * enabled as we were generating to many errors. 306 * "custom": Like "scalar" but instead of calling CoreMathVerifier.computeXXX() to compute 307 * the expected value, we call instead CoreMathVerifier.verifyXXX(). This method 308 * returns a string that contains the error message, null if there's no error. 309 * "vector": Generate test code that calls the CoreMathVerifier only once for each vector. 310 * This is useful for APIs like dot() or length(). 311 * "noverify": Generate test code that calls the API but don't verify the returned value. 312 * This can discover unresolved references. 313 */ 314 std::string mTest; 315 std::string mAttribute; // Function attributes. 316 std::string mPrecisionLimit; // Maximum precision required when checking output of this 317 // function. 318 319 // The vectors of values with which we'll replace #1, #2, ... 320 std::vector<std::vector<std::string> > mReplaceables; 321 322 /* The collection of permutations for this specification, i.e. this class instantianted 323 * for specific values of #1, #2, etc. Owned. 324 */ 325 std::vector<FunctionPermutation*> mPermutations; 326 327 // The following fields may contain placeholders that will be replaced using the mReplaceables. 328 329 /* As of this writing, convert_... is the only function with #1 in its name. 330 * The related Function object contains the name of the function without #n, e.g. convert. 331 * This is the name with the #, e.g. convert_#1_#2 332 */ 333 std::string mUnexpandedName; 334 ParameterEntry* mReturn; // The return type. The name should be empty. Owned. 335 int mReturnLineNumber; 336 std::vector<ParameterEntry*> mParameters; // The parameters. Owned. 337 std::vector<std::string> mInline; // The inline code to be included in the header 338 339 /* Substitute the placeholders in the strings (e.g. #1, #2, ...) by the corresponding 340 * entries in mReplaceables. indexOfReplaceable1 selects with value to use for #1, 341 * same for 2, 3, and 4. 342 */ 343 std::string expandString(std::string s, int indexOfReplaceable[MAX_REPLACEABLES]) const; 344 void expandStringVector(const std::vector<std::string>& in, 345 int replacementIndexes[MAX_REPLACEABLES], 346 std::vector<std::string>* out) const; 347 348 // Fill the mPermutations field. 349 void createPermutations(Function* function, Scanner* scanner); 350 351public: 352 FunctionSpecification() : mReturn(nullptr) {} 353 ~FunctionSpecification(); 354 355 std::string getAttribute() const { return mAttribute; } 356 std::string getTest() const { return mTest; } 357 std::string getPrecisionLimit() const { return mPrecisionLimit; } 358 359 const std::vector<FunctionPermutation*>& getPermutations() const { return mPermutations; } 360 361 std::string getName(int replacementIndexes[MAX_REPLACEABLES]) const; 362 void getReturn(int replacementIndexes[MAX_REPLACEABLES], std::string* retType, 363 int* lineNumber) const; 364 size_t getNumberOfParams() const { return mParameters.size(); } 365 void getParam(size_t index, int replacementIndexes[MAX_REPLACEABLES], std::string* type, 366 std::string* name, std::string* testOption, int* lineNumber) const; 367 void getInlines(int replacementIndexes[MAX_REPLACEABLES], 368 std::vector<std::string>* inlines) const; 369 370 // Parse the "test:" line. 371 void parseTest(Scanner* scanner); 372 373 // Return true if we need to generate tests for this function. 374 bool hasTests(int versionOfTestFiles) const; 375 376 // Parse a function specification and add it to specFile. 377 static void scanFunctionSpecification(Scanner* scanner, SpecFile* specFile); 378}; 379 380/* A concrete version of a function specification, where all placeholders have been replaced by 381 * actual values. 382 */ 383class FunctionPermutation { 384private: 385 Function* mFunction; // NOT OWNED. 386 387 // These are the expanded version of those found on FunctionSpecification 388 std::string mName; 389 std::string mNameTrunk; // The name without any expansion, e.g. convert 390 std::string mTest; // How to test. One of "scalar", "vector", "noverify", "limited", and 391 // "none". 392 std::string mPrecisionLimit; // Maximum precision required when checking output of this 393 // function. 394 395 // The parameters of the function. This does not include the return type. Owned. 396 std::vector<ParameterDefinition*> mParams; 397 // The return type. nullptr if a void function. Owned. 398 ParameterDefinition* mReturn; 399 400 // The number of input and output parameters. mOutputCount counts the return type. 401 int mInputCount; 402 int mOutputCount; 403 404 // Whether one of the output parameters is a float. 405 bool mHasFloatAnswers; 406 407 // The inline code that implements this function. Will be empty if not an inline. 408 std::vector<std::string> mInline; 409 410public: 411 FunctionPermutation(Function* function, FunctionSpecification* specification, 412 int replacementIndexes[MAX_REPLACEABLES], Scanner* scanner); 413 ~FunctionPermutation(); 414 415 std::string getName() const { return mName; } 416 std::string getNameTrunk() const { return mNameTrunk; } 417 std::string getTest() const { return mTest; } 418 std::string getPrecisionLimit() const { return mPrecisionLimit; } 419 420 const std::vector<std::string> getInline() const { return mInline; } 421 const ParameterDefinition* getReturn() const { return mReturn; } 422 int getInputCount() const { return mInputCount; } 423 int getOutputCount() const { return mOutputCount; } 424 bool hasFloatAnswers() const { return mHasFloatAnswers; } 425 426 const std::vector<ParameterDefinition*> getParams() const { return mParams; } 427}; 428 429// An entire spec file and the methods to process it. 430class SpecFile { 431private: 432 std::string mSpecFileName; 433 std::string mHeaderFileName; 434 std::string mDetailedDocumentationUrl; 435 std::string mBriefDescription; 436 std::vector<std::string> mFullDescription; 437 // Text to insert as-is in the generated header. 438 std::vector<std::string> mVerbatimInclude; 439 440 /* The constants, types, and functions declared in this file, 441 * in the order they are found in the file. This matters for 442 * header generation, as some types and inline functions depend 443 * on each other. 444 * 445 * Pointers are owned by this list. 446 */ 447 std::list<Constant*> mConstantsList; 448 std::list<Type*> mTypesList; 449 std::list<Function*> mFunctionsList; 450 451 // Quick way to find entries in the previous lists. Pointers not owned. 452 std::map<std::string, Constant*> mConstantsMap; 453 std::map<std::string, Type*> mTypesMap; 454 std::map<std::string, Function*> mFunctionsMap; 455 456public: 457 explicit SpecFile(const std::string& specFileName); 458 ~SpecFile(); 459 460 std::string getSpecFileName() const { return mSpecFileName; } 461 std::string getHeaderFileName() const { return mHeaderFileName; } 462 std::string getDetailedDocumentationUrl() const { return mDetailedDocumentationUrl; } 463 const std::string getBriefDescription() const { return mBriefDescription; } 464 const std::vector<std::string>& getFullDescription() const { return mFullDescription; } 465 const std::vector<std::string>& getVerbatimInclude() const { return mVerbatimInclude; } 466 467 const std::list<Constant*>& getConstantsList() const { return mConstantsList; } 468 const std::list<Type*>& getTypesList() const { return mTypesList; } 469 const std::list<Function*>& getFunctionsList() const { return mFunctionsList; } 470 471 const std::map<std::string, Constant*>& getConstantsMap() const { return mConstantsMap; } 472 const std::map<std::string, Type*>& getTypesMap() const { return mTypesMap; } 473 const std::map<std::string, Function*>& getFunctionsMap() const { return mFunctionsMap; } 474 475 bool readSpecFile(); 476 477 Constant* findOrCreateConstant(const std::string& name, bool* created); 478 Type* findOrCreateType(const std::string& name, bool* created); 479 Function* findOrCreateFunction(const std::string& name, bool* created); 480}; 481 482// The collection of all the spec files. 483class SystemSpecification { 484private: 485 std::vector<SpecFile*> mSpecFiles; 486 487 /* Entries in the table of contents. We accumulate them in a map to sort them. 488 * Pointers are not owned, they belong to the SpecFile object. 489 */ 490 std::map<std::string, Constant*> mConstants; 491 std::map<std::string, Type*> mTypes; 492 std::map<std::string, Function*> mFunctions; 493 494public: 495 ~SystemSpecification(); 496 // Parse the spec file and create the object hierarchy, adding a pointer to mSpecFiles. 497 bool readSpecFile(const std::string& fileName); 498 // Generate all the files. 499 bool generateFiles(int versionOfTestFiles) const; 500 501 const std::vector<SpecFile*>& getSpecFiles() const { return mSpecFiles; } 502 const std::map<std::string, Constant*>& getConstants() const { return mConstants; } 503 const std::map<std::string, Type*>& getTypes() const { return mTypes; } 504 const std::map<std::string, Function*>& getFunctions() const { return mFunctions; } 505 506 // Returns "<a href='...'> for the named specification, or empty if not found. 507 std::string getHtmlAnchor(const std::string& name) const; 508}; 509 510// Singleton that represents the collection of all the specs we're processing. 511extern SystemSpecification systemSpecification; 512 513// Table of equivalences of numerical types. 514extern const NumericalType TYPES[]; 515extern const int NUM_TYPES; 516 517#endif // ANDROID_RS_API_GENERATOR_SPECIFICATION_H 518