summaryrefslogtreecommitdiff
path: root/docs/grammar.rst
blob: ee6fa06988c0fb1ef3c1c12c0771dba3743ff2d3 (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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
=======
Grammar
=======

QFace (Quick Interface Language) is an Interface Description Language (IDL). While it is primarily designed to define an interface between Qt, QML and C++, it is intended to be flexible enough also to be used in other contexts.

The grammar of QFace is well defined and is based on the concept of modules as larger collections of information.

A module can have several interfaces, structs and/or enums/flags. Here a not complete unformal grammar.

.. code-block:: html

    module <module> <version>

    import <module> <version>

    interface <Identifier> {
        <type> <identifier>
        <type> <operation>(<parameter>*)
        signal <signal>(<parameter>*)
    }

    struct <Identifier> {
        <type> <identifier>
    }

    enum <Identifier> {
        <name> = <value>,
    }

    flag <Identifier> {
        <name> = <value>,
    }

A QFace document always describes one module. It is convention that a qface document is named after the module. If the same module appears in different documents the behavior is not defined currently. Each document can contain one or more interfaces, structs, flags or enums. Each document can import other modules using the import statement.


Module
======

A module is identified by its name. A module should be normally a URI where all parts are lowercase (e.g. `entertainment.tuner`). A module may import other modules with the primary purpose being to ensure that dependencies are declared inside the QFace file.

.. code-block:: js

    // org.example.qface
    module org.example 1.0

    import org.common 1.0


.. note:: The parser will not validate if the module exists yet. It will just provide the reference to the module and will try to resolve the module on code-generation runtime.

Interface
=========

An interface is a collection of properties, operations and signals. Properties carry data, whereas the operations normally modify the data. Signals are used to notify the user of changes.

.. code-block:: js

    interface WeatherStation {
        real temperature;
        void reset();
        signal error(string message);
    }

QFace allows to extend interfaces using the ``extends`` keyword after the interface name.

.. note:: It is in the responsibility of the author to ensure the order of interfaces are correct. E.g. the base interface should come before the depending interface. QFace does not try to re-order interfaces based on dependency. The order they appear in the document is the order they are passed to the code generator.


.. code-block:: js

    interface Station {
        void reset();
        signal error(string message);
    }

    interface WeatherStation extends Station {
        real temperature;
    }

.. note::

    For the sake of simplicity, as an API designer you should carefully evaluate if an extension is required. The typical way in QFace to allow extensions is normally to write your own code-generator and use type annotations for kind of interfaces.


    .. code-block:: js

        @kind: Station
        interface WeatherStation {
            real temperature;
        }

    The API reader does not need to know the internals of the API. The station behavior would be automatically attached by the custom generator.


Struct
======

The struct resembles a data container. It consist of a set of fields where each field has a name and a data type. Data types can be primitive of complex types.

.. code-block:: js

    struct Error {
        string message;
        int code;
    };

Structs can also be nested. A struct can be used everywhere where a type can be used.

.. code-block:: js

    interface WeatherStation {
        real temperature;
        Error lastError;
        void reset();
        signal error(Error error);
    }

.. note:: When you nest structs, ensure the used struct comes before the using structs and there are no circular dependencies. The order struct appear is the same order they are passed to the code generator.



Enum/Flag
=========

An enum and flag is an enumeration type. The value of each member is automatically assigned if missing and starts with 0.

.. code-block:: js

    enum State {
        Null,       // implicit 0
        Loading,    // will be one
        Ready,      // will be two
        Error       // will be three
    }

The value assignment for the enum type is sequential beginning from 0. To specify the exact value you can assign a value to the member. The value can also be written in hex form (e.f. 0xN).

.. code-block:: js

    enum State {
        Null = 0,
        Loading = 0x1,
        Ready = 2,
        Error = 3
    }

The flag type defines an enumeration type where different values are treated as a bit mask. The values are in the sequence of the 2^n.

.. code-block:: js

    flag Cell {
        Null,   // starting value is one
        Box,    // value is two
        Wall,   // value is four
        Figure  // value is eight
    }


Types
=====

Types are either local and can be referenced simply by their names, or they are from external modules. In the latter case they need to be referenced with the fully qualified name (``<module>.<symbol>``). A type can be an interface, struct, enum or flag. It is also possible to reference the inner members of the symbols with the fragment syntax (``<module>.<symbol>#<fragment>``).

A module consists of either one or more interfaces, structs and enums/flags. They can come in any number or combination. The interface is the only type which can contain properties, operations and signals. The struct is merely a container to transport structured data. An enum/flag allows the user to encode information used inside the struct or interface as data-type.

Below is an example of a QFace file.

.. code-block:: js

    module entertainment.tuner 1.0;

    import common 1.0

    /*! Service Tuner */
    interface Tuner {
        /*! property currentStation */
        readonly Station currentStation;
        /*! operation nextStation */
        void nextStation();
        /*! operation previousStation */
        void previousStation();
        /*! operation updateCurrentStation */
        void updateCurrentStation(int stationId);

        list<int> primitiveList;
        list<Station> complexList;
        map<int> simpleMap;
        map<Station> complexMap;
        model<int> primitiveModel;
        model<Station> complexModel;
    }

    /*! enum State */
    enum State {
        /*! value State.Null */
        Null=0,
        /*! value State.Loading */
        Loading=1,
        /*! value State.Ready */
        Ready=2,
        /*! value State.Error */
        Error=3
    }

    /*! enum Waveband */
    enum Waveband {
        /*! value Waveband.FM */
        FM=0,
        /*! value Waveband.AM */
        AM=1
    }

    flag Features {
        Mono = 0x1,
        Stereo = 0x2,
    }

    /*! struct Station */
    struct Station {
        /*! member stationId */
        int stationId;
        /*! member name */
        string name;
        /*! last time modified */
        common.TimeStamp modified;
    }



Nested Types
============

A nested type is a complex type which nests another type. These are container types, e.g. list, map or model.

.. code-block:: language

    list<Color>  colors
    map<Station> stations
    model<WeatherInfo> weather

A list is an array of the provided value type. A map specifies only the value type. The key-type should be generic (e.g. a string type) and can be freely chosen by the generator. This allows for example the generator to add an id to each structure and use it as a key in the map.

A model is a special type of a list. It should be able to stream (e.g. add/change/remove) the data and the changes should be reflected by a more advanced API. Also the data could in general grow infinitely and the generator should provide some form of pagination or window API. You should use a model if you expect the data it represents to grow in a way that it may influence the performance of your API.

Annotations
===========

Annotations allow the writer to add meta data to an interface document. It uses the `@` notation followed by valid YAML one line content.

.. code-block:: js

    @singleton: true
    @config: { port: 1234 }
    interface Echo {
    }

More information on annotations can be found in the annotations chapter.

Comments
========

Comments use the JavaDoc convention of using an `@` sign as prefix with the keyword followed by the required parameters.

.. code-block::java

    /**
     * @brief The last echo message
     */

Currently only brief, description, see and deprecated are supported doc tags.

The QtCPP built-in generator generates valid Qt documentation out of these comments.


Default Values
==============

QFace supports the assignment of default values to properties and struct fields. A default values is a text string
passed to the generator.

.. code-block:: js

    interface Counter {
        int count = "0";
        Message lastMessage;
    }

    struct Message {
        string text = "NO DATA";
    }

You can use quotes `'` or double-quotes `"` as a marker for text. There is no type check on QFace side. The
text-content is directly passed to the generator.