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