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