blob: c868916df26b7204f50a775f247866a504fb1c9b [file] [log] [blame]
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001#!/usr/bin/env python
2
3import pprint
4import re
5import sys
6import unittest
7
8sys.path.insert(0, '..')
9
10from pycparser import c_parser
11from pycparser.c_ast import *
12from pycparser.c_parser import CParser, Coord, ParseError
13
14
15_c_parser = c_parser.CParser(
16 lex_optimize=False,
17 yacc_debug=True,
18 yacc_optimize=False,
19 yacctab='yacctab')
20
21
22def expand_decl(decl):
23 """ Converts the declaration into a nested list.
24 """
25 typ = type(decl)
26
27 if typ == TypeDecl:
28 return ['TypeDecl', expand_decl(decl.type)]
29 elif typ == IdentifierType:
30 return ['IdentifierType', decl.names]
31 elif typ == ID:
32 return ['ID', decl.name]
33 elif typ in [Struct, Union]:
34 decls = [expand_decl(d) for d in decl.decls or []]
35 return [typ.__name__, decl.name, decls]
36 else:
37 nested = expand_decl(decl.type)
38
39 if typ == Decl:
40 if decl.quals:
41 return ['Decl', decl.quals, decl.name, nested]
42 else:
43 return ['Decl', decl.name, nested]
44 elif typ == Typename: # for function parameters
45 if decl.quals:
46 return ['Typename', decl.quals, nested]
47 else:
48 return ['Typename', nested]
49 elif typ == ArrayDecl:
50 dimval = decl.dim.value if decl.dim else ''
51 return ['ArrayDecl', dimval, nested]
52 elif typ == PtrDecl:
53 return ['PtrDecl', nested]
54 elif typ == Typedef:
55 return ['Typedef', decl.name, nested]
56 elif typ == FuncDecl:
57 if decl.args:
58 params = [expand_decl(param) for param in decl.args.params]
59 else:
60 params = []
61 return ['FuncDecl', params, nested]
62
63
64def expand_init(init):
65 """ Converts an initialization into a nested list
66 """
67 typ = type(init)
68
eli.benderskyf890a862010-10-30 12:13:23 +020069 if typ == NamedInitializer:
70 des = [expand_init(dp) for dp in init.name]
71 return (des, expand_init(init.expr))
72 elif typ == ExprList:
73 return [expand_init(expr) for expr in init.exprs]
74 elif typ == Constant:
Eli Bendersky3921e8e2010-05-21 09:05:39 +030075 return ['Constant', init.type, init.value]
76 elif typ == ID:
77 return ['ID', init.name]
Eli Bendersky3921e8e2010-05-21 09:05:39 +030078
79
80class TestCParser_fundamentals(unittest.TestCase):
81 """ Tests for "fundamental features" of CParser. Testing
82 (mostly) each feature in a detailed manner.
83 """
84 def parse(self, txt, filename=''):
85 return self.cparser.parse(txt, filename)
86
87 def setUp(self):
88 self.cparser = _c_parser
89
90 def get_decl(self, txt, index=0):
91 """ Given a source and an index returns the expanded
92 declaration at that index.
93
94 FileAST holds a list of 'external declarations'.
95 index is the offset of the desired declaration in that
96 list.
97 """
98 t = self.parse(txt).ext[index]
99 return expand_decl(t)
100
101 def get_decl_init(self, txt, index=0):
102 """ Returns the expanded initializer of the declaration
103 at index.
104 """
105 t = self.parse(txt).ext[index]
106 return expand_init(t.init)
107
108 def test_FileAST(self):
109 t = self.parse('int a; char c;')
110 self.failUnless(isinstance(t, FileAST))
111 self.assertEqual(len(t.ext), 2)
112
eli.bendersky38165b72011-02-04 08:13:39 +0200113 def test_empty_toplevel_decl(self):
114 code = 'int foo;;'
115 t = self.parse(code)
116 self.failUnless(isinstance(t, FileAST))
117 self.assertEqual(len(t.ext), 1)
118 self.assertEqual(self.get_decl(code),
119 ['Decl', 'foo',
120 ['TypeDecl', ['IdentifierType', ['int']]]])
121
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300122 def assert_coord(self, node, line, file=None):
123 self.assertEqual(node.coord.line, line)
124 if file:
125 self.assertEqual(node.coord.file, file)
126
127 def test_coords(self):
eli.bendersky38165b72011-02-04 08:13:39 +0200128 """ Tests the "coordinates" of parsed elements - file
129 name and line numbers, with modification insterted by
130 #line directives.
131 """
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300132 self.assert_coord(self.parse('int a;').ext[0], 1)
133
134 t1 = """
135 int a;
136 int b;\n\n
137 int c;
138 """
139 f1 = self.parse(t1, filename='test.c')
140 self.assert_coord(f1.ext[0], 2, 'test.c')
141 self.assert_coord(f1.ext[1], 3, 'test.c')
142 self.assert_coord(f1.ext[2], 6, 'test.c')
143
144 t1_1 = '''
145 int main() {
146 k = p;
147 printf("%d", b);
148 return 0;
149 }'''
150 f1_1 = self.parse(t1_1, filename='test.c')
eli.benderskyef29ff92010-10-29 16:25:43 +0200151 self.assert_coord(f1_1.ext[0].body.block_items[0], 3, 'test.c')
152 self.assert_coord(f1_1.ext[0].body.block_items[1], 4, 'test.c')
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300153
154 t2 = """
155 #line 99
156 int c;
157 """
158 self.assert_coord(self.parse(t2).ext[0], 99)
159
160 t3 = """
161 int dsf;
162 char p;
163 #line 3000 "in.h"
164 char d;
165 """
166 f3 = self.parse(t3, filename='test.c')
167 self.assert_coord(f3.ext[0], 2, 'test.c')
168 self.assert_coord(f3.ext[1], 3, 'test.c')
169 self.assert_coord(f3.ext[2], 3000, 'in.h')
170
171 t4 = """
172 #line 20 "restore.h"
173 int maydler(char);
174
175 #line 30 "includes/daween.ph"
176 long j, k;
177
178 #line 50000
179 char* ro;
180 """
181 f4 = self.parse(t4, filename='myb.c')
182 self.assert_coord(f4.ext[0], 20, 'restore.h')
183 self.assert_coord(f4.ext[1], 30, 'includes/daween.ph')
184 self.assert_coord(f4.ext[2], 30, 'includes/daween.ph')
185 self.assert_coord(f4.ext[3], 50000, 'includes/daween.ph')
186
187 t5 = """
188 int
189 #line 99
190 c;
191 """
192 self.assert_coord(self.parse(t5).ext[0], 99)
193
194 def test_simple_decls(self):
195 self.assertEqual(self.get_decl('int a;'),
196 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
197
198 self.assertEqual(self.get_decl('unsigned int a;'),
199 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int', 'unsigned']]]])
200
201 self.assertEqual(self.get_decl('char* string;'),
202 ['Decl', 'string',
203 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]])
204
205 self.assertEqual(self.get_decl('long ar[15];'),
206 ['Decl', 'ar',
207 ['ArrayDecl', '15',
208 ['TypeDecl', ['IdentifierType', ['long']]]]])
eli.bendersky98f45372010-10-30 09:46:29 +0200209
210 self.assertEqual(self.get_decl('long long ar[15];'),
211 ['Decl', 'ar',
212 ['ArrayDecl', '15',
eli.benderskyf890a862010-10-30 12:13:23 +0200213 ['TypeDecl', ['IdentifierType', ['long', 'long']]]]])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300214
215 self.assertEqual(self.get_decl('unsigned ar[];'),
216 ['Decl', 'ar',
217 ['ArrayDecl', '',
218 ['TypeDecl', ['IdentifierType', ['unsigned']]]]])
219
220 self.assertEqual(self.get_decl('int strlen(char* s);'),
221 ['Decl', 'strlen',
222 ['FuncDecl',
223 [['Decl', 's',
224 ['PtrDecl',
225 ['TypeDecl', ['IdentifierType', ['char']]]]]],
226 ['TypeDecl', ['IdentifierType', ['int']]]]])
227
228 self.assertEqual(self.get_decl('int strcmp(char* s1, char* s2);'),
229 ['Decl', 'strcmp',
230 ['FuncDecl',
231 [ ['Decl', 's1',
232 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
233 ['Decl', 's2',
234 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]
235 ],
236 ['TypeDecl', ['IdentifierType', ['int']]]]])
237
238 def test_nested_decls(self): # the fun begins
239 self.assertEqual(self.get_decl('char** ar2D;'),
240 ['Decl', 'ar2D',
241 ['PtrDecl', ['PtrDecl',
242 ['TypeDecl', ['IdentifierType', ['char']]]]]])
243
244 self.assertEqual(self.get_decl('int (*a)[1][2];'),
245 ['Decl', 'a',
246 ['PtrDecl',
247 ['ArrayDecl', '1',
248 ['ArrayDecl', '2',
249 ['TypeDecl', ['IdentifierType', ['int']]]]]]])
250
251 self.assertEqual(self.get_decl('int *a[1][2];'),
252 ['Decl', 'a',
253 ['ArrayDecl', '1',
254 ['ArrayDecl', '2',
255 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['int']]]]]]])
256
257 self.assertEqual(self.get_decl('char ***ar3D[40];'),
258 ['Decl', 'ar3D',
259 ['ArrayDecl', '40',
260 ['PtrDecl', ['PtrDecl', ['PtrDecl',
261 ['TypeDecl', ['IdentifierType', ['char']]]]]]]])
262
263 self.assertEqual(self.get_decl('char (***ar3D)[40];'),
264 ['Decl', 'ar3D',
265 ['PtrDecl', ['PtrDecl', ['PtrDecl',
266 ['ArrayDecl', '40', ['TypeDecl', ['IdentifierType', ['char']]]]]]]])
267
268 self.assertEqual(self.get_decl('int (*x[4])(char, int);'),
269 ['Decl', 'x',
270 ['ArrayDecl', '4',
271 ['PtrDecl',
272 ['FuncDecl',
273 [ ['Typename', ['TypeDecl', ['IdentifierType', ['char']]]],
274 ['Typename', ['TypeDecl', ['IdentifierType', ['int']]]]],
275 ['TypeDecl', ['IdentifierType', ['int']]]]]]])
276
277 self.assertEqual(self.get_decl('char *(*(**foo [][8])())[];'),
278 ['Decl', 'foo',
279 ['ArrayDecl', '',
280 ['ArrayDecl', '8',
281 ['PtrDecl', ['PtrDecl',
282 ['FuncDecl',
283 [],
284 ['PtrDecl',
285 ['ArrayDecl', '',
286 ['PtrDecl',
287 ['TypeDecl',
288 ['IdentifierType', ['char']]]]]]]]]]]])
289
290 # explore named and unnamed function pointer parameters,
291 # with and without qualifiers
292 #
293
294 # unnamed w/o quals
295 self.assertEqual(self.get_decl('int (*k)(int);'),
296 ['Decl', 'k',
297 ['PtrDecl',
298 ['FuncDecl',
299 [['Typename', ['TypeDecl', ['IdentifierType', ['int']]]]],
300 ['TypeDecl', ['IdentifierType', ['int']]]]]])
301
302 # unnamed w/ quals
303 self.assertEqual(self.get_decl('int (*k)(const int);'),
304 ['Decl', 'k',
305 ['PtrDecl',
306 ['FuncDecl',
307 [['Typename', ['const'], ['TypeDecl', ['IdentifierType', ['int']]]]],
308 ['TypeDecl', ['IdentifierType', ['int']]]]]])
309
310 # named w/o quals
311 self.assertEqual(self.get_decl('int (*k)(int q);'),
312 ['Decl', 'k',
313 ['PtrDecl',
314 ['FuncDecl',
315 [['Decl', 'q', ['TypeDecl', ['IdentifierType', ['int']]]]],
316 ['TypeDecl', ['IdentifierType', ['int']]]]]])
317
318 # named w/ quals
319 self.assertEqual(self.get_decl('int (*k)(const volatile int q);'),
320 ['Decl', 'k',
321 ['PtrDecl',
322 ['FuncDecl',
323 [['Decl', ['volatile', 'const'], 'q',
324 ['TypeDecl', ['IdentifierType', ['int']]]]],
325 ['TypeDecl', ['IdentifierType', ['int']]]]]])
326
eli.bendersky79d5cf62010-10-29 13:33:52 +0200327 # restrict qualifier
328 self.assertEqual(self.get_decl('int (*k)(restrict int* q);'),
329 ['Decl', 'k',
330 ['PtrDecl',
331 ['FuncDecl',
332 [['Decl', ['restrict'], 'q',
333 ['PtrDecl',
334 ['TypeDecl', ['IdentifierType', ['int']]]]]],
335 ['TypeDecl', ['IdentifierType', ['int']]]]]])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300336
337 def test_qualifiers_storage_specifiers(self):
338 def assert_qs(txt, index, quals, storage):
339 d = self.parse(txt).ext[index]
340 self.assertEqual(d.quals, quals)
341 self.assertEqual(d.storage, storage)
342
343 assert_qs("extern int p;", 0, [], ['extern'])
344 assert_qs("const long p = 6;", 0, ['const'], [])
345
346 d1 = "static const int p, q, r;"
347 for i in range(3):
348 assert_qs(d1, i, ['const'], ['static'])
349
350 d2 = "static char * const p;"
351 assert_qs(d2, 0, [], ['static'])
352 pdecl = self.parse(d2).ext[0].type
353 self.failUnless(isinstance(pdecl, PtrDecl))
354 self.assertEqual(pdecl.quals, ['const'])
355
356 def test_sizeof(self):
357 e = """
358 void foo()
359 {
360 int a = sizeof k;
361 int b = sizeof(int);
eli.benderskyc51e1d32011-02-04 08:52:33 +0200362 int c = sizeof(int**);;
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300363
364 char* p = "just to make sure this parses w/o error...";
365 int d = sizeof(int());
366 }
367 """
368 compound = self.parse(e).ext[0].body
369
eli.benderskyef29ff92010-10-29 16:25:43 +0200370 s1 = compound.block_items[0].init
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300371 self.assertTrue(isinstance(s1, UnaryOp))
372 self.assertEqual(s1.op, 'sizeof')
373 self.assertTrue(isinstance(s1.expr, ID))
374 self.assertEqual(s1.expr.name, 'k')
375
eli.benderskyef29ff92010-10-29 16:25:43 +0200376 s2 = compound.block_items[1].init
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300377 self.assertEqual(expand_decl(s2.expr),
378 ['Typename', ['TypeDecl', ['IdentifierType', ['int']]]])
379
eli.benderskyef29ff92010-10-29 16:25:43 +0200380 s3 = compound.block_items[2].init
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300381 self.assertEqual(expand_decl(s3.expr),
382 ['Typename',
383 ['PtrDecl',
384 ['PtrDecl',
385 ['TypeDecl',
386 ['IdentifierType', ['int']]]]]])
387
eli.bendersky9f481562010-10-30 15:50:47 +0200388 # The C99 compound literal feature
389 #
eli.benderskyf890a862010-10-30 12:13:23 +0200390 def test_compound_literals(self):
eli.bendersky9f481562010-10-30 15:50:47 +0200391 ps1 = self.parse(r'''
eli.benderskyf890a862010-10-30 12:13:23 +0200392 void foo() {
eli.bendersky9f481562010-10-30 15:50:47 +0200393 p = (long long){k};
394 tc = (struct jk){.a = {1, 2}, .b[0] = t};
395 }''')
eli.benderskyf890a862010-10-30 12:13:23 +0200396
eli.bendersky9f481562010-10-30 15:50:47 +0200397 compound = ps1.ext[0].body.block_items[0].rvalue
398 self.assertEqual(expand_decl(compound.type),
399 ['Typename', ['TypeDecl', ['IdentifierType', ['long', 'long']]]])
400 self.assertEqual(expand_init(compound.init),
401 [['ID', 'k']])
402
403 compound = ps1.ext[0].body.block_items[1].rvalue
404 self.assertEqual(expand_decl(compound.type),
405 ['Typename', ['TypeDecl', ['Struct', 'jk', []]]])
406 self.assertEqual(expand_init(compound.init),
407 [
408 ([['ID', 'a']], [['Constant', 'int', '1'], ['Constant', 'int', '2']]),
409 ([['ID', 'b'], ['Constant', 'int', '0']], ['ID', 't'])])
eli.benderskyf890a862010-10-30 12:13:23 +0200410
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300411 def test_enums(self):
412 e1 = "enum mycolor op;"
413 e1_type = self.parse(e1).ext[0].type.type
414
415 self.assertTrue(isinstance(e1_type, Enum))
416 self.assertEqual(e1_type.name, 'mycolor')
417 self.assertEqual(e1_type.values, None)
418
419 e2 = "enum mysize {large=20, small, medium} shoes;"
420 e2_type = self.parse(e2).ext[0].type.type
421
422 self.assertTrue(isinstance(e2_type, Enum))
423 self.assertEqual(e2_type.name, 'mysize')
424
425 e2_elist = e2_type.values
426 self.assertTrue(isinstance(e2_elist, EnumeratorList))
427
428 for e2_eval in e2_elist.enumerators:
429 self.assertTrue(isinstance(e2_eval, Enumerator))
430
431 self.assertEqual(e2_elist.enumerators[0].name, 'large')
432 self.assertEqual(e2_elist.enumerators[0].value.value, '20')
433 self.assertEqual(e2_elist.enumerators[2].name, 'medium')
434 self.assertEqual(e2_elist.enumerators[2].value, None)
435
436 # enum with trailing comma (C99 feature)
437 e3 = """
438 enum
439 {
440 red,
441 blue,
442 green,
443 } color;
444 """
445
446 e3_type = self.parse(e3).ext[0].type.type
447 self.assertTrue(isinstance(e3_type, Enum))
448 e3_elist = e3_type.values
449 self.assertTrue(isinstance(e3_elist, EnumeratorList))
450
451 for e3_eval in e3_elist.enumerators:
452 self.assertTrue(isinstance(e3_eval, Enumerator))
453
454 self.assertEqual(e3_elist.enumerators[0].name, 'red')
455 self.assertEqual(e3_elist.enumerators[0].value, None)
456 self.assertEqual(e3_elist.enumerators[1].name, 'blue')
457 self.assertEqual(e3_elist.enumerators[2].name, 'green')
458
459 def test_typedef(self):
460 # without typedef, error
461 s1 = """
462 node k;
463 """
464 self.assertRaises(ParseError, self.parse, s1)
465
466 # now with typedef, works
467 s2 = """
468 typedef void* node;
469 node k;
470 """
471 ps2 = self.parse(s2)
472 self.assertEqual(expand_decl(ps2.ext[0]),
473 ['Typedef', 'node',
474 ['PtrDecl',
475 ['TypeDecl', ['IdentifierType', ['void']]]]])
476
477 self.assertEqual(expand_decl(ps2.ext[1]),
478 ['Decl', 'k',
479 ['TypeDecl', ['IdentifierType', ['node']]]])
480
481 s3 = """
482 typedef int T;
483 typedef T *pT;
484
485 pT aa, bb;
486 """
487 ps3 = self.parse(s3)
488 self.assertEqual(expand_decl(ps3.ext[3]),
489 ['Decl', 'bb',
490 ['TypeDecl', ['IdentifierType', ['pT']]]])
491
492 s4 = '''
493 typedef char* __builtin_va_list;
494 typedef __builtin_va_list __gnuc_va_list;
495 '''
496 ps4 = self.parse(s4)
497 self.assertEqual(expand_decl(ps4.ext[1]),
498 ['Typedef', '__gnuc_va_list',
499 ['TypeDecl',
500 ['IdentifierType', ['__builtin_va_list']]]])
501
502 s5 = '''typedef struct tagHash Hash;'''
503 ps5 = self.parse(s5)
504 self.assertEqual(expand_decl(ps5.ext[0]),
505 ['Typedef', 'Hash', ['TypeDecl', ['Struct', 'tagHash', []]]])
506
507 def test_struct_union(self):
508 s1 = """
509 struct {
510 int id;
511 char* name;
512 } joe;
513 """
514
515 self.assertEqual(expand_decl(self.parse(s1).ext[0]),
516 ['Decl', 'joe',
517 ['TypeDecl', ['Struct', None,
518 [ ['Decl', 'id',
519 ['TypeDecl',
520 ['IdentifierType', ['int']]]],
521 ['Decl', 'name',
522 ['PtrDecl',
523 ['TypeDecl',
524 ['IdentifierType', ['char']]]]]]]]])
525
526 s2 = """
527 struct node p;
528 """
529 self.assertEqual(expand_decl(self.parse(s2).ext[0]),
530 ['Decl', 'p',
531 ['TypeDecl', ['Struct', 'node', []]]])
532
533 s21 = """
534 union pri ra;
535 """
536 self.assertEqual(expand_decl(self.parse(s21).ext[0]),
537 ['Decl', 'ra',
538 ['TypeDecl', ['Union', 'pri', []]]])
539
540 s3 = """
541 struct node* p;
542 """
543 self.assertEqual(expand_decl(self.parse(s3).ext[0]),
544 ['Decl', 'p',
545 ['PtrDecl',
546 ['TypeDecl', ['Struct', 'node', []]]]])
547
548 s4 = """
549 struct node;
550 """
551 self.assertEqual(expand_decl(self.parse(s4).ext[0]),
552 ['Decl', None,
553 ['Struct', 'node', []]])
554
555 s5 = """
556 union
557 {
558 struct
559 {
560 int type;
561 } n;
562
563 struct
564 {
565 int type;
566 int intnode;
567 } ni;
568 } u;
569 """
570 self.assertEqual(expand_decl(self.parse(s5).ext[0]),
571 ['Decl', 'u',
572 ['TypeDecl',
573 ['Union', None,
574 [['Decl', 'n',
575 ['TypeDecl',
576 ['Struct', None,
577 [['Decl', 'type',
578 ['TypeDecl', ['IdentifierType', ['int']]]]]]]],
579 ['Decl', 'ni',
580 ['TypeDecl',
581 ['Struct', None,
582 [['Decl', 'type',
583 ['TypeDecl', ['IdentifierType', ['int']]]],
584 ['Decl', 'intnode',
585 ['TypeDecl', ['IdentifierType', ['int']]]]]]]]]]]])
586
587 s6 = """
588 typedef struct foo_tag
589 {
590 void* data;
591 } foo, *pfoo;
592 """
593 s6_ast = self.parse(s6)
594
595 self.assertEqual(expand_decl(s6_ast.ext[0]),
596 ['Typedef', 'foo',
597 ['TypeDecl',
598 ['Struct', 'foo_tag',
599 [['Decl', 'data',
600 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]])
601
602 self.assertEqual(expand_decl(s6_ast.ext[1]),
603 ['Typedef', 'pfoo',
604 ['PtrDecl',
605 ['TypeDecl',
606 ['Struct', 'foo_tag',
607 [['Decl', 'data',
608 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]]])
609
610 s7 = r"""
611 struct _on_exit_args {
612 void * _fnargs[32];
613 void * _dso_handle[32];
614
615 long _fntypes;
616 #line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
617
618 long _is_cxa;
619 };
620 """
621
622 s7_ast = self.parse(s7, filename='test.c')
623 self.assert_coord(s7_ast.ext[0].type.decls[2], 6, 'test.c')
624 self.assert_coord(s7_ast.ext[0].type.decls[3], 78,
625 r'D:\eli\cpp_stuff\libc_include/sys/reent.h')
626
627 s8 = """
628 typedef enum tagReturnCode {SUCCESS, FAIL} ReturnCode;
629
630 typedef struct tagEntry
631 {
632 char* key;
633 char* value;
634 } Entry;
635
636
637 typedef struct tagNode
638 {
639 Entry* entry;
640
641 struct tagNode* next;
642 } Node;
643
644 typedef struct tagHash
645 {
646 unsigned int table_size;
647
648 Node** heads;
649
650 } Hash;
651 """
652 s8_ast = self.parse(s8)
653 self.assertEqual(expand_decl(s8_ast.ext[3]),
654 ['Typedef', 'Hash',
655 ['TypeDecl', ['Struct', 'tagHash',
656 [['Decl', 'table_size',
657 ['TypeDecl', ['IdentifierType', ['int', 'unsigned']]]],
658 ['Decl', 'heads',
659 ['PtrDecl', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['Node']]]]]]]]]])
660
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200661 def test_struct_bitfields(self):
eli.bendersky38ed9a92010-10-09 09:29:59 +0200662 # a struct with two bitfields, one unnamed
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200663 s1 = """
664 struct {
665 int k:6;
666 int :2;
667 } joe;
668 """
669
670 parsed_struct = self.parse(s1).ext[0]
671
eli.bendersky38ed9a92010-10-09 09:29:59 +0200672 # We can see here the name of the decl for the unnamed bitfield is
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200673 # None, but expand_decl doesn't show bitfield widths
674 # ...
675 self.assertEqual(expand_decl(parsed_struct),
676 ['Decl', 'joe',
677 ['TypeDecl', ['Struct', None,
678 [ ['Decl', 'k',
679 ['TypeDecl',
680 ['IdentifierType', ['int']]]],
681 ['Decl', None,
682 ['TypeDecl',
683 ['IdentifierType', ['int']]]]]]]])
684
685 # ...
686 # so we test them manually
687 self.assertEqual(parsed_struct.type.type.decls[0].bitsize.value, '6')
688 self.assertEqual(parsed_struct.type.type.decls[1].bitsize.value, '2')
689
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300690 def test_tags_namespace(self):
691 """ Tests that the tags of structs/unions/enums reside in a separate namespace and
692 can be named after existing types.
693 """
694 s1 = """
695 typedef int tagEntry;
696
697 struct tagEntry
698 {
699 char* key;
700 char* value;
701 } Entry;
702 """
703
704 s1_ast = self.parse(s1)
705 self.assertEqual(expand_decl(s1_ast.ext[1]),
706 ['Decl', 'Entry',
707 ['TypeDecl', ['Struct', 'tagEntry',
708 [['Decl', 'key',
709 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
710 ['Decl', 'value',
711 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
712
713 s2 = """
714 struct tagEntry;
715
716 typedef struct tagEntry tagEntry;
717
718 struct tagEntry
719 {
720 char* key;
721 char* value;
722 } Entry;
723 """
724
725 s2_ast = self.parse(s2)
726 self.assertEqual(expand_decl(s2_ast.ext[2]),
727 ['Decl', 'Entry',
728 ['TypeDecl', ['Struct', 'tagEntry',
729 [['Decl', 'key',
730 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
731 ['Decl', 'value',
732 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
733
734 s3 = """
735 typedef int mytag;
736
737 enum mytag {ABC, CDE};
738 enum mytag joe;
739 """
740
741 s3_type = self.parse(s3).ext[1].type
742
743 self.assertTrue(isinstance(s3_type, Enum))
744 self.assertEqual(s3_type.name, 'mytag')
745
746 def test_multi_decls(self):
747 d1 = 'int a, b;'
748
749 self.assertEqual(self.get_decl(d1, 0),
750 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
751 self.assertEqual(self.get_decl(d1, 1),
752 ['Decl', 'b', ['TypeDecl', ['IdentifierType', ['int']]]])
753
754 d2 = 'char* p, notp, ar[4];'
755 self.assertEqual(self.get_decl(d2, 0),
756 ['Decl', 'p',
757 ['PtrDecl',
758 ['TypeDecl', ['IdentifierType', ['char']]]]])
759 self.assertEqual(self.get_decl(d2, 1),
760 ['Decl', 'notp', ['TypeDecl', ['IdentifierType', ['char']]]])
761 self.assertEqual(self.get_decl(d2, 2),
762 ['Decl', 'ar',
763 ['ArrayDecl', '4',
764 ['TypeDecl', ['IdentifierType', ['char']]]]])
765
766 def test_invalid_multiple_types_error(self):
767 bad = [
768 'int enum {ab, cd} fubr;',
769 'enum kid char brbr;']
770
771 for b in bad:
772 self.assertRaises(ParseError, self.parse, b)
773
774 def test_decl_inits(self):
775 d1 = 'int a = 16;'
eli.benderskyf890a862010-10-30 12:13:23 +0200776 #~ self.parse(d1).show()
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300777 self.assertEqual(self.get_decl(d1),
778 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
779 self.assertEqual(self.get_decl_init(d1),
780 ['Constant', 'int', '16'])
781
782 d2 = 'long ar[] = {7, 8, 9};'
eli.benderskyf890a862010-10-30 12:13:23 +0200783 #~ self.parse(d2).show()
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300784 self.assertEqual(self.get_decl(d2),
785 ['Decl', 'ar',
786 ['ArrayDecl', '',
787 ['TypeDecl', ['IdentifierType', ['long']]]]])
788 self.assertEqual(self.get_decl_init(d2),
789 [ ['Constant', 'int', '7'],
790 ['Constant', 'int', '8'],
eli.benderskyf890a862010-10-30 12:13:23 +0200791 ['Constant', 'int', '9']])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300792
793 d3 = 'char p = j;'
794 self.assertEqual(self.get_decl(d3),
795 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['char']]]])
796 self.assertEqual(self.get_decl_init(d3),
797 ['ID', 'j'])
798
799 d4 = "char x = 'c', *p = {0, 1, 2, {4, 5}, 6};"
800 self.assertEqual(self.get_decl(d4, 0),
801 ['Decl', 'x', ['TypeDecl', ['IdentifierType', ['char']]]])
802 self.assertEqual(self.get_decl_init(d4, 0),
803 ['Constant', 'char', "'c'"])
804 self.assertEqual(self.get_decl(d4, 1),
805 ['Decl', 'p',
806 ['PtrDecl',
807 ['TypeDecl', ['IdentifierType', ['char']]]]])
eli.benderskyf890a862010-10-30 12:13:23 +0200808
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300809 self.assertEqual(self.get_decl_init(d4, 1),
810 [ ['Constant', 'int', '0'],
811 ['Constant', 'int', '1'],
812 ['Constant', 'int', '2'],
eli.benderskyf890a862010-10-30 12:13:23 +0200813 [['Constant', 'int', '4'],
814 ['Constant', 'int', '5']],
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300815 ['Constant', 'int', '6']])
eli.benderskyf890a862010-10-30 12:13:23 +0200816
817 def test_decl_named_inits(self):
818 d1 = 'int a = {.k = 16};'
819 self.assertEqual(self.get_decl_init(d1),
820 [( [['ID', 'k']],
821 ['Constant', 'int', '16'])])
822
823 d2 = 'int a = { [0].a = {1}, [1].a[0] = 2 };'
824 self.assertEqual(self.get_decl_init(d2),
825 [
826 ([['Constant', 'int', '0'], ['ID', 'a']],
827 [['Constant', 'int', '1']]),
828 ([['Constant', 'int', '1'], ['ID', 'a'], ['Constant', 'int', '0']],
829 ['Constant', 'int', '2'])])
830
831 d3 = 'int a = { .a = 1, .c = 3, 4, .b = 5};'
832 self.assertEqual(self.get_decl_init(d3),
833 [
834 ([['ID', 'a']], ['Constant', 'int', '1']),
835 ([['ID', 'c']], ['Constant', 'int', '3']),
836 ['Constant', 'int', '4'],
837 ([['ID', 'b']], ['Constant', 'int', '5'])])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300838
839 def test_function_definitions(self):
840 def parse_fdef(str):
841 return self.parse(str).ext[0]
842
843 def fdef_decl(fdef):
844 return expand_decl(fdef.decl)
845
846 f1 = parse_fdef('''
847 int factorial(int p)
848 {
849 return 3;
850 }
851 ''')
852
853 self.assertEqual(fdef_decl(f1),
854 ['Decl', 'factorial',
855 ['FuncDecl',
856 [['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]]],
857 ['TypeDecl', ['IdentifierType', ['int']]]]])
858
eli.benderskyef29ff92010-10-29 16:25:43 +0200859 self.assertEqual(type(f1.body.block_items[0]), Return)
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300860
861 f2 = parse_fdef('''
862 char* zzz(int p, char* c)
863 {
864 int a;
865 char b;
866
867 a = b + 2;
868 return 3;
869 }
870 ''')
871
872 self.assertEqual(fdef_decl(f2),
873 ['Decl', 'zzz',
874 ['FuncDecl',
875 [ ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]],
876 ['Decl', 'c', ['PtrDecl',
877 ['TypeDecl', ['IdentifierType', ['char']]]]]],
878 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
879
eli.benderskyef29ff92010-10-29 16:25:43 +0200880 self.assertEqual(list(map(type, f2.body.block_items)),
881 [Decl, Decl, Assignment, Return])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300882
883 f3 = parse_fdef('''
884 char* zzz(p, c)
885 long p, *c;
886 {
887 int a;
888 char b;
889
890 a = b + 2;
891 return 3;
892 }
893 ''')
894
895 self.assertEqual(fdef_decl(f3),
896 ['Decl', 'zzz',
897 ['FuncDecl',
898 [ ['ID', 'p'],
899 ['ID', 'c']],
900 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
901
eli.benderskyef29ff92010-10-29 16:25:43 +0200902 self.assertEqual(list(map(type, f3.body.block_items)),
903 [Decl, Decl, Assignment, Return])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300904
905 self.assertEqual(expand_decl(f3.param_decls[0]),
906 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['long']]]])
907 self.assertEqual(expand_decl(f3.param_decls[1]),
908 ['Decl', 'c', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['long']]]]])
909
eli.bendersky71540662010-07-03 12:58:52 +0200910 def test_unified_string_literals(self):
911 # simple string, for reference
912 d1 = self.get_decl_init('char* s = "hello";')
913 self.assertEqual(d1, ['Constant', 'string', '"hello"'])
914
915 d2 = self.get_decl_init('char* s = "hello" " world";')
916 self.assertEqual(d2, ['Constant', 'string', '"hello world"'])
917
918 # the test case from issue 6
919 d3 = self.parse(r'''
920 int main() {
921 fprintf(stderr,
922 "Wrong Params?\n"
923 "Usage:\n"
924 "%s <binary_file_path>\n",
925 argv[0]
926 );
927 }
928 ''')
929
930 self.assertEqual(
eli.benderskyef29ff92010-10-29 16:25:43 +0200931 d3.ext[0].body.block_items[0].args.exprs[1].value,
eli.bendersky71540662010-07-03 12:58:52 +0200932 r'"Wrong Params?\nUsage:\n%s <binary_file_path>\n"')
eli.bendersky4a89f112010-07-05 06:02:03 +0200933
934 d4 = self.get_decl_init('char* s = "" "foobar";')
935 self.assertEqual(d4, ['Constant', 'string', '"foobar"'])
936
937 d5 = self.get_decl_init(r'char* s = "foo\"" "bar";')
938 self.assertEqual(d5, ['Constant', 'string', r'"foo\"bar"'])
eli.bendersky71540662010-07-03 12:58:52 +0200939
eli.bendersky79d5cf62010-10-29 13:33:52 +0200940 def test_inline_specifier(self):
941 ps2 = self.parse('static inline void inlinefoo(void);')
942 self.assertEqual(ps2.ext[0].funcspec, ['inline'])
eli.bendersky2e907fa2010-10-29 15:51:07 +0200943
944 # variable length array
945 def test_vla(self):
946 ps2 = self.parse(r'''
947 int main() {
948 int size;
949 int var[size = 5];
950
951 int var2[*];
952 }
953 ''')
eli.benderskyef29ff92010-10-29 16:25:43 +0200954 self.failUnless(isinstance(ps2.ext[0].body.block_items[1].type.dim, Assignment))
955 self.failUnless(isinstance(ps2.ext[0].body.block_items[2].type.dim, ID))
eli.bendersky79d5cf62010-10-29 13:33:52 +0200956
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300957
958class TestCParser_whole_code(unittest.TestCase):
959 """ Testing of parsing whole chunks of code.
960
961 Since I don't want to rely on the structure of ASTs too
962 much, most of these tests are implemented with visitors.
963 """
964 def parse(self, txt, filename=''):
965 return self.cparser.parse(txt, filename)
966
967 def setUp(self):
968 self.cparser = _c_parser
969
970 # A simple helper visitor that lists the values of all the
971 # Constant nodes it sees.
972 #
973 class ConstantVisitor(NodeVisitor):
974 def __init__(self):
975 self.values = []
976
977 def visit_Constant(self, node):
978 self.values.append(node.value)
979
980 # This visitor counts the amount of references to the ID
981 # with the name provided to it in the constructor.
982 #
983 class IDNameCounter(NodeVisitor):
984 def __init__(self, name):
985 self.name = name
986 self.nrefs = 0
987
988 def visit_ID(self, node):
989 if node.name == self.name:
990 self.nrefs += 1
991
992 # Counts the amount of nodes of a given class
993 #
994 class NodeKlassCounter(NodeVisitor):
995 def __init__(self, node_klass):
996 self.klass = node_klass
997 self.n = 0
998
999 def generic_visit(self, node):
1000 if node.__class__ == self.klass:
1001 self.n += 1
1002
1003 NodeVisitor.generic_visit(self, node)
1004
1005 def assert_all_Constants(self, code, constants):
1006 """ Asserts that the list of all Constant values (by
1007 'preorder' appearance) in the chunk of code is as
1008 given.
1009 """
eli.benderskyed890492010-06-25 08:25:55 +03001010 if isinstance(code, str):
1011 parsed = self.parse(code)
1012 else:
1013 parsed = code
1014
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001015 cv = self.ConstantVisitor()
1016 cv.visit(parsed)
1017 self.assertEqual(cv.values, constants)
1018
1019 def assert_num_ID_refs(self, code, name, num):
1020 """ Asserts the number of references to the ID with
1021 the given name.
1022 """
1023 if isinstance(code, str):
1024 parsed = self.parse(code)
1025 else:
1026 parsed = code
1027
1028 iv = self.IDNameCounter(name)
1029 iv.visit(parsed)
1030 self.assertEqual(iv.nrefs, num)
1031
1032 def assert_num_klass_nodes(self, code, klass, num):
1033 """ Asserts the amount of klass nodes in the code.
1034 """
1035 if isinstance(code, str):
1036 parsed = self.parse(code)
1037 else:
1038 parsed = code
1039
1040 cv = self.NodeKlassCounter(klass)
1041 cv.visit(parsed)
1042 self.assertEqual(cv.n, num)
1043
1044 def test_expressions(self):
1045 e1 = '''int k = (r + 10.0) >> 6 + 8 << (3 & 0x14);'''
1046 self.assert_all_Constants(e1, ['10.0', '6', '8', '3', '0x14'])
1047
1048 e2 = r'''char n = '\n', *prefix = "st_";'''
1049 self.assert_all_Constants(e2, [r"'\n'", '"st_"'])
1050
1051 def test_statements(self):
1052 s1 = r'''
1053 void foo(){
1054 if (sp == 1)
1055 if (optind >= argc ||
1056 argv[optind][0] != '-' || argv[optind][1] == '\0')
1057 return -1;
1058 else if (strcmp(argv[optind], "--") == 0) {
1059 optind++;
1060 return -1;
1061 }
1062 }
1063 '''
1064
1065 self.assert_all_Constants(s1,
1066 ['1', '0', r"'-'", '1', r"'\0'", '1', r'"--"', '0', '1'])
1067
1068 ps1 = self.parse(s1)
1069 self.assert_num_ID_refs(ps1, 'argv', 3)
1070 self.assert_num_ID_refs(ps1, 'optind', 5)
1071
1072 self.assert_num_klass_nodes(ps1, If, 3)
1073 self.assert_num_klass_nodes(ps1, Return, 2)
1074 self.assert_num_klass_nodes(ps1, FuncCall, 1) # strcmp
1075 self.assert_num_klass_nodes(ps1, BinaryOp, 7)
1076
1077 # In the following code, Hash and Node were defined as
1078 # int to pacify the parser that sees they're used as
1079 # types
1080 #
1081 s2 = r'''
1082 typedef int Hash, Node;
1083
1084 void HashDestroy(Hash* hash)
1085 {
1086 unsigned int i;
1087
1088 if (hash == NULL)
1089 return;
1090
1091 for (i = 0; i < hash->table_size; ++i)
1092 {
1093 Node* temp = hash->heads[i];
1094
1095 while (temp != NULL)
1096 {
1097 Node* temp2 = temp;
1098
1099 free(temp->entry->key);
1100 free(temp->entry->value);
1101 free(temp->entry);
1102
1103 temp = temp->next;
1104
1105 free(temp2);
1106 }
1107 }
1108
1109 free(hash->heads);
1110 hash->heads = NULL;
1111
1112 free(hash);
1113 }
1114 '''
1115
1116 ps2 = self.parse(s2)
1117 self.assert_num_klass_nodes(ps2, FuncCall, 6)
1118 self.assert_num_klass_nodes(ps2, FuncDef, 1)
1119 self.assert_num_klass_nodes(ps2, For, 1)
1120 self.assert_num_klass_nodes(ps2, While, 1)
1121 self.assert_num_klass_nodes(ps2, StructRef, 10)
1122
1123 # declarations don't count
1124 self.assert_num_ID_refs(ps2, 'hash', 6)
1125 self.assert_num_ID_refs(ps2, 'i', 4)
eli.benderskyed890492010-06-25 08:25:55 +03001126
1127 s3 = r'''
1128 void x(void) {
1129 int a, b;
1130 if (a < b)
1131 do {
1132 a = 0;
1133 } while (0);
1134 else if (a == b) {
1135 a = 1;
1136 }
1137 }
1138 '''
1139
1140 ps3 = self.parse(s3)
1141 self.assert_num_klass_nodes(ps3, DoWhile, 1)
1142 self.assert_num_ID_refs(ps3, 'a', 4)
1143 self.assert_all_Constants(ps3, ['0', '0', '1'])
eli.bendersky145890d2010-10-29 12:02:32 +02001144
1145 def test_for_statement(self):
1146 s2 = r'''
1147 void x(void)
1148 {
1149 int i;
1150 for (i = 0; i < 5; ++i) {
1151 x = 50;
1152 }
1153 }
1154 '''
1155 ps2 = self.parse(s2)
1156 self.assert_num_klass_nodes(ps2, For, 1)
1157 # here there are 3 refs to 'i' since the declaration doesn't count as
1158 # a ref in the visitor
1159 #
1160 self.assert_num_ID_refs(ps2, 'i', 3)
eli.benderskyed890492010-06-25 08:25:55 +03001161
eli.bendersky145890d2010-10-29 12:02:32 +02001162 s3 = r'''
1163 void x(void)
1164 {
1165 for (int i = 0; i < 5; ++i) {
1166 x = 50;
1167 }
1168 }
1169 '''
1170 ps3 = self.parse(s3)
eli.bendersky145890d2010-10-29 12:02:32 +02001171 self.assert_num_klass_nodes(ps3, For, 1)
1172 # here there are 2 refs to 'i' since the declaration doesn't count as
1173 # a ref in the visitor
1174 #
1175 self.assert_num_ID_refs(ps3, 'i', 2)
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001176
1177 def test_whole_file(self):
1178 # See how pycparser handles a whole, real C file.
1179 #
1180 filename = 'c_files/memmgr_with_h.c'
1181 code = open(filename, 'rU').read()
1182 p = self.parse(code)
1183
1184 self.assert_num_klass_nodes(p, FuncDef, 5)
1185
1186 # each FuncDef also has a FuncDecl. 4 declarations
1187 # + 5 definitions, overall 9
1188 self.assert_num_klass_nodes(p, FuncDecl, 9)
1189
1190 self.assert_num_klass_nodes(p, Typedef, 4)
1191
1192 self.assertEqual(p.ext[4].coord.line, 88)
1193 self.assertEqual(p.ext[4].coord.file, "./memmgr.h")
1194
1195 self.assertEqual(p.ext[6].coord.line, 10)
1196 self.assertEqual(p.ext[6].coord.file, "memmgr.c")
1197
1198 def test_whole_file_with_stdio(self):
1199 # Parse a whole file with stdio.h included by cpp
1200 #
1201 filename = 'c_files/cppd_with_stdio_h.c'
1202 code = open(filename, 'rU').read()
1203 p = self.parse(code)
1204
1205 self.failUnless(isinstance(p.ext[0], Typedef))
1206 self.assertEqual(p.ext[0].coord.line, 213)
1207 self.assertEqual(p.ext[0].coord.file, "D:\eli\cpp_stuff\libc_include/stddef.h")
1208
1209 self.failUnless(isinstance(p.ext[-1], FuncDef))
1210 self.assertEqual(p.ext[-1].coord.line, 15)
1211 self.assertEqual(p.ext[-1].coord.file, "example_c_file.c")
1212
1213 self.failUnless(isinstance(p.ext[-8], Typedef))
1214 self.failUnless(isinstance(p.ext[-8].type, TypeDecl))
1215 self.assertEqual(p.ext[-8].name, 'cookie_io_functions_t')
1216
1217
1218if __name__ == '__main__':
1219 #~ suite = unittest.TestLoader().loadTestsFromNames(
1220 #~ ['test_c_parser.TestCParser_fundamentals.test_typedef'])
1221
1222 #~ suite = unittest.TestLoader().loadTestsFromNames(
1223 #~ ['test_c_parser.TestCParser_whole_code.test_whole_file_with_stdio'])
1224
1225 #~ suite = unittest.TestLoader().loadTestsFromTestCase(
1226 #~ TestCParser_whole_code)
1227
1228 #~ unittest.TextTestRunner(verbosity=2).run(suite)
1229 unittest.main()