blob: aa75f00afe2ba4f2997992dd1e514a509f9c91c8 [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
310
311 def test_qualifiers_storage_specifiers(self):
312 def assert_qs(txt, index, quals, storage):
313 d = self.parse(txt).ext[index]
314 self.assertEqual(d.quals, quals)
315 self.assertEqual(d.storage, storage)
316
317 assert_qs("extern int p;", 0, [], ['extern'])
318 assert_qs("const long p = 6;", 0, ['const'], [])
319
320 d1 = "static const int p, q, r;"
321 for i in range(3):
322 assert_qs(d1, i, ['const'], ['static'])
323
324 d2 = "static char * const p;"
325 assert_qs(d2, 0, [], ['static'])
326 pdecl = self.parse(d2).ext[0].type
327 self.failUnless(isinstance(pdecl, PtrDecl))
328 self.assertEqual(pdecl.quals, ['const'])
329
330 def test_sizeof(self):
331 e = """
332 void foo()
333 {
334 int a = sizeof k;
335 int b = sizeof(int);
336 int c = sizeof(int**);
337
338 char* p = "just to make sure this parses w/o error...";
339 int d = sizeof(int());
340 }
341 """
342 compound = self.parse(e).ext[0].body
343
344 s1 = compound.decls[0].init
345 self.assertTrue(isinstance(s1, UnaryOp))
346 self.assertEqual(s1.op, 'sizeof')
347 self.assertTrue(isinstance(s1.expr, ID))
348 self.assertEqual(s1.expr.name, 'k')
349
350 s2 = compound.decls[1].init
351 self.assertEqual(expand_decl(s2.expr),
352 ['Typename', ['TypeDecl', ['IdentifierType', ['int']]]])
353
354 s3 = compound.decls[2].init
355 self.assertEqual(expand_decl(s3.expr),
356 ['Typename',
357 ['PtrDecl',
358 ['PtrDecl',
359 ['TypeDecl',
360 ['IdentifierType', ['int']]]]]])
361
362 def test_enums(self):
363 e1 = "enum mycolor op;"
364 e1_type = self.parse(e1).ext[0].type.type
365
366 self.assertTrue(isinstance(e1_type, Enum))
367 self.assertEqual(e1_type.name, 'mycolor')
368 self.assertEqual(e1_type.values, None)
369
370 e2 = "enum mysize {large=20, small, medium} shoes;"
371 e2_type = self.parse(e2).ext[0].type.type
372
373 self.assertTrue(isinstance(e2_type, Enum))
374 self.assertEqual(e2_type.name, 'mysize')
375
376 e2_elist = e2_type.values
377 self.assertTrue(isinstance(e2_elist, EnumeratorList))
378
379 for e2_eval in e2_elist.enumerators:
380 self.assertTrue(isinstance(e2_eval, Enumerator))
381
382 self.assertEqual(e2_elist.enumerators[0].name, 'large')
383 self.assertEqual(e2_elist.enumerators[0].value.value, '20')
384 self.assertEqual(e2_elist.enumerators[2].name, 'medium')
385 self.assertEqual(e2_elist.enumerators[2].value, None)
386
387 # enum with trailing comma (C99 feature)
388 e3 = """
389 enum
390 {
391 red,
392 blue,
393 green,
394 } color;
395 """
396
397 e3_type = self.parse(e3).ext[0].type.type
398 self.assertTrue(isinstance(e3_type, Enum))
399 e3_elist = e3_type.values
400 self.assertTrue(isinstance(e3_elist, EnumeratorList))
401
402 for e3_eval in e3_elist.enumerators:
403 self.assertTrue(isinstance(e3_eval, Enumerator))
404
405 self.assertEqual(e3_elist.enumerators[0].name, 'red')
406 self.assertEqual(e3_elist.enumerators[0].value, None)
407 self.assertEqual(e3_elist.enumerators[1].name, 'blue')
408 self.assertEqual(e3_elist.enumerators[2].name, 'green')
409
410 def test_typedef(self):
411 # without typedef, error
412 s1 = """
413 node k;
414 """
415 self.assertRaises(ParseError, self.parse, s1)
416
417 # now with typedef, works
418 s2 = """
419 typedef void* node;
420 node k;
421 """
422 ps2 = self.parse(s2)
423 self.assertEqual(expand_decl(ps2.ext[0]),
424 ['Typedef', 'node',
425 ['PtrDecl',
426 ['TypeDecl', ['IdentifierType', ['void']]]]])
427
428 self.assertEqual(expand_decl(ps2.ext[1]),
429 ['Decl', 'k',
430 ['TypeDecl', ['IdentifierType', ['node']]]])
431
432 s3 = """
433 typedef int T;
434 typedef T *pT;
435
436 pT aa, bb;
437 """
438 ps3 = self.parse(s3)
439 self.assertEqual(expand_decl(ps3.ext[3]),
440 ['Decl', 'bb',
441 ['TypeDecl', ['IdentifierType', ['pT']]]])
442
443 s4 = '''
444 typedef char* __builtin_va_list;
445 typedef __builtin_va_list __gnuc_va_list;
446 '''
447 ps4 = self.parse(s4)
448 self.assertEqual(expand_decl(ps4.ext[1]),
449 ['Typedef', '__gnuc_va_list',
450 ['TypeDecl',
451 ['IdentifierType', ['__builtin_va_list']]]])
452
453 s5 = '''typedef struct tagHash Hash;'''
454 ps5 = self.parse(s5)
455 self.assertEqual(expand_decl(ps5.ext[0]),
456 ['Typedef', 'Hash', ['TypeDecl', ['Struct', 'tagHash', []]]])
457
458 def test_struct_union(self):
459 s1 = """
460 struct {
461 int id;
462 char* name;
463 } joe;
464 """
465
466 self.assertEqual(expand_decl(self.parse(s1).ext[0]),
467 ['Decl', 'joe',
468 ['TypeDecl', ['Struct', None,
469 [ ['Decl', 'id',
470 ['TypeDecl',
471 ['IdentifierType', ['int']]]],
472 ['Decl', 'name',
473 ['PtrDecl',
474 ['TypeDecl',
475 ['IdentifierType', ['char']]]]]]]]])
476
477 s2 = """
478 struct node p;
479 """
480 self.assertEqual(expand_decl(self.parse(s2).ext[0]),
481 ['Decl', 'p',
482 ['TypeDecl', ['Struct', 'node', []]]])
483
484 s21 = """
485 union pri ra;
486 """
487 self.assertEqual(expand_decl(self.parse(s21).ext[0]),
488 ['Decl', 'ra',
489 ['TypeDecl', ['Union', 'pri', []]]])
490
491 s3 = """
492 struct node* p;
493 """
494 self.assertEqual(expand_decl(self.parse(s3).ext[0]),
495 ['Decl', 'p',
496 ['PtrDecl',
497 ['TypeDecl', ['Struct', 'node', []]]]])
498
499 s4 = """
500 struct node;
501 """
502 self.assertEqual(expand_decl(self.parse(s4).ext[0]),
503 ['Decl', None,
504 ['Struct', 'node', []]])
505
506 s5 = """
507 union
508 {
509 struct
510 {
511 int type;
512 } n;
513
514 struct
515 {
516 int type;
517 int intnode;
518 } ni;
519 } u;
520 """
521 self.assertEqual(expand_decl(self.parse(s5).ext[0]),
522 ['Decl', 'u',
523 ['TypeDecl',
524 ['Union', None,
525 [['Decl', 'n',
526 ['TypeDecl',
527 ['Struct', None,
528 [['Decl', 'type',
529 ['TypeDecl', ['IdentifierType', ['int']]]]]]]],
530 ['Decl', 'ni',
531 ['TypeDecl',
532 ['Struct', None,
533 [['Decl', 'type',
534 ['TypeDecl', ['IdentifierType', ['int']]]],
535 ['Decl', 'intnode',
536 ['TypeDecl', ['IdentifierType', ['int']]]]]]]]]]]])
537
538 s6 = """
539 typedef struct foo_tag
540 {
541 void* data;
542 } foo, *pfoo;
543 """
544 s6_ast = self.parse(s6)
545
546 self.assertEqual(expand_decl(s6_ast.ext[0]),
547 ['Typedef', 'foo',
548 ['TypeDecl',
549 ['Struct', 'foo_tag',
550 [['Decl', 'data',
551 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]])
552
553 self.assertEqual(expand_decl(s6_ast.ext[1]),
554 ['Typedef', 'pfoo',
555 ['PtrDecl',
556 ['TypeDecl',
557 ['Struct', 'foo_tag',
558 [['Decl', 'data',
559 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]]])
560
561 s7 = r"""
562 struct _on_exit_args {
563 void * _fnargs[32];
564 void * _dso_handle[32];
565
566 long _fntypes;
567 #line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
568
569 long _is_cxa;
570 };
571 """
572
573 s7_ast = self.parse(s7, filename='test.c')
574 self.assert_coord(s7_ast.ext[0].type.decls[2], 6, 'test.c')
575 self.assert_coord(s7_ast.ext[0].type.decls[3], 78,
576 r'D:\eli\cpp_stuff\libc_include/sys/reent.h')
577
578 s8 = """
579 typedef enum tagReturnCode {SUCCESS, FAIL} ReturnCode;
580
581 typedef struct tagEntry
582 {
583 char* key;
584 char* value;
585 } Entry;
586
587
588 typedef struct tagNode
589 {
590 Entry* entry;
591
592 struct tagNode* next;
593 } Node;
594
595 typedef struct tagHash
596 {
597 unsigned int table_size;
598
599 Node** heads;
600
601 } Hash;
602 """
603 s8_ast = self.parse(s8)
604 self.assertEqual(expand_decl(s8_ast.ext[3]),
605 ['Typedef', 'Hash',
606 ['TypeDecl', ['Struct', 'tagHash',
607 [['Decl', 'table_size',
608 ['TypeDecl', ['IdentifierType', ['int', 'unsigned']]]],
609 ['Decl', 'heads',
610 ['PtrDecl', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['Node']]]]]]]]]])
611
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200612 def test_struct_bitfields(self):
eli.bendersky38ed9a92010-10-09 09:29:59 +0200613 # a struct with two bitfields, one unnamed
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200614 s1 = """
615 struct {
616 int k:6;
617 int :2;
618 } joe;
619 """
620
621 parsed_struct = self.parse(s1).ext[0]
622
eli.bendersky38ed9a92010-10-09 09:29:59 +0200623 # We can see here the name of the decl for the unnamed bitfield is
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200624 # None, but expand_decl doesn't show bitfield widths
625 # ...
626 self.assertEqual(expand_decl(parsed_struct),
627 ['Decl', 'joe',
628 ['TypeDecl', ['Struct', None,
629 [ ['Decl', 'k',
630 ['TypeDecl',
631 ['IdentifierType', ['int']]]],
632 ['Decl', None,
633 ['TypeDecl',
634 ['IdentifierType', ['int']]]]]]]])
635
636 # ...
637 # so we test them manually
638 self.assertEqual(parsed_struct.type.type.decls[0].bitsize.value, '6')
639 self.assertEqual(parsed_struct.type.type.decls[1].bitsize.value, '2')
640
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300641 def test_tags_namespace(self):
642 """ Tests that the tags of structs/unions/enums reside in a separate namespace and
643 can be named after existing types.
644 """
645 s1 = """
646 typedef int tagEntry;
647
648 struct tagEntry
649 {
650 char* key;
651 char* value;
652 } Entry;
653 """
654
655 s1_ast = self.parse(s1)
656 self.assertEqual(expand_decl(s1_ast.ext[1]),
657 ['Decl', 'Entry',
658 ['TypeDecl', ['Struct', 'tagEntry',
659 [['Decl', 'key',
660 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
661 ['Decl', 'value',
662 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
663
664 s2 = """
665 struct tagEntry;
666
667 typedef struct tagEntry tagEntry;
668
669 struct tagEntry
670 {
671 char* key;
672 char* value;
673 } Entry;
674 """
675
676 s2_ast = self.parse(s2)
677 self.assertEqual(expand_decl(s2_ast.ext[2]),
678 ['Decl', 'Entry',
679 ['TypeDecl', ['Struct', 'tagEntry',
680 [['Decl', 'key',
681 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
682 ['Decl', 'value',
683 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
684
685 s3 = """
686 typedef int mytag;
687
688 enum mytag {ABC, CDE};
689 enum mytag joe;
690 """
691
692 s3_type = self.parse(s3).ext[1].type
693
694 self.assertTrue(isinstance(s3_type, Enum))
695 self.assertEqual(s3_type.name, 'mytag')
696
697 def test_multi_decls(self):
698 d1 = 'int a, b;'
699
700 self.assertEqual(self.get_decl(d1, 0),
701 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
702 self.assertEqual(self.get_decl(d1, 1),
703 ['Decl', 'b', ['TypeDecl', ['IdentifierType', ['int']]]])
704
705 d2 = 'char* p, notp, ar[4];'
706 self.assertEqual(self.get_decl(d2, 0),
707 ['Decl', 'p',
708 ['PtrDecl',
709 ['TypeDecl', ['IdentifierType', ['char']]]]])
710 self.assertEqual(self.get_decl(d2, 1),
711 ['Decl', 'notp', ['TypeDecl', ['IdentifierType', ['char']]]])
712 self.assertEqual(self.get_decl(d2, 2),
713 ['Decl', 'ar',
714 ['ArrayDecl', '4',
715 ['TypeDecl', ['IdentifierType', ['char']]]]])
716
717 def test_invalid_multiple_types_error(self):
718 bad = [
719 'int enum {ab, cd} fubr;',
720 'enum kid char brbr;']
721
722 for b in bad:
723 self.assertRaises(ParseError, self.parse, b)
724
725 def test_decl_inits(self):
726 d1 = 'int a = 16;'
727 self.assertEqual(self.get_decl(d1),
728 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
729 self.assertEqual(self.get_decl_init(d1),
730 ['Constant', 'int', '16'])
731
732 d2 = 'long ar[] = {7, 8, 9};'
733 self.assertEqual(self.get_decl(d2),
734 ['Decl', 'ar',
735 ['ArrayDecl', '',
736 ['TypeDecl', ['IdentifierType', ['long']]]]])
737 self.assertEqual(self.get_decl_init(d2),
738 [ ['Constant', 'int', '7'],
739 ['Constant', 'int', '8'],
740 ['Constant', 'int', '9'],])
741
742 d3 = 'char p = j;'
743 self.assertEqual(self.get_decl(d3),
744 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['char']]]])
745 self.assertEqual(self.get_decl_init(d3),
746 ['ID', 'j'])
747
748 d4 = "char x = 'c', *p = {0, 1, 2, {4, 5}, 6};"
749 self.assertEqual(self.get_decl(d4, 0),
750 ['Decl', 'x', ['TypeDecl', ['IdentifierType', ['char']]]])
751 self.assertEqual(self.get_decl_init(d4, 0),
752 ['Constant', 'char', "'c'"])
753 self.assertEqual(self.get_decl(d4, 1),
754 ['Decl', 'p',
755 ['PtrDecl',
756 ['TypeDecl', ['IdentifierType', ['char']]]]])
757 self.assertEqual(self.get_decl_init(d4, 1),
758 [ ['Constant', 'int', '0'],
759 ['Constant', 'int', '1'],
760 ['Constant', 'int', '2'],
761 [ ['Constant', 'int', '4'],
762 ['Constant', 'int', '5']],
763 ['Constant', 'int', '6']])
764
765 def test_function_definitions(self):
766 def parse_fdef(str):
767 return self.parse(str).ext[0]
768
769 def fdef_decl(fdef):
770 return expand_decl(fdef.decl)
771
772 f1 = parse_fdef('''
773 int factorial(int p)
774 {
775 return 3;
776 }
777 ''')
778
779 self.assertEqual(fdef_decl(f1),
780 ['Decl', 'factorial',
781 ['FuncDecl',
782 [['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]]],
783 ['TypeDecl', ['IdentifierType', ['int']]]]])
784
785 self.assertEqual(type(f1.body.stmts[0]), Return)
786 self.assertEqual(f1.body.decls, None)
787
788 f2 = parse_fdef('''
789 char* zzz(int p, char* c)
790 {
791 int a;
792 char b;
793
794 a = b + 2;
795 return 3;
796 }
797 ''')
798
799 self.assertEqual(fdef_decl(f2),
800 ['Decl', 'zzz',
801 ['FuncDecl',
802 [ ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]],
803 ['Decl', 'c', ['PtrDecl',
804 ['TypeDecl', ['IdentifierType', ['char']]]]]],
805 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
806
807 self.assertEqual(list(map(type, f2.body.stmts)),
808 [Assignment, Return])
809 self.assertEqual(len(f2.body.decls), 2)
810
811 f3 = parse_fdef('''
812 char* zzz(p, c)
813 long p, *c;
814 {
815 int a;
816 char b;
817
818 a = b + 2;
819 return 3;
820 }
821 ''')
822
823 self.assertEqual(fdef_decl(f3),
824 ['Decl', 'zzz',
825 ['FuncDecl',
826 [ ['ID', 'p'],
827 ['ID', 'c']],
828 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
829
830 self.assertEqual(list(map(type, f3.body.stmts)),
831 [Assignment, Return])
832 self.assertEqual(len(f3.body.decls), 2)
833
834 self.assertEqual(expand_decl(f3.param_decls[0]),
835 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['long']]]])
836 self.assertEqual(expand_decl(f3.param_decls[1]),
837 ['Decl', 'c', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['long']]]]])
838
eli.bendersky71540662010-07-03 12:58:52 +0200839 def test_unified_string_literals(self):
840 # simple string, for reference
841 d1 = self.get_decl_init('char* s = "hello";')
842 self.assertEqual(d1, ['Constant', 'string', '"hello"'])
843
844 d2 = self.get_decl_init('char* s = "hello" " world";')
845 self.assertEqual(d2, ['Constant', 'string', '"hello world"'])
846
847 # the test case from issue 6
848 d3 = self.parse(r'''
849 int main() {
850 fprintf(stderr,
851 "Wrong Params?\n"
852 "Usage:\n"
853 "%s <binary_file_path>\n",
854 argv[0]
855 );
856 }
857 ''')
858
859 self.assertEqual(
860 d3.ext[0].body.stmts[0].args.exprs[1].value,
861 r'"Wrong Params?\nUsage:\n%s <binary_file_path>\n"')
eli.bendersky4a89f112010-07-05 06:02:03 +0200862
863 d4 = self.get_decl_init('char* s = "" "foobar";')
864 self.assertEqual(d4, ['Constant', 'string', '"foobar"'])
865
866 d5 = self.get_decl_init(r'char* s = "foo\"" "bar";')
867 self.assertEqual(d5, ['Constant', 'string', r'"foo\"bar"'])
eli.bendersky71540662010-07-03 12:58:52 +0200868
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300869
870class TestCParser_whole_code(unittest.TestCase):
871 """ Testing of parsing whole chunks of code.
872
873 Since I don't want to rely on the structure of ASTs too
874 much, most of these tests are implemented with visitors.
875 """
876 def parse(self, txt, filename=''):
877 return self.cparser.parse(txt, filename)
878
879 def setUp(self):
880 self.cparser = _c_parser
881
882 # A simple helper visitor that lists the values of all the
883 # Constant nodes it sees.
884 #
885 class ConstantVisitor(NodeVisitor):
886 def __init__(self):
887 self.values = []
888
889 def visit_Constant(self, node):
890 self.values.append(node.value)
891
892 # This visitor counts the amount of references to the ID
893 # with the name provided to it in the constructor.
894 #
895 class IDNameCounter(NodeVisitor):
896 def __init__(self, name):
897 self.name = name
898 self.nrefs = 0
899
900 def visit_ID(self, node):
901 if node.name == self.name:
902 self.nrefs += 1
903
904 # Counts the amount of nodes of a given class
905 #
906 class NodeKlassCounter(NodeVisitor):
907 def __init__(self, node_klass):
908 self.klass = node_klass
909 self.n = 0
910
911 def generic_visit(self, node):
912 if node.__class__ == self.klass:
913 self.n += 1
914
915 NodeVisitor.generic_visit(self, node)
916
917 def assert_all_Constants(self, code, constants):
918 """ Asserts that the list of all Constant values (by
919 'preorder' appearance) in the chunk of code is as
920 given.
921 """
eli.benderskyed890492010-06-25 08:25:55 +0300922 if isinstance(code, str):
923 parsed = self.parse(code)
924 else:
925 parsed = code
926
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300927 cv = self.ConstantVisitor()
928 cv.visit(parsed)
929 self.assertEqual(cv.values, constants)
930
931 def assert_num_ID_refs(self, code, name, num):
932 """ Asserts the number of references to the ID with
933 the given name.
934 """
935 if isinstance(code, str):
936 parsed = self.parse(code)
937 else:
938 parsed = code
939
940 iv = self.IDNameCounter(name)
941 iv.visit(parsed)
942 self.assertEqual(iv.nrefs, num)
943
944 def assert_num_klass_nodes(self, code, klass, num):
945 """ Asserts the amount of klass nodes in the code.
946 """
947 if isinstance(code, str):
948 parsed = self.parse(code)
949 else:
950 parsed = code
951
952 cv = self.NodeKlassCounter(klass)
953 cv.visit(parsed)
954 self.assertEqual(cv.n, num)
955
956 def test_expressions(self):
957 e1 = '''int k = (r + 10.0) >> 6 + 8 << (3 & 0x14);'''
958 self.assert_all_Constants(e1, ['10.0', '6', '8', '3', '0x14'])
959
960 e2 = r'''char n = '\n', *prefix = "st_";'''
961 self.assert_all_Constants(e2, [r"'\n'", '"st_"'])
962
963 def test_statements(self):
964 s1 = r'''
965 void foo(){
966 if (sp == 1)
967 if (optind >= argc ||
968 argv[optind][0] != '-' || argv[optind][1] == '\0')
969 return -1;
970 else if (strcmp(argv[optind], "--") == 0) {
971 optind++;
972 return -1;
973 }
974 }
975 '''
976
977 self.assert_all_Constants(s1,
978 ['1', '0', r"'-'", '1', r"'\0'", '1', r'"--"', '0', '1'])
979
980 ps1 = self.parse(s1)
981 self.assert_num_ID_refs(ps1, 'argv', 3)
982 self.assert_num_ID_refs(ps1, 'optind', 5)
983
984 self.assert_num_klass_nodes(ps1, If, 3)
985 self.assert_num_klass_nodes(ps1, Return, 2)
986 self.assert_num_klass_nodes(ps1, FuncCall, 1) # strcmp
987 self.assert_num_klass_nodes(ps1, BinaryOp, 7)
988
989 # In the following code, Hash and Node were defined as
990 # int to pacify the parser that sees they're used as
991 # types
992 #
993 s2 = r'''
994 typedef int Hash, Node;
995
996 void HashDestroy(Hash* hash)
997 {
998 unsigned int i;
999
1000 if (hash == NULL)
1001 return;
1002
1003 for (i = 0; i < hash->table_size; ++i)
1004 {
1005 Node* temp = hash->heads[i];
1006
1007 while (temp != NULL)
1008 {
1009 Node* temp2 = temp;
1010
1011 free(temp->entry->key);
1012 free(temp->entry->value);
1013 free(temp->entry);
1014
1015 temp = temp->next;
1016
1017 free(temp2);
1018 }
1019 }
1020
1021 free(hash->heads);
1022 hash->heads = NULL;
1023
1024 free(hash);
1025 }
1026 '''
1027
1028 ps2 = self.parse(s2)
1029 self.assert_num_klass_nodes(ps2, FuncCall, 6)
1030 self.assert_num_klass_nodes(ps2, FuncDef, 1)
1031 self.assert_num_klass_nodes(ps2, For, 1)
1032 self.assert_num_klass_nodes(ps2, While, 1)
1033 self.assert_num_klass_nodes(ps2, StructRef, 10)
1034
1035 # declarations don't count
1036 self.assert_num_ID_refs(ps2, 'hash', 6)
1037 self.assert_num_ID_refs(ps2, 'i', 4)
eli.benderskyed890492010-06-25 08:25:55 +03001038
1039 s3 = r'''
1040 void x(void) {
1041 int a, b;
1042 if (a < b)
1043 do {
1044 a = 0;
1045 } while (0);
1046 else if (a == b) {
1047 a = 1;
1048 }
1049 }
1050 '''
1051
1052 ps3 = self.parse(s3)
1053 self.assert_num_klass_nodes(ps3, DoWhile, 1)
1054 self.assert_num_ID_refs(ps3, 'a', 4)
1055 self.assert_all_Constants(ps3, ['0', '0', '1'])
eli.bendersky145890d2010-10-29 12:02:32 +02001056
1057 def test_for_statement(self):
1058 s2 = r'''
1059 void x(void)
1060 {
1061 int i;
1062 for (i = 0; i < 5; ++i) {
1063 x = 50;
1064 }
1065 }
1066 '''
1067 ps2 = self.parse(s2)
1068 self.assert_num_klass_nodes(ps2, For, 1)
1069 # here there are 3 refs to 'i' since the declaration doesn't count as
1070 # a ref in the visitor
1071 #
1072 self.assert_num_ID_refs(ps2, 'i', 3)
eli.benderskyed890492010-06-25 08:25:55 +03001073
eli.bendersky145890d2010-10-29 12:02:32 +02001074 s3 = r'''
1075 void x(void)
1076 {
1077 for (int i = 0; i < 5; ++i) {
1078 x = 50;
1079 }
1080 }
1081 '''
1082 ps3 = self.parse(s3)
1083 ps3.show()
1084 self.assert_num_klass_nodes(ps3, For, 1)
1085 # here there are 2 refs to 'i' since the declaration doesn't count as
1086 # a ref in the visitor
1087 #
1088 self.assert_num_ID_refs(ps3, 'i', 2)
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001089
1090 def test_whole_file(self):
1091 # See how pycparser handles a whole, real C file.
1092 #
1093 filename = 'c_files/memmgr_with_h.c'
1094 code = open(filename, 'rU').read()
1095 p = self.parse(code)
1096
1097 self.assert_num_klass_nodes(p, FuncDef, 5)
1098
1099 # each FuncDef also has a FuncDecl. 4 declarations
1100 # + 5 definitions, overall 9
1101 self.assert_num_klass_nodes(p, FuncDecl, 9)
1102
1103 self.assert_num_klass_nodes(p, Typedef, 4)
1104
1105 self.assertEqual(p.ext[4].coord.line, 88)
1106 self.assertEqual(p.ext[4].coord.file, "./memmgr.h")
1107
1108 self.assertEqual(p.ext[6].coord.line, 10)
1109 self.assertEqual(p.ext[6].coord.file, "memmgr.c")
1110
1111 def test_whole_file_with_stdio(self):
1112 # Parse a whole file with stdio.h included by cpp
1113 #
1114 filename = 'c_files/cppd_with_stdio_h.c'
1115 code = open(filename, 'rU').read()
1116 p = self.parse(code)
1117
1118 self.failUnless(isinstance(p.ext[0], Typedef))
1119 self.assertEqual(p.ext[0].coord.line, 213)
1120 self.assertEqual(p.ext[0].coord.file, "D:\eli\cpp_stuff\libc_include/stddef.h")
1121
1122 self.failUnless(isinstance(p.ext[-1], FuncDef))
1123 self.assertEqual(p.ext[-1].coord.line, 15)
1124 self.assertEqual(p.ext[-1].coord.file, "example_c_file.c")
1125
1126 self.failUnless(isinstance(p.ext[-8], Typedef))
1127 self.failUnless(isinstance(p.ext[-8].type, TypeDecl))
1128 self.assertEqual(p.ext[-8].name, 'cookie_io_functions_t')
1129
1130
1131if __name__ == '__main__':
1132 #~ suite = unittest.TestLoader().loadTestsFromNames(
1133 #~ ['test_c_parser.TestCParser_fundamentals.test_typedef'])
1134
1135 #~ suite = unittest.TestLoader().loadTestsFromNames(
1136 #~ ['test_c_parser.TestCParser_whole_code.test_whole_file_with_stdio'])
1137
1138 #~ suite = unittest.TestLoader().loadTestsFromTestCase(
1139 #~ TestCParser_whole_code)
1140
1141 #~ unittest.TextTestRunner(verbosity=2).run(suite)
1142 unittest.main()