summaryrefslogtreecommitdiff
path: root/nn/tools/api/README.md
blob: fe4dd482fb6e0800398ead228041614ab9c8fc40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# API File Generation

There are certain pieces of `NeuralNetworks.h` and of our various `*.hal` files
that ought to be kept in sync -- most notably the operand type and operation
type definitions and descriptions in our `NeuralNetworks.h` and `types.hal`
files.  To avoid having to do this manually, a tool `generate_api.py` is
employed to combine a single *specification file* with one *template file* per
API file (`NeuralNetworks.h` or `types.hal`) to produce that API file.  The
script `generate_api.sh` invokes `generate_api.py` once per API file, passing
appropriate arguments.

## `generate_api.sh`

The environment variable `ANDROID_BUILD_TOP` must be set.

Invoked with no arguments, this script regenerates the `NeuralNetworks.h` file
and every `types.hal` file in place, by invoking `generate_api.py` once per
generated file.

Invoked with the `--dryrun` argument, this script instead shows how it would
invoke `generate_api.py`.

## `generate_api.py`

This tool generates a single output file from an input specification file and an
input template file.  It takes the following mandatory arguments:

* `--output OUTPUT` path to generated output file (such as `NeuralNetworks.h`)
* `--specification SPECIFICATION` path to input specification file
* `--template TEMPLATE` path to input template file
* `--kind KIND` token identifying kind of file to generate

The "kind" is an arbitrary token that the specification file can reference with
the `%kind` directive to help generate different text in different situations.
It has no meaning to the tool itself.  Today, the following kinds are used:
`ndk` (when generating `NeuralNetworks.h`), `hal_1.0` (when generating
`1.0/types.hal`), `hal_1.1`, `hal_1.2` and `hal_1.3`.

## Template File Syntax

Every line of the template file is copied verbatim to the output file *unless*
that line begins with `%`.

A line that begins with `%%` is a comment, and is ignored.

A line that begins with `%` and is not a comment is a *directive*.

### Directives

#### `%insert *name*`

Copy the *section* with the specified *name* from the specification file to the
output file.  The section is defined by a `%section` directive in the
specification file.

## Specification File Syntax

The specification file consists of comments, *directives*, and other text.

A line that begins with `%%` is a comment, and is ignored.

A line that begins with `%` and is not a comment is a *directive*.

The meaning of a line that is neither a comment nor a directive depends on the
context -- the *region* in which that line appears.

### Regions

The specification file is divided into *regions*, which are sequences of lines
delimited by certain directives.

Certain regions can enclose certain other regions, but this is very limited:

* A conditional region can enclose a definition region.
* A section region can enclose a conditional region or a definition region.

Equivalently:

* A conditional region can be enclosed by a section region.
* A definition region can be enclosed by a conditional region or a section
  region.
  
#### null region

A *null region* is a sequence of lines that is not part of any other region.
For example, a specification file that contains no directives other than
`%define` and `%define-kinds` consists of a single null region.

Within a null region, all lines other than directives are treated as comments
and are ignored.

#### conditional region

A *conditional region* is a sequence of lines immediately preceded by the `%kind
*list*` directive and immediately followed by the `%/kind` directive.  The
`%kind` directive establishes a condition state **on** or **off** (see the
description of the directive for details).  When the condition is **on**, the
lines in the region are processed normally (i.e., directives have their usual
effect, and non-directive lines are added to the enclosing section region, if
any).  When the condition is **off**, lines in the region other than the `%else`
directive are ignored *except* that even ignored directives undergo some level
of syntactic and semantic checking.

#### definition region

A *definition region* is a sequence of lines immediately preceded by the
`%define-lines *name*` directive and immediately followed by the
`%/define-lines` directive.  Every non-comment line in the sequence undergoes
macro substitution, and the resulting lines are associated with the region name.
They can later be added to a section region with the `%insert-lines` directive.

This can be thought of as a multi-line macro facility.

#### section region

A *section region* is a sequence of lines immediately preceded by the `%section
*name*` directive and immediately followed by the `%/section` directive.  Every
non-comment line in the sequence undergoes macro substitution, and the resulting
lines are associated with the section name.  They can be inserted into the
generated output file as directed by the template file's `%insert` directive.

This is the mechanism by which a specification file contributes text to the
generated output file.

### Directives

#### `%define *name* *body*`

Defines a macro identified by the token *name*.  The *body* is separated from
the *name* by exactly one whitespace character, and extends to the end of the
line -- it may contain whitespace itself. For example,

  %define test  this body begins and ends with a space character 

Macro substitution occurs within a definition region or a section region: a
substring `%{*name*}` is replaced with the corresponding *body*.  Macro
substitution is *not* recursive: A substring `%{*name2*}` in *body* will not
undergo macro substitution, except as discussed for *macro arguments* below.

Permitted in regions: null, conditional, section

##### macro arguments

The more general form of a macro invocation is `%{*name* *arglist*}`, where
*arglist* is a list of whitespace-separated arguments.  Within the *body*, a
substring of the form `%{argnum}` will be replaced by the corresponding argument
from *arglist*.  For example, if the definition is

  %define test second is %{2}, first is %{1}
  
then the macro invocation

  %{test alpha beta}
  
is expanded to

  second is beta, first is alpha

The only check on the number of arguments supplied at macro invocation time is
that there must be at least as many arguments as the highest `%{argnum}`
reference in the macro body.  In the example above, `%{test alpha}` would be an
error, but `%{test alpha beta gamma}` would not.

#### `%define-lines *name*`, `%/define-lines`

`%define-lines *name*` creates a *definition region* terminated by
`%/define-lines`.

Permitted in regions: null, conditional, section

#### `%insert-lines *name*`

Adds all lines from the named definition region to the current section region.

Permitted in regions: section

#### `%kind *list*`, `%else`, `%/kind`

`%kind *list*` creates a *conditional region* terminated by `%/kind`.

The *list* consists of a space-delimited list of tokens, any of which may end in
`*` to indicate a *wildcard pattern* or `+` to indicate a *lowest version
pattern*. Any other pattern is a *simple pattern*. The condition is **on** in
three cases:
* One of the simple pattern tokens equals the "kind"
* One of the wildcard pattern tokens less the `*` is a prefix of the "kind"
* One of the lowest version pattern tokens less the `+` matches the "kind" or
  the "kind" matches any token to the right from the lowest version pattern in
  the list passed to %define-kinds

In all other cases, the condition is **off**.

Within the region, the condition is inverted every time the `%else` directive
appears.

Permitted in regions: null, section

#### `%define-kinds *list*`

This directive has two purposes:

* Sanity-checking. If the "kind" is not on the space-delimited *list* of tokens,
  `generate_api.py` terminates with an error.
* Ordering the possible kinds for the *lowest version pattern* (see the section
  above for the explanation of the pattern).

Only one such directive is allowed per specification file.

Permitted in regions: null, section

#### `%section *name*`, `%/section`

`%section *name*` creates a *section region* terminated by `%/section`.

Permitted in regions: null