1/* $NetBSD: lsym_preprocessing.c,v 1.15 2023/06/16 23:19:01 rillig Exp $ */
2
3/*
4 * Tests for the token lsym_preprocessing, which represents a '#' that starts
5 * a preprocessing line.
6 *
7 * #define
8 * #ifdef
9 * #include
10 * #line
11 * #pragma
12 *
13 * The whole preprocessing line is processed separately from the main source
14 * code, without much tokenizing or parsing.
15 */
16
17// TODO: test '#' in the middle of a non-preprocessing line
18// TODO: test stringify '#'
19// TODO: test token paste '##'
20
21//indent input
22// TODO: add input
23//indent end
24
25//indent run-equals-input
26
27
28/*
29 * Whitespace in the following preprocessing directives is preserved.
30 */
31//indent input
32#define space ' '		/* the 'define' is followed by a space */
33#define	tab '\t'		/* the 'define' is followed by a tab */
34#if   0				/* 3 spaces */
35#elif		0		/* 2 tabs */
36#elif	0	>	1	/* tabs between the tokens */
37#endif
38//indent end
39
40//indent run-equals-input
41
42// TODO: #define unfinished_string "...
43// TODO: #define unfinished_char '...
44// TODO: # 123 "file.h"
45// TODO: backslash-newline
46// TODO: block comment
47// TODO: line comment
48
49
50//indent input
51#include <system-header.h>
52#include "local-header.h"
53//indent end
54
55//indent run-equals-input
56
57
58/*
59 * Nested conditional compilation.
60 */
61//indent input
62#if 0
63#else
64#endif
65
66#if 0 /* if comment */
67#else /* else comment */
68#endif /* endif comment */
69
70#if 0 /* outer if comment */
71#  if nested /* inner if comment */
72#  else /* inner else comment */
73#  endif /* inner endif comment */
74#endif /* outer endif comment */
75//indent end
76
77//indent run-equals-input
78
79
80//indent input
81#define multi_line_definition /* first line
82 * middle
83 * final line
84 */ actual_value
85//indent end
86
87//indent run-equals-input
88
89
90/*
91 * Before indent.c 1.129 from 2021-10-08, indent mistakenly interpreted quotes
92 * in comments as starting a string literal. The '"' in the comment started a
93 * string, the next '"' finished the string, and the following '/' '*' was
94 * interpreted as the beginning of a comment. This comment lasted until the
95 * next '*' '/', which in this test is another preprocessor directive, solely
96 * for symmetry.
97 *
98 * The effect was that the extra space after d2 was not formatted, as that
99 * line was considered part of the comment.
100 */
101//indent input
102#define comment_in_string_literal "/* no comment "
103int this_is_an_ordinary_line_again;
104
105int d1 ;
106#define confuse_d /*"*/ "/*"
107int d2 ;
108#define resolve_d "*/"
109int d3 ;
110
111int s1 ;
112#define confuse_s /*'*/ '/*'
113int s2 ;
114#define resolve_s '*/'
115int s3 ;
116//indent end
117
118//indent run
119#define comment_in_string_literal "/* no comment "
120int		this_is_an_ordinary_line_again;
121
122int		d1;
123#define confuse_d /*"*/ "/*"
124int		d2;
125#define resolve_d "*/"
126int		d3;
127
128int		s1;
129#define confuse_s /*'*/ '/*'
130int		s2;
131#define resolve_s '*/'
132int		s3;
133//indent end
134
135
136/*
137 * A preprocessing directive inside an expression keeps the state about
138 * whether the next operator is unary or binary.
139 */
140//indent input
141int binary_plus = 3
142#define intermediate 1
143	+4;
144int unary_plus =
145#define intermediate 1
146	+ 4;
147//indent end
148
149//indent run
150int		binary_plus = 3
151#define intermediate 1
152+ 4;
153int		unary_plus =
154#define intermediate 1
155+4;
156//indent end
157
158
159/*
160 * Before io.c 1.135 from 2021-11-26, indent fixed malformed preprocessing
161 * lines that had arguments even though they shouldn't. It is not the task of
162 * an indenter to fix code, that's what a linter is for.
163 */
164//indent input
165#if 0
166#elif 1
167#else if 3
168#endif 0
169//indent end
170
171//indent run-equals-input
172
173
174/*
175 * Existing comments are indented just like code comments.
176 *
177 * This means that the above wrong preprocessing lines (#else with argument)
178 * need to be fed through indent twice until they become stable. Since
179 * compilers issue warnings about these invalid lines, not much code still has
180 * these, making this automatic fix an edge case.
181 */
182//indent input
183#if 0		/* comment */
184#else		/* comment */
185#endif		/* comment */
186
187#if 0/* comment */
188#else/* comment */
189#endif/* comment */
190//indent end
191
192//indent run-equals-input
193
194
195/*
196 * Multi-line comments in preprocessing lines.
197 */
198//indent input
199#define eol_comment		// EOL
200
201#define no_wrap_comment		/* line 1
202				 * line 2
203				 * line 3
204				 */
205
206#define fixed_comment		/*- line 1
207				 * line 2
208				 * line 3
209				 */
210
211#define two_comments /* 1 */ /* 2 */ /*3*/
212#define three_comments		/* first */ /* second */ /*third*/
213//indent end
214
215//indent run-equals-input
216
217
218/*
219 * Do not touch multi-line macro definitions.
220 */
221//indent input
222#define do_once(stmt)		\
223do {				\
224	stmt;			\
225} while (/* constant condition */ false)
226//indent end
227
228//indent run-equals-input
229
230
231/*
232 * The 'INDENT OFF' state is global, it does not depend on the preprocessing
233 * directives, otherwise the declarations for 'on' and 'after' would be moved
234 * to column 1.
235 */
236//indent input
237int first_line;
238	int before;
239#if 0
240/*INDENT OFF*/
241	int off;
242#else
243	int on;
244#endif
245	int after;
246//indent end
247
248//indent run -di0
249int first_line;
250int before;
251#if 0
252/*INDENT OFF*/
253	int off;
254#else
255	int on;
256#endif
257	int after;
258//indent end
259
260
261/*
262 * Before 2023-06-14, indent was limited to 5 levels of conditional compilation
263 * directives.
264 */
265//indent input
266#if 1
267#if 2
268#if 3
269#if 4
270#if 5
271#if 6
272#endif 6
273#endif 5
274#endif 4
275#endif 3
276#endif 2
277#endif 1
278//indent end
279
280//indent run-equals-input
281
282
283/*
284 * Unrecognized and unmatched preprocessing directives are preserved.
285 */
286//indent input
287#else
288#elif 0
289#elifdef var
290#endif
291
292#unknown
293# 3 "file.c"
294//indent end
295
296//indent run
297#else
298#elif 0
299#elifdef var
300#endif
301
302#unknown
303# 3 "file.c"
304// exit 1
305// error: Standard Input:1: Unmatched #else
306// error: Standard Input:2: Unmatched #elif
307// error: Standard Input:3: Unmatched #elifdef
308// error: Standard Input:4: Unmatched #endif
309//indent end
310
311
312/*
313 * The '#' can only occur at the beginning of a line, therefore indent does not
314 * care when it occurs in the middle of a line.
315 */
316//indent input
317int no = #;
318//indent end
319
320//indent run -di0
321int no =
322#;
323//indent end
324
325
326/*
327 * Preprocessing directives may be indented; indent moves them to the beginning
328 * of a line.
329 */
330//indent input
331#if 0
332	#if 1 \
333	 || 2
334	#endif
335#endif
336//indent end
337
338//indent run
339#if 0
340#if 1 \
341	 || 2
342#endif
343#endif
344//indent end
345