blob: d57d8eee5f123222dc4f7833c3191d49a41d8872 [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
612 def test_tags_namespace(self):
613 """ Tests that the tags of structs/unions/enums reside in a separate namespace and
614 can be named after existing types.
615 """
616 s1 = """
617 typedef int tagEntry;
618
619 struct tagEntry
620 {
621 char* key;
622 char* value;
623 } Entry;
624 """
625
626 s1_ast = self.parse(s1)
627 self.assertEqual(expand_decl(s1_ast.ext[1]),
628 ['Decl', 'Entry',
629 ['TypeDecl', ['Struct', 'tagEntry',
630 [['Decl', 'key',
631 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
632 ['Decl', 'value',
633 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
634
635 s2 = """
636 struct tagEntry;
637
638 typedef struct tagEntry tagEntry;
639
640 struct tagEntry
641 {
642 char* key;
643 char* value;
644 } Entry;
645 """
646
647 s2_ast = self.parse(s2)
648 self.assertEqual(expand_decl(s2_ast.ext[2]),
649 ['Decl', 'Entry',
650 ['TypeDecl', ['Struct', 'tagEntry',
651 [['Decl', 'key',
652 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
653 ['Decl', 'value',
654 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
655
656 s3 = """
657 typedef int mytag;
658
659 enum mytag {ABC, CDE};
660 enum mytag joe;
661 """
662
663 s3_type = self.parse(s3).ext[1].type
664
665 self.assertTrue(isinstance(s3_type, Enum))
666 self.assertEqual(s3_type.name, 'mytag')
667
668 def test_multi_decls(self):
669 d1 = 'int a, b;'
670
671 self.assertEqual(self.get_decl(d1, 0),
672 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
673 self.assertEqual(self.get_decl(d1, 1),
674 ['Decl', 'b', ['TypeDecl', ['IdentifierType', ['int']]]])
675
676 d2 = 'char* p, notp, ar[4];'
677 self.assertEqual(self.get_decl(d2, 0),
678 ['Decl', 'p',
679 ['PtrDecl',
680 ['TypeDecl', ['IdentifierType', ['char']]]]])
681 self.assertEqual(self.get_decl(d2, 1),
682 ['Decl', 'notp', ['TypeDecl', ['IdentifierType', ['char']]]])
683 self.assertEqual(self.get_decl(d2, 2),
684 ['Decl', 'ar',
685 ['ArrayDecl', '4',
686 ['TypeDecl', ['IdentifierType', ['char']]]]])
687
688 def test_invalid_multiple_types_error(self):
689 bad = [
690 'int enum {ab, cd} fubr;',
691 'enum kid char brbr;']
692
693 for b in bad:
694 self.assertRaises(ParseError, self.parse, b)
695
696 def test_decl_inits(self):
697 d1 = 'int a = 16;'
698 self.assertEqual(self.get_decl(d1),
699 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
700 self.assertEqual(self.get_decl_init(d1),
701 ['Constant', 'int', '16'])
702
703 d2 = 'long ar[] = {7, 8, 9};'
704 self.assertEqual(self.get_decl(d2),
705 ['Decl', 'ar',
706 ['ArrayDecl', '',
707 ['TypeDecl', ['IdentifierType', ['long']]]]])
708 self.assertEqual(self.get_decl_init(d2),
709 [ ['Constant', 'int', '7'],
710 ['Constant', 'int', '8'],
711 ['Constant', 'int', '9'],])
712
713 d3 = 'char p = j;'
714 self.assertEqual(self.get_decl(d3),
715 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['char']]]])
716 self.assertEqual(self.get_decl_init(d3),
717 ['ID', 'j'])
718
719 d4 = "char x = 'c', *p = {0, 1, 2, {4, 5}, 6};"
720 self.assertEqual(self.get_decl(d4, 0),
721 ['Decl', 'x', ['TypeDecl', ['IdentifierType', ['char']]]])
722 self.assertEqual(self.get_decl_init(d4, 0),
723 ['Constant', 'char', "'c'"])
724 self.assertEqual(self.get_decl(d4, 1),
725 ['Decl', 'p',
726 ['PtrDecl',
727 ['TypeDecl', ['IdentifierType', ['char']]]]])
728 self.assertEqual(self.get_decl_init(d4, 1),
729 [ ['Constant', 'int', '0'],
730 ['Constant', 'int', '1'],
731 ['Constant', 'int', '2'],
732 [ ['Constant', 'int', '4'],
733 ['Constant', 'int', '5']],
734 ['Constant', 'int', '6']])
735
736 def test_function_definitions(self):
737 def parse_fdef(str):
738 return self.parse(str).ext[0]
739
740 def fdef_decl(fdef):
741 return expand_decl(fdef.decl)
742
743 f1 = parse_fdef('''
744 int factorial(int p)
745 {
746 return 3;
747 }
748 ''')
749
750 self.assertEqual(fdef_decl(f1),
751 ['Decl', 'factorial',
752 ['FuncDecl',
753 [['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]]],
754 ['TypeDecl', ['IdentifierType', ['int']]]]])
755
756 self.assertEqual(type(f1.body.stmts[0]), Return)
757 self.assertEqual(f1.body.decls, None)
758
759 f2 = parse_fdef('''
760 char* zzz(int p, char* c)
761 {
762 int a;
763 char b;
764
765 a = b + 2;
766 return 3;
767 }
768 ''')
769
770 self.assertEqual(fdef_decl(f2),
771 ['Decl', 'zzz',
772 ['FuncDecl',
773 [ ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]],
774 ['Decl', 'c', ['PtrDecl',
775 ['TypeDecl', ['IdentifierType', ['char']]]]]],
776 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
777
778 self.assertEqual(list(map(type, f2.body.stmts)),
779 [Assignment, Return])
780 self.assertEqual(len(f2.body.decls), 2)
781
782 f3 = parse_fdef('''
783 char* zzz(p, c)
784 long p, *c;
785 {
786 int a;
787 char b;
788
789 a = b + 2;
790 return 3;
791 }
792 ''')
793
794 self.assertEqual(fdef_decl(f3),
795 ['Decl', 'zzz',
796 ['FuncDecl',
797 [ ['ID', 'p'],
798 ['ID', 'c']],
799 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
800
801 self.assertEqual(list(map(type, f3.body.stmts)),
802 [Assignment, Return])
803 self.assertEqual(len(f3.body.decls), 2)
804
805 self.assertEqual(expand_decl(f3.param_decls[0]),
806 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['long']]]])
807 self.assertEqual(expand_decl(f3.param_decls[1]),
808 ['Decl', 'c', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['long']]]]])
809
810
811class TestCParser_whole_code(unittest.TestCase):
812 """ Testing of parsing whole chunks of code.
813
814 Since I don't want to rely on the structure of ASTs too
815 much, most of these tests are implemented with visitors.
816 """
817 def parse(self, txt, filename=''):
818 return self.cparser.parse(txt, filename)
819
820 def setUp(self):
821 self.cparser = _c_parser
822
823 # A simple helper visitor that lists the values of all the
824 # Constant nodes it sees.
825 #
826 class ConstantVisitor(NodeVisitor):
827 def __init__(self):
828 self.values = []
829
830 def visit_Constant(self, node):
831 self.values.append(node.value)
832
833 # This visitor counts the amount of references to the ID
834 # with the name provided to it in the constructor.
835 #
836 class IDNameCounter(NodeVisitor):
837 def __init__(self, name):
838 self.name = name
839 self.nrefs = 0
840
841 def visit_ID(self, node):
842 if node.name == self.name:
843 self.nrefs += 1
844
845 # Counts the amount of nodes of a given class
846 #
847 class NodeKlassCounter(NodeVisitor):
848 def __init__(self, node_klass):
849 self.klass = node_klass
850 self.n = 0
851
852 def generic_visit(self, node):
853 if node.__class__ == self.klass:
854 self.n += 1
855
856 NodeVisitor.generic_visit(self, node)
857
858 def assert_all_Constants(self, code, constants):
859 """ Asserts that the list of all Constant values (by
860 'preorder' appearance) in the chunk of code is as
861 given.
862 """
863 parsed = self.parse(code)
864 cv = self.ConstantVisitor()
865 cv.visit(parsed)
866 self.assertEqual(cv.values, constants)
867
868 def assert_num_ID_refs(self, code, name, num):
869 """ Asserts the number of references to the ID with
870 the given name.
871 """
872 if isinstance(code, str):
873 parsed = self.parse(code)
874 else:
875 parsed = code
876
877 iv = self.IDNameCounter(name)
878 iv.visit(parsed)
879 self.assertEqual(iv.nrefs, num)
880
881 def assert_num_klass_nodes(self, code, klass, num):
882 """ Asserts the amount of klass nodes in the code.
883 """
884 if isinstance(code, str):
885 parsed = self.parse(code)
886 else:
887 parsed = code
888
889 cv = self.NodeKlassCounter(klass)
890 cv.visit(parsed)
891 self.assertEqual(cv.n, num)
892
893 def test_expressions(self):
894 e1 = '''int k = (r + 10.0) >> 6 + 8 << (3 & 0x14);'''
895 self.assert_all_Constants(e1, ['10.0', '6', '8', '3', '0x14'])
896
897 e2 = r'''char n = '\n', *prefix = "st_";'''
898 self.assert_all_Constants(e2, [r"'\n'", '"st_"'])
899
900 def test_statements(self):
901 s1 = r'''
902 void foo(){
903 if (sp == 1)
904 if (optind >= argc ||
905 argv[optind][0] != '-' || argv[optind][1] == '\0')
906 return -1;
907 else if (strcmp(argv[optind], "--") == 0) {
908 optind++;
909 return -1;
910 }
911 }
912 '''
913
914 self.assert_all_Constants(s1,
915 ['1', '0', r"'-'", '1', r"'\0'", '1', r'"--"', '0', '1'])
916
917 ps1 = self.parse(s1)
918 self.assert_num_ID_refs(ps1, 'argv', 3)
919 self.assert_num_ID_refs(ps1, 'optind', 5)
920
921 self.assert_num_klass_nodes(ps1, If, 3)
922 self.assert_num_klass_nodes(ps1, Return, 2)
923 self.assert_num_klass_nodes(ps1, FuncCall, 1) # strcmp
924 self.assert_num_klass_nodes(ps1, BinaryOp, 7)
925
926 # In the following code, Hash and Node were defined as
927 # int to pacify the parser that sees they're used as
928 # types
929 #
930 s2 = r'''
931 typedef int Hash, Node;
932
933 void HashDestroy(Hash* hash)
934 {
935 unsigned int i;
936
937 if (hash == NULL)
938 return;
939
940 for (i = 0; i < hash->table_size; ++i)
941 {
942 Node* temp = hash->heads[i];
943
944 while (temp != NULL)
945 {
946 Node* temp2 = temp;
947
948 free(temp->entry->key);
949 free(temp->entry->value);
950 free(temp->entry);
951
952 temp = temp->next;
953
954 free(temp2);
955 }
956 }
957
958 free(hash->heads);
959 hash->heads = NULL;
960
961 free(hash);
962 }
963 '''
964
965 ps2 = self.parse(s2)
966 self.assert_num_klass_nodes(ps2, FuncCall, 6)
967 self.assert_num_klass_nodes(ps2, FuncDef, 1)
968 self.assert_num_klass_nodes(ps2, For, 1)
969 self.assert_num_klass_nodes(ps2, While, 1)
970 self.assert_num_klass_nodes(ps2, StructRef, 10)
971
972 # declarations don't count
973 self.assert_num_ID_refs(ps2, 'hash', 6)
974 self.assert_num_ID_refs(ps2, 'i', 4)
975
976 def test_whole_file(self):
977 # See how pycparser handles a whole, real C file.
978 #
979 filename = 'c_files/memmgr_with_h.c'
980 code = open(filename, 'rU').read()
981 p = self.parse(code)
982
983 self.assert_num_klass_nodes(p, FuncDef, 5)
984
985 # each FuncDef also has a FuncDecl. 4 declarations
986 # + 5 definitions, overall 9
987 self.assert_num_klass_nodes(p, FuncDecl, 9)
988
989 self.assert_num_klass_nodes(p, Typedef, 4)
990
991 self.assertEqual(p.ext[4].coord.line, 88)
992 self.assertEqual(p.ext[4].coord.file, "./memmgr.h")
993
994 self.assertEqual(p.ext[6].coord.line, 10)
995 self.assertEqual(p.ext[6].coord.file, "memmgr.c")
996
997 def test_whole_file_with_stdio(self):
998 # Parse a whole file with stdio.h included by cpp
999 #
1000 filename = 'c_files/cppd_with_stdio_h.c'
1001 code = open(filename, 'rU').read()
1002 p = self.parse(code)
1003
1004 self.failUnless(isinstance(p.ext[0], Typedef))
1005 self.assertEqual(p.ext[0].coord.line, 213)
1006 self.assertEqual(p.ext[0].coord.file, "D:\eli\cpp_stuff\libc_include/stddef.h")
1007
1008 self.failUnless(isinstance(p.ext[-1], FuncDef))
1009 self.assertEqual(p.ext[-1].coord.line, 15)
1010 self.assertEqual(p.ext[-1].coord.file, "example_c_file.c")
1011
1012 self.failUnless(isinstance(p.ext[-8], Typedef))
1013 self.failUnless(isinstance(p.ext[-8].type, TypeDecl))
1014 self.assertEqual(p.ext[-8].name, 'cookie_io_functions_t')
1015
1016
1017if __name__ == '__main__':
1018 #~ suite = unittest.TestLoader().loadTestsFromNames(
1019 #~ ['test_c_parser.TestCParser_fundamentals.test_typedef'])
1020
1021 #~ suite = unittest.TestLoader().loadTestsFromNames(
1022 #~ ['test_c_parser.TestCParser_whole_code.test_whole_file_with_stdio'])
1023
1024 #~ suite = unittest.TestLoader().loadTestsFromTestCase(
1025 #~ TestCParser_whole_code)
1026
1027 #~ unittest.TextTestRunner(verbosity=2).run(suite)
1028 unittest.main()