Specification.h revision 66fea24fb5f3a02b744a9c71ae0fc22c03c4fc6e
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    bool mDeprecated;                       // True if this API should not be used
141    std::string mDeprecatedMessage;         // Optional specific warning if the API is deprecated
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);
149
150    std::string getName() const { return mName; }
151    bool deprecated() const { return mDeprecated; }
152    std::string getDeprecatedMessage() const { return mDeprecatedMessage; }
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, const SpecFile* specFile);
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) : Definition(name) {}
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) : Definition(name) {}
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);
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    Constant* mConstant;  // Not owned
243
244    std::string mValue;  // E.g. "3.1415"
245public:
246    ConstantSpecification(Constant* constant) : mConstant(constant) {}
247
248    Constant* getConstant() const { return mConstant; }
249    std::string getValue() const { return mValue; }
250
251    // Parse a constant specification and add it to specFile.
252    static void scanConstantSpecification(Scanner* scanner, SpecFile* specFile);
253};
254
255enum TypeKind {
256    SIMPLE,
257    STRUCT,
258    ENUM,
259};
260
261/* Defines one of the many variations of a type.  There's a one to one correspondance between
262 * TypeSpecification objects and entries in the spec file.
263 */
264class TypeSpecification : public Specification {
265private:
266    Type* mType;  // Not owned
267
268    TypeKind mKind;  // The kind of type specification
269
270    // If mKind is SIMPLE:
271    std::string mSimpleType;  // The definition of the type
272
273    // If mKind is STRUCT:
274    std::string mStructName;                  // The name found after the struct keyword
275    std::vector<std::string> mFields;         // One entry per struct field
276    std::vector<std::string> mFieldComments;  // One entry per struct field
277    std::string mAttrib;                      // Some structures may have attributes
278
279    // If mKind is ENUM:
280    std::string mEnumName;                    // The name found after the enum keyword
281    std::vector<std::string> mValues;         // One entry per enum value
282    std::vector<std::string> mValueComments;  // One entry per enum value
283public:
284    TypeSpecification(Type* type) : mType(type) {}
285
286    Type* getType() const { return mType; }
287    TypeKind getKind() const { return mKind; }
288    std::string getSimpleType() const { return mSimpleType; }
289    std::string getStructName() const { return mStructName; }
290    const std::vector<std::string>& getFields() const { return mFields; }
291    const std::vector<std::string>& getFieldComments() const { return mFieldComments; }
292    std::string getAttrib() const { return mAttrib; }
293    std::string getEnumName() const { return mEnumName; }
294    const std::vector<std::string>& getValues() const { return mValues; }
295    const std::vector<std::string>& getValueComments() const { return mValueComments; }
296
297    // Parse a type specification and add it to specFile.
298    static void scanTypeSpecification(Scanner* scanner, SpecFile* specFile);
299};
300
301// Maximum number of placeholders (like #1, #2) in function specifications.
302const int MAX_REPLACEABLES = 4;
303
304/* Defines one of the many variations of the function.  There's a one to one correspondance between
305 * FunctionSpecification objects and entries in the spec file.  Some of the strings that are parts
306 * of a FunctionSpecification can include placeholders, which are "#1", "#2", "#3", and "#4".  We'll
307 * replace these by values before generating the files.
308 */
309class FunctionSpecification : public Specification {
310private:
311    Function* mFunction;  // Not owned
312
313    /* How to test.  One of:
314     * "scalar": Generate test code that checks entries of each vector indepently.  E.g. for
315     *           sin(float3), the test code will call the CoreMathVerfier.computeSin 3 times.
316     * "limited": Like "scalar" but we don't generate extreme values.  This is not currently
317     *            enabled as we were generating to many errors.
318     * "custom": Like "scalar" but instead of calling CoreMathVerifier.computeXXX() to compute
319     *           the expected value, we call instead CoreMathVerifier.verifyXXX().  This method
320     *           returns a string that contains the error message, null if there's no error.
321     * "vector": Generate test code that calls the CoreMathVerifier only once for each vector.
322     *           This is useful for APIs like dot() or length().
323     * "noverify": Generate test code that calls the API but don't verify the returned value.
324     *             This can discover unresolved references.
325     * "": Don't test.  This is the default.
326     */
327    std::string mTest;
328    std::string mAttribute;       // Function attributes.
329    std::string mPrecisionLimit;  // Maximum precision required when checking output of this
330                                  // function.
331
332    // The vectors of values with which we'll replace #1, #2, ...
333    std::vector<std::vector<std::string> > mReplaceables;
334
335    /* The collection of permutations for this specification, i.e. this class instantianted
336     * for specific values of #1, #2, etc.  Owned.
337     */
338    std::vector<FunctionPermutation*> mPermutations;
339
340    // The following fields may contain placeholders that will be replaced using the mReplaceables.
341
342    /* As of this writing, convert_... is the only function with #1 in its name.
343     * The related Function object contains the name of the function without #n, e.g. convert.
344     * This is the name with the #, e.g. convert_#1_#2
345     */
346    std::string mUnexpandedName;
347    ParameterEntry* mReturn;  // The return type. The name should be empty.  Owned.
348    std::vector<ParameterEntry*> mParameters;  // The parameters.  Owned.
349    std::vector<std::string> mInline;          // The inline code to be included in the header
350
351    /* Substitute the placeholders in the strings (e.g. #1, #2, ...) by the corresponding
352     * entries in mReplaceables.  indexOfReplaceable1 selects with value to use for #1,
353     * same for 2, 3, and 4.
354     */
355    std::string expandString(std::string s, int indexOfReplaceable[MAX_REPLACEABLES]) const;
356    void expandStringVector(const std::vector<std::string>& in,
357                            int replacementIndexes[MAX_REPLACEABLES],
358                            std::vector<std::string>* out) const;
359
360    // Fill the mPermutations field.
361    void createPermutations(Function* function, Scanner* scanner);
362
363public:
364    FunctionSpecification(Function* function) : mFunction(function), mReturn(nullptr) {}
365    ~FunctionSpecification();
366
367    Function* getFunction() { return mFunction; }
368    std::string getAttribute() const { return mAttribute; }
369    std::string getTest() const { return mTest; }
370    std::string getPrecisionLimit() const { return mPrecisionLimit; }
371
372    const std::vector<FunctionPermutation*>& getPermutations() const { return mPermutations; }
373
374    std::string getName(int replacementIndexes[MAX_REPLACEABLES]) const;
375    void getReturn(int replacementIndexes[MAX_REPLACEABLES], std::string* retType,
376                   int* lineNumber) const;
377    size_t getNumberOfParams() const { return mParameters.size(); }
378    void getParam(size_t index, int replacementIndexes[MAX_REPLACEABLES], std::string* type,
379                  std::string* name, std::string* testOption, int* lineNumber) const;
380    void getInlines(int replacementIndexes[MAX_REPLACEABLES],
381                    std::vector<std::string>* inlines) const;
382
383    // Parse the "test:" line.
384    void parseTest(Scanner* scanner);
385
386    // Return true if we need to generate tests for this function.
387    bool hasTests(int versionOfTestFiles) const;
388
389    // Parse a function specification and add it to specFile.
390    static void scanFunctionSpecification(Scanner* scanner, SpecFile* specFile);
391};
392
393/* A concrete version of a function specification, where all placeholders have been replaced by
394 * actual values.
395 */
396class FunctionPermutation {
397private:
398    // These are the expanded version of those found on FunctionSpecification
399    std::string mName;
400    std::string mNameTrunk;  // The name without any expansion, e.g. convert
401    std::string mTest;       // How to test.  One of "scalar", "vector", "noverify", "limited", and
402                             // "none".
403    std::string mPrecisionLimit;  // Maximum precision required when checking output of this
404                                  // function.
405
406    // The parameters of the function.  This does not include the return type.  Owned.
407    std::vector<ParameterDefinition*> mParams;
408    // The return type.  nullptr if a void function.  Owned.
409    ParameterDefinition* mReturn;
410
411    // The number of input and output parameters.  mOutputCount counts the return type.
412    int mInputCount;
413    int mOutputCount;
414
415    // Whether one of the output parameters is a float.
416    bool mHasFloatAnswers;
417
418    // The inline code that implements this function.  Will be empty if not an inline.
419    std::vector<std::string> mInline;
420
421public:
422    FunctionPermutation(Function* function, FunctionSpecification* specification,
423                        int replacementIndexes[MAX_REPLACEABLES], Scanner* scanner);
424    ~FunctionPermutation();
425
426    std::string getName() const { return mName; }
427    std::string getNameTrunk() const { return mNameTrunk; }
428    std::string getTest() const { return mTest; }
429    std::string getPrecisionLimit() const { return mPrecisionLimit; }
430
431    const std::vector<std::string>& getInline() const { return mInline; }
432    const ParameterDefinition* getReturn() const { return mReturn; }
433    int getInputCount() const { return mInputCount; }
434    int getOutputCount() const { return mOutputCount; }
435    bool hasFloatAnswers() const { return mHasFloatAnswers; }
436
437    const std::vector<ParameterDefinition*> getParams() const { return mParams; }
438};
439
440// An entire spec file and the methods to process it.
441class SpecFile {
442private:
443    std::string mSpecFileName;
444    std::string mHeaderFileName;
445    std::string mDetailedDocumentationUrl;
446    std::string mBriefDescription;
447    std::vector<std::string> mFullDescription;
448    // Text to insert as-is in the generated header.
449    std::vector<std::string> mVerbatimInclude;
450
451    /* The constants, types, and functions specifications declared in this
452     *  file, in the order they are found in the file.  This matters for
453     * header generation, as some types and inline functions depend
454     * on each other.  Pointers not owned.
455     */
456    std::list<ConstantSpecification*> mConstantSpecificationsList;
457    std::list<TypeSpecification*> mTypeSpecificationsList;
458    std::list<FunctionSpecification*> mFunctionSpecificationsList;
459
460    /* The constants, types, and functions that are documented in this file.
461     * In very rare cases, specifications for an API are split across multiple
462     * files, e.g. currently for ClearObject().  The documentation for
463     * that function must be found in the first spec file encountered, so the
464     * order of the files on the command line matters.
465     */
466    std::map<std::string, Constant*> mDocumentedConstants;
467    std::map<std::string, Type*> mDocumentedTypes;
468    std::map<std::string, Function*> mDocumentedFunctions;
469
470public:
471    explicit SpecFile(const std::string& specFileName);
472
473    std::string getSpecFileName() const { return mSpecFileName; }
474    std::string getHeaderFileName() const { return mHeaderFileName; }
475    std::string getDetailedDocumentationUrl() const { return mDetailedDocumentationUrl; }
476    const std::string getBriefDescription() const { return mBriefDescription; }
477    const std::vector<std::string>& getFullDescription() const { return mFullDescription; }
478    const std::vector<std::string>& getVerbatimInclude() const { return mVerbatimInclude; }
479
480    const std::list<ConstantSpecification*>& getConstantSpecifications() const {
481        return mConstantSpecificationsList;
482    }
483    const std::list<TypeSpecification*>& getTypeSpecifications() const {
484        return mTypeSpecificationsList;
485    }
486    const std::list<FunctionSpecification*>& getFunctionSpecifications() const {
487        return mFunctionSpecificationsList;
488    }
489    const std::map<std::string, Constant*>& getDocumentedConstants() const {
490        return mDocumentedConstants;
491    }
492    const std::map<std::string, Type*>& getDocumentedTypes() const { return mDocumentedTypes; }
493    const std::map<std::string, Function*>& getDocumentedFunctions() const {
494        return mDocumentedFunctions;
495    }
496
497    bool readSpecFile();
498
499    /* These are called by the parser to keep track of the specifications defined in this file.
500     * hasDocumentation is true if this specification containes the documentation.
501     */
502    void addConstantSpecification(ConstantSpecification* spec, bool hasDocumentation);
503    void addTypeSpecification(TypeSpecification* spec, bool hasDocumentation);
504    void addFunctionSpecification(FunctionSpecification* spec, bool hasDocumentation);
505};
506
507// The collection of all the spec files.
508class SystemSpecification {
509private:
510    std::vector<SpecFile*> mSpecFiles;
511
512    /* Entries in the table of contents.  We accumulate them in a map to sort them.
513     * Pointers are owned.
514     */
515    std::map<std::string, Constant*> mConstants;
516    std::map<std::string, Type*> mTypes;
517    std::map<std::string, Function*> mFunctions;
518
519public:
520    ~SystemSpecification();
521
522    /* These are called the parser to create unique instances per name.  Set *created to true
523     * if the named specification did not already exist.
524     */
525    Constant* findOrCreateConstant(const std::string& name, bool* created);
526    Type* findOrCreateType(const std::string& name, bool* created);
527    Function* findOrCreateFunction(const std::string& name, bool* created);
528
529    // Parse the spec file and create the object hierarchy, adding a pointer to mSpecFiles.
530    bool readSpecFile(const std::string& fileName);
531    // Generate all the files.
532    bool generateFiles(int versionOfTestFiles) const;
533
534    const std::vector<SpecFile*>& getSpecFiles() const { return mSpecFiles; }
535    const std::map<std::string, Constant*>& getConstants() const { return mConstants; }
536    const std::map<std::string, Type*>& getTypes() const { return mTypes; }
537    const std::map<std::string, Function*>& getFunctions() const { return mFunctions; }
538
539    // Returns "<a href='...'> for the named specification, or empty if not found.
540    std::string getHtmlAnchor(const std::string& name) const;
541};
542
543// Singleton that represents the collection of all the specs we're processing.
544extern SystemSpecification systemSpecification;
545
546// Table of equivalences of numerical types.
547extern const NumericalType TYPES[];
548extern const int NUM_TYPES;
549
550#endif  // ANDROID_RS_API_GENERATOR_SPECIFICATION_H
551