File: inlining.txt

package info (click to toggle)
pike7.8 7.8.866-7
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 69,304 kB
  • ctags: 28,082
  • sloc: ansic: 252,877; xml: 36,537; makefile: 4,214; sh: 2,879; lisp: 655; asm: 591; objc: 212; pascal: 157; sed: 34
file content (268 lines) | stat: -rw-r--r-- 7,563 bytes parent folder | download | duplicates (6)
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
                      +-----------------------+
                      | Pike autodoc inlining |
                      +-----------------------+

The autodoc extractor works either in C mode or in Pike mode. The
reason why the two modes are not the same is that they perform two
very different tasks.

The C mode only has to find comments in the file, and ignores the
surrounding code totally.

The Pike mode, on the other hand, is supposed to be smarter and
distill a lot of information from the Pike code that surrounds the
comments.

Both work at the file level. That makes it easy to use for example
"make" to generate documentation for the source tree. Another benefit
is that the generation will not have to reparse all of the tree if
only one source file is changed.

For Pike module trees, the extractor can recurse through the file tree
on its own, but for C files, where the directory structure gives
insufficient cues about what is what, there must be make targets set
up manually. All generated XML files can then be merged together into
the final Pike namespace.

======================================================================
a) C files
----------------------------------------------------------------------

In C files, the doc comments look like:

  /*! yadda yadda
   *! yadda yadda yadda
   */

Note that only lines that start with *! count, so above are only two
doc lines. Any whitespace before the leading *! is skipped, so that
the lines can be indented freely.

In the C files, no parsing of the surrounding code is done. The
context lies completely in the doc comments themselves, and the target
of the doc comment is determined by special meta keywords that are not
really part of the doc blocks, but rather modifiers that tell which
Pike entity the doc is about.

  /*! @module Foo
   *!   ... doc for the Foo module ...
   *!           ...                 */

    /*! @decl int a()
     *!   ... doc for the method Foo.a() ...
     *!    ....                      */

    /*! @class Bar
     *!   ... doc for the class Foo.Bar  ...
     *!           ...                 */

      /*! @decl mapping(string:string) userprefs()
       *!   ... doc for the method Foo.Bar->userprefs() ...
       *!           ...                 */

      /*! @decl int a
       *! @decl int b
       *!   ... doc for the variables Foo.Bar->a and Foo.Bar->b ...
       *!      ...                      */

    /*! @endclass */

  /*! @endmodule */

The @module and @class too keywords are to work like segment
directives in assembler source files. That is, you can have "@module
foo" in several C files, if the module source is spread over multiple
files. However, if you write doc for the module itself in several
places, an error will be triggered.


======================================================================
b) Pike files
----------------------------------------------------------------------

Doc comments look like:

  //! yadda yadda yadda
  //! yadda yadda

To be considered one doc block, the comments must be separated only by
whitespace and _one_ "\n", that is they have to be on adjacent lines
in the code. Each doc block in the Pike code has one or more targets;
the Pike entities (modules, classes, variables etc.) that the doc
block is documenting. The target of a doc comment is the coherent
block of declarations adjacent to (immediately before or after) it in
the code, without intervening blank lines. Examples:

  //! Doc for alpha
  int alpha()
  {
    return 4711;
  }

  protected int undocumented;

  //! Error! This doc block has no destination!

  int beta;
  //! Doc for beta

  //! Doc for gamma, delta, and epsilon
  int gamma, delta;
  float epsilon;

  //! Error here!
  int zeta;
  //! ambiguous which doc to associate with zeta.

  int eta;
  //! Error here too! ambiguous which variable is documented.
  int theta;

  //! Doc for two methods. This is so UGLY! We strongly recommend
  //! using the decl keywords instead to accomplish this effect.
  int methodOne()
  {
    ...
  }
  int methodTwo()
  {
    ...
  }

  //! However, it can be useful sometimes, for really short methods:
  int very_short() { return 4711; }
  int even_shorter() { return 0; }

In Pike files, you can not use @class or @module to tell which module
or class you are in. To document a class, you simply write:

  //! Doc for the class
  class CheeseMaker
  {
    //! You can even document inherits!
    inherit Earth : earth;
  
    //! Doc for CheeseMaker->a()
    int a()
    {
      ...
    }
  
    void create(string s) { ... }
  }

The parser will automatically identify a() as a member method of the
class CheeseMaker, and will detect that Earth is inherited by
CheeseMaker. If a class has no documentation comment, it's internals
will not be examined, thus it is an error if a class contains
documentation comments but is itself undocumented:

  class a()
  {
    //! @decl foo
    //!    ... doc for foo ...
  }
  
A special inlining case is that of functions and classes. When documenting
these, the doc comment can be put between the head of the function/class,
and the opening "{", like this:

  class Roy
  //! Documentation for Roy
  {
    ....
  }
  
  int un_randomize(int x)
  //! This function takes a random number, and transforms it into
  //! a predictable number.
  {
    return x = 4711;
  }

If a doc block is the first in a file, and it has no target, then it
is treated as doc for the file (or rather: the module/class that the
file compiles into) itself. In any other case it is an error to have a
targetless doc block. A target can also be set with the @decl meta
keyword. If a doc comment begins with some @decl keywords, these
@decl's act just like real declarations standing next to the doc.
Thus:

  //! @decl int a(int x)
  //! @decl int b(int x)
  //! 	Here is some doc for these functions....

is autodocwise equivalent to:

  //! Here is some doc for these functions....
  int a(int x)
  {
     .....
  }
  int b(int x)
  {
     .....
  }

In _one_ case it is legal to have both an adjacent declaration and
the @decl keyword at the block beginning. That is when you document
"polymorph" methods. Then the adjacent declaration must be a method,
and all @decl's must be methods that have the same name as the real
method:

  //! @decl float cube(float x)
  //! @decl int cube(int x)
  //! 	Gives x**3.
  //! @param x
  //! 	The number to cube.
  int|float cube(int|float x)
  {
     ....
  }

The real method prototype is discarded in favour to the @decl'ed
variants, who will be shown in the documentation instead.

One problem that is unsolved so far is how to handle #if .. #else ..
#endif constructions. The approach so far has been to ignore
preprocessor directives totally. For example, the parser does not
handle:

  #ifdef MALE
    int bertil()
  #else
    int berit()
  #endif
  {
    ... body ...
  }

It a portion of the code is unextractable because it contains too much
preprocessor macros and stuff, you can make the extractor skip it by using
@ignore:

  //! @ignore
  
  HERE_ARE_SOME_STRANGE_THINGS
  #ifdef A
  A
  #endif
  
  //! @endignore

All @ignore-@endignore sections of the file are removed before any extraction
is done, so they can cross class boundaries and the like. You can nest @ignore
inside eachother. Another application for @ignore is to hide actual class
boundaries from the extractor:

  //! @ignore
  class C {
  //! @endignore

    //! To the parser, this function appears to be on the top level
    int f() { ... }

  //! @ignore
  }
  //! @endignore