README.md
1# API File Generation
2
3There are certain pieces of `NeuralNetworksTypes.h`, `Types.h`,
4`OperandTypes.h`, `OperationTypes.h`, and of our various `*.hal` files that
5ought to be kept in sync -- most notably the operand type and operation type
6definitions and descriptions. To avoid having to do this manually, a tool
7`generate_api.py` is employed to combine a single *specification file* with one
8*template file* per API file (`NeuralNetworksTypes.h`, `Types.h`,
9`OperandTypes.h`, `OperationTypes.h`, or `types.hal`) to produce that API file.
10The script `generate_api.sh` invokes `generate_api.py` once per API file,
11passing appropriate arguments.
12
13## `generate_api.sh`
14
15The environment variable `ANDROID_BUILD_TOP` must be set.
16
17Invoked with no arguments or with the `--mode=update` argument, this script
18regenerates each API file in place, by invoking `generate_api.py` once per
19generated file.
20
21Invoked with the `--mode=hook` argument, this script checks whether
22`NeuralNetworksTypes.h`, `Types.h`, `OperandTypes.h`, or `OperationTypes.h`
23needs to be regenerated.
24
25When the `--dryrun` argument is present, this script shows how it would invoke
26`generate_api.py` but does not actually regenerate files or check whether they
27need to be regenerated.
28
29## `generate_api.py`
30
31This tool generates a single output file from an input specification file and an
32input template file. It takes the following mandatory arguments:
33
34* `--output OUTPUT` path to generated output file (such as `Types.h`)
35* `--specification SPECIFICATION` path to input specification file
36* `--template TEMPLATE` path to input template file
37* `--kind KIND` token identifying kind of file to generate
38
39The "kind" is an arbitrary token that the specification file can reference with
40the `%kind` directive to help generate different text in different situations.
41It has no meaning to the tool itself. Today, the following kinds are used:
42`ndk` (when generating `NeuralNetworksTypes.h`), `canonical` (when generating
43`Types.h`, `OperandTypes.h`, and `OperationTypes.h`), `hal_1.0` (when generating
44`1.0/types.hal`), `hal_1.1`, `hal_1.2`, and `hal_1.3`.
45
46## Template File Syntax
47
48Every line of the template file is copied verbatim to the output file *unless*
49that line begins with `%`.
50
51A line that begins with `%%` is a comment, and is ignored.
52
53A line that begins with `%` and is not a comment is a *directive*.
54
55### Directives
56
57#### `%insert *name*`
58
59Copy the *section* with the specified *name* from the specification file to the
60output file. The section is defined by a `%section` directive in the
61specification file.
62
63#### `%insert-indented *count* *name*`
64
65Similar to `%insert *name*`, but each non-empty copied line is prefixed with
66*count* space characters. *count* must be a non-negative integer.
67
68## Specification File Syntax
69
70The specification file consists of comments, *directives*, and other text.
71
72A line that begins with `%%` is a comment, and is ignored.
73
74A line that begins with `%` and is not a comment is a *directive*.
75
76The meaning of a line that is neither a comment nor a directive depends on the
77context -- the *region* in which that line appears.
78
79### Regions
80
81The specification file is divided into *regions*, which are sequences of lines
82delimited by certain directives.
83
84Certain regions can enclose certain other regions, but this is very limited:
85
86* A conditional region can enclose a section region.
87* A section region can enclose a conditional region.
88
89Equivalently:
90
91* A conditional region can be enclosed by a section region.
92* A section region can be enclosed by a conditional region.
93
94#### null region
95
96A *null region* is a sequence of lines that is not part of any other region.
97For example, a specification file that contains no directives other than
98`%define` and `%define-kinds` consists of a single null region.
99
100Within a null region, all lines other than directives are treated as comments
101and are ignored.
102
103#### conditional region
104
105A *conditional region* is a sequence of lines immediately preceded by the `%kind
106*list*` directive and immediately followed by the `%/kind` directive. The
107`%kind` directive establishes a condition state **on** or **off** (see the
108description of the directive for details). When the condition is **on**, the
109lines in the region are processed normally (i.e., directives have their usual
110effect, and non-directive lines are added to the enclosing section region, if
111any). When the condition is **off**, lines in the region other than the `%else`
112directive are ignored *except* that even ignored directives undergo some level
113of syntactic and semantic checking.
114
115#### section region
116
117A *section region* is a sequence of lines immediately preceded by the `%section
118*name*` directive and immediately followed by the `%/section` directive. Every
119line in the sequence that doesn't begin with `%` undergoes macro substitution,
120and the resulting lines are associated with the section name. They can be
121inserted into the generated output file as directed by the template file's
122`%insert` and `%insert-indented` directives. They can be added to another
123section region with the with the specification file's `%insert` and
124`%insert-indented` directives.
125
126This is the mechanism by which a specification file contributes text to the
127generated output file.
128
129### Directives
130
131#### `%define *name* *body*`
132
133Defines a macro identified by the token *name*. The *body* is separated from
134the *name* by exactly one whitespace character, and extends to the end of the
135line -- it may contain whitespace itself. For example,
136
137 %define test this body begins and ends with a space character
138
139Macro substitution occurs within a section region: a substring `%{*name*}` is
140replaced with the corresponding *body*. Macro substitution is *not* recursive:
141A substring `%{*name2*}` in *body* will not undergo macro substitution, except
142as discussed for *macro arguments* below.
143
144Permitted in regions: null, conditional, section
145
146##### macro arguments
147
148The more general form of a macro invocation is `%{*name* *arglist*}`, where
149*arglist* is a list of whitespace-separated arguments. Within the *body*, a
150substring of the form `%{argnum}` will be replaced by the corresponding argument
151from *arglist*. For example, if the definition is
152
153```
154%define test second is %{2}, first is %{1}
155```
156
157then the macro invocation
158
159```
160%{test alpha beta}
161```
162
163is expanded to
164
165```
166second is beta, first is alpha
167```
168
169The only check on the number of arguments supplied at macro invocation time is
170that there must be at least as many arguments as the highest `%{argnum}`
171reference in the macro body. In the example above, `%{test alpha}` would be an
172error, but `%{test alpha beta gamma}` would not.
173
174#### `%insert *name*`
175
176Adds all lines from the named section region to the current section region.
177
178Permitted in regions: section
179
180#### `%insert-indented *count* *name*`
181
182Similar to `%insert *name*`, but each non-empty added line is prefixed
183with *count* space characters. *count* must be a non-negative integer.
184
185Permitted in regions: section
186
187#### `%kind *list*`, `%else`, `%/kind`
188
189`%kind *list*` creates a *conditional region* terminated by `%/kind`.
190
191The *list* consists of a space-delimited list of tokens, any of which may end in
192`*` to indicate a *wildcard pattern* or `+` to indicate a *lowest version
193pattern*. Any other pattern is a *simple pattern*. The condition is **on** in
194three cases:
195* One of the simple pattern tokens equals the "kind"
196* One of the wildcard pattern tokens less the `*` is a prefix of the "kind"
197* One of the lowest version pattern tokens less the `+` matches the "kind" or
198 the "kind" matches any token to the right from the lowest version pattern in
199 the list passed to %define-kinds
200
201In all other cases, the condition is **off**.
202
203Within the region, the condition is inverted every time the `%else` directive
204appears.
205
206Permitted in regions: null, section
207
208#### `%define-kinds *list*`
209
210This directive has two purposes:
211
212* Validity-checking. If the "kind" is not on the space-delimited *list* of tokens,
213 `generate_api.py` terminates with an error.
214* Ordering the possible kinds for the *lowest version pattern* (see the section
215 above for the explanation of the pattern).
216
217Only one such directive is allowed per specification file.
218
219Permitted in regions: null, section
220
221#### `%section *name*`, `%/section`
222
223`%section *name*` creates a *section region* terminated by `%/section`.
224
225Permitted in regions: null, conditional
226