blob: 96a6a0237cf51efd15066fb650376bd8beeb684e [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.bendersky9f481562010-10-30 15:50:47 +0200379 # The C99 compound literal feature
380 #
eli.benderskyf890a862010-10-30 12:13:23 +0200381 def test_compound_literals(self):
eli.bendersky9f481562010-10-30 15:50:47 +0200382 ps1 = self.parse(r'''
eli.benderskyf890a862010-10-30 12:13:23 +0200383 void foo() {
eli.bendersky9f481562010-10-30 15:50:47 +0200384 p = (long long){k};
385 tc = (struct jk){.a = {1, 2}, .b[0] = t};
386 }''')
eli.benderskyf890a862010-10-30 12:13:23 +0200387
eli.bendersky9f481562010-10-30 15:50:47 +0200388 compound = ps1.ext[0].body.block_items[0].rvalue
389 self.assertEqual(expand_decl(compound.type),
390 ['Typename', ['TypeDecl', ['IdentifierType', ['long', 'long']]]])
391 self.assertEqual(expand_init(compound.init),
392 [['ID', 'k']])
393
394 compound = ps1.ext[0].body.block_items[1].rvalue
395 self.assertEqual(expand_decl(compound.type),
396 ['Typename', ['TypeDecl', ['Struct', 'jk', []]]])
397 self.assertEqual(expand_init(compound.init),
398 [
399 ([['ID', 'a']], [['Constant', 'int', '1'], ['Constant', 'int', '2']]),
400 ([['ID', 'b'], ['Constant', 'int', '0']], ['ID', 't'])])
eli.benderskyf890a862010-10-30 12:13:23 +0200401
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300402 def test_enums(self):
403 e1 = "enum mycolor op;"
404 e1_type = self.parse(e1).ext[0].type.type
405
406 self.assertTrue(isinstance(e1_type, Enum))
407 self.assertEqual(e1_type.name, 'mycolor')
408 self.assertEqual(e1_type.values, None)
409
410 e2 = "enum mysize {large=20, small, medium} shoes;"
411 e2_type = self.parse(e2).ext[0].type.type
412
413 self.assertTrue(isinstance(e2_type, Enum))
414 self.assertEqual(e2_type.name, 'mysize')
415
416 e2_elist = e2_type.values
417 self.assertTrue(isinstance(e2_elist, EnumeratorList))
418
419 for e2_eval in e2_elist.enumerators:
420 self.assertTrue(isinstance(e2_eval, Enumerator))
421
422 self.assertEqual(e2_elist.enumerators[0].name, 'large')
423 self.assertEqual(e2_elist.enumerators[0].value.value, '20')
424 self.assertEqual(e2_elist.enumerators[2].name, 'medium')
425 self.assertEqual(e2_elist.enumerators[2].value, None)
426
427 # enum with trailing comma (C99 feature)
428 e3 = """
429 enum
430 {
431 red,
432 blue,
433 green,
434 } color;
435 """
436
437 e3_type = self.parse(e3).ext[0].type.type
438 self.assertTrue(isinstance(e3_type, Enum))
439 e3_elist = e3_type.values
440 self.assertTrue(isinstance(e3_elist, EnumeratorList))
441
442 for e3_eval in e3_elist.enumerators:
443 self.assertTrue(isinstance(e3_eval, Enumerator))
444
445 self.assertEqual(e3_elist.enumerators[0].name, 'red')
446 self.assertEqual(e3_elist.enumerators[0].value, None)
447 self.assertEqual(e3_elist.enumerators[1].name, 'blue')
448 self.assertEqual(e3_elist.enumerators[2].name, 'green')
449
450 def test_typedef(self):
451 # without typedef, error
452 s1 = """
453 node k;
454 """
455 self.assertRaises(ParseError, self.parse, s1)
456
457 # now with typedef, works
458 s2 = """
459 typedef void* node;
460 node k;
461 """
462 ps2 = self.parse(s2)
463 self.assertEqual(expand_decl(ps2.ext[0]),
464 ['Typedef', 'node',
465 ['PtrDecl',
466 ['TypeDecl', ['IdentifierType', ['void']]]]])
467
468 self.assertEqual(expand_decl(ps2.ext[1]),
469 ['Decl', 'k',
470 ['TypeDecl', ['IdentifierType', ['node']]]])
471
472 s3 = """
473 typedef int T;
474 typedef T *pT;
475
476 pT aa, bb;
477 """
478 ps3 = self.parse(s3)
479 self.assertEqual(expand_decl(ps3.ext[3]),
480 ['Decl', 'bb',
481 ['TypeDecl', ['IdentifierType', ['pT']]]])
482
483 s4 = '''
484 typedef char* __builtin_va_list;
485 typedef __builtin_va_list __gnuc_va_list;
486 '''
487 ps4 = self.parse(s4)
488 self.assertEqual(expand_decl(ps4.ext[1]),
489 ['Typedef', '__gnuc_va_list',
490 ['TypeDecl',
491 ['IdentifierType', ['__builtin_va_list']]]])
492
493 s5 = '''typedef struct tagHash Hash;'''
494 ps5 = self.parse(s5)
495 self.assertEqual(expand_decl(ps5.ext[0]),
496 ['Typedef', 'Hash', ['TypeDecl', ['Struct', 'tagHash', []]]])
497
498 def test_struct_union(self):
499 s1 = """
500 struct {
501 int id;
502 char* name;
503 } joe;
504 """
505
506 self.assertEqual(expand_decl(self.parse(s1).ext[0]),
507 ['Decl', 'joe',
508 ['TypeDecl', ['Struct', None,
509 [ ['Decl', 'id',
510 ['TypeDecl',
511 ['IdentifierType', ['int']]]],
512 ['Decl', 'name',
513 ['PtrDecl',
514 ['TypeDecl',
515 ['IdentifierType', ['char']]]]]]]]])
516
517 s2 = """
518 struct node p;
519 """
520 self.assertEqual(expand_decl(self.parse(s2).ext[0]),
521 ['Decl', 'p',
522 ['TypeDecl', ['Struct', 'node', []]]])
523
524 s21 = """
525 union pri ra;
526 """
527 self.assertEqual(expand_decl(self.parse(s21).ext[0]),
528 ['Decl', 'ra',
529 ['TypeDecl', ['Union', 'pri', []]]])
530
531 s3 = """
532 struct node* p;
533 """
534 self.assertEqual(expand_decl(self.parse(s3).ext[0]),
535 ['Decl', 'p',
536 ['PtrDecl',
537 ['TypeDecl', ['Struct', 'node', []]]]])
538
539 s4 = """
540 struct node;
541 """
542 self.assertEqual(expand_decl(self.parse(s4).ext[0]),
543 ['Decl', None,
544 ['Struct', 'node', []]])
545
546 s5 = """
547 union
548 {
549 struct
550 {
551 int type;
552 } n;
553
554 struct
555 {
556 int type;
557 int intnode;
558 } ni;
559 } u;
560 """
561 self.assertEqual(expand_decl(self.parse(s5).ext[0]),
562 ['Decl', 'u',
563 ['TypeDecl',
564 ['Union', None,
565 [['Decl', 'n',
566 ['TypeDecl',
567 ['Struct', None,
568 [['Decl', 'type',
569 ['TypeDecl', ['IdentifierType', ['int']]]]]]]],
570 ['Decl', 'ni',
571 ['TypeDecl',
572 ['Struct', None,
573 [['Decl', 'type',
574 ['TypeDecl', ['IdentifierType', ['int']]]],
575 ['Decl', 'intnode',
576 ['TypeDecl', ['IdentifierType', ['int']]]]]]]]]]]])
577
578 s6 = """
579 typedef struct foo_tag
580 {
581 void* data;
582 } foo, *pfoo;
583 """
584 s6_ast = self.parse(s6)
585
586 self.assertEqual(expand_decl(s6_ast.ext[0]),
587 ['Typedef', 'foo',
588 ['TypeDecl',
589 ['Struct', 'foo_tag',
590 [['Decl', 'data',
591 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]])
592
593 self.assertEqual(expand_decl(s6_ast.ext[1]),
594 ['Typedef', 'pfoo',
595 ['PtrDecl',
596 ['TypeDecl',
597 ['Struct', 'foo_tag',
598 [['Decl', 'data',
599 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]]])
600
601 s7 = r"""
602 struct _on_exit_args {
603 void * _fnargs[32];
604 void * _dso_handle[32];
605
606 long _fntypes;
607 #line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
608
609 long _is_cxa;
610 };
611 """
612
613 s7_ast = self.parse(s7, filename='test.c')
614 self.assert_coord(s7_ast.ext[0].type.decls[2], 6, 'test.c')
615 self.assert_coord(s7_ast.ext[0].type.decls[3], 78,
616 r'D:\eli\cpp_stuff\libc_include/sys/reent.h')
617
618 s8 = """
619 typedef enum tagReturnCode {SUCCESS, FAIL} ReturnCode;
620
621 typedef struct tagEntry
622 {
623 char* key;
624 char* value;
625 } Entry;
626
627
628 typedef struct tagNode
629 {
630 Entry* entry;
631
632 struct tagNode* next;
633 } Node;
634
635 typedef struct tagHash
636 {
637 unsigned int table_size;
638
639 Node** heads;
640
641 } Hash;
642 """
643 s8_ast = self.parse(s8)
644 self.assertEqual(expand_decl(s8_ast.ext[3]),
645 ['Typedef', 'Hash',
646 ['TypeDecl', ['Struct', 'tagHash',
647 [['Decl', 'table_size',
648 ['TypeDecl', ['IdentifierType', ['int', 'unsigned']]]],
649 ['Decl', 'heads',
650 ['PtrDecl', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['Node']]]]]]]]]])
651
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200652 def test_struct_bitfields(self):
eli.bendersky38ed9a92010-10-09 09:29:59 +0200653 # a struct with two bitfields, one unnamed
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200654 s1 = """
655 struct {
656 int k:6;
657 int :2;
658 } joe;
659 """
660
661 parsed_struct = self.parse(s1).ext[0]
662
eli.bendersky38ed9a92010-10-09 09:29:59 +0200663 # We can see here the name of the decl for the unnamed bitfield is
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200664 # None, but expand_decl doesn't show bitfield widths
665 # ...
666 self.assertEqual(expand_decl(parsed_struct),
667 ['Decl', 'joe',
668 ['TypeDecl', ['Struct', None,
669 [ ['Decl', 'k',
670 ['TypeDecl',
671 ['IdentifierType', ['int']]]],
672 ['Decl', None,
673 ['TypeDecl',
674 ['IdentifierType', ['int']]]]]]]])
675
676 # ...
677 # so we test them manually
678 self.assertEqual(parsed_struct.type.type.decls[0].bitsize.value, '6')
679 self.assertEqual(parsed_struct.type.type.decls[1].bitsize.value, '2')
680
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300681 def test_tags_namespace(self):
682 """ Tests that the tags of structs/unions/enums reside in a separate namespace and
683 can be named after existing types.
684 """
685 s1 = """
686 typedef int tagEntry;
687
688 struct tagEntry
689 {
690 char* key;
691 char* value;
692 } Entry;
693 """
694
695 s1_ast = self.parse(s1)
696 self.assertEqual(expand_decl(s1_ast.ext[1]),
697 ['Decl', 'Entry',
698 ['TypeDecl', ['Struct', 'tagEntry',
699 [['Decl', 'key',
700 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
701 ['Decl', 'value',
702 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
703
704 s2 = """
705 struct tagEntry;
706
707 typedef struct tagEntry tagEntry;
708
709 struct tagEntry
710 {
711 char* key;
712 char* value;
713 } Entry;
714 """
715
716 s2_ast = self.parse(s2)
717 self.assertEqual(expand_decl(s2_ast.ext[2]),
718 ['Decl', 'Entry',
719 ['TypeDecl', ['Struct', 'tagEntry',
720 [['Decl', 'key',
721 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
722 ['Decl', 'value',
723 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
724
725 s3 = """
726 typedef int mytag;
727
728 enum mytag {ABC, CDE};
729 enum mytag joe;
730 """
731
732 s3_type = self.parse(s3).ext[1].type
733
734 self.assertTrue(isinstance(s3_type, Enum))
735 self.assertEqual(s3_type.name, 'mytag')
736
737 def test_multi_decls(self):
738 d1 = 'int a, b;'
739
740 self.assertEqual(self.get_decl(d1, 0),
741 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
742 self.assertEqual(self.get_decl(d1, 1),
743 ['Decl', 'b', ['TypeDecl', ['IdentifierType', ['int']]]])
744
745 d2 = 'char* p, notp, ar[4];'
746 self.assertEqual(self.get_decl(d2, 0),
747 ['Decl', 'p',
748 ['PtrDecl',
749 ['TypeDecl', ['IdentifierType', ['char']]]]])
750 self.assertEqual(self.get_decl(d2, 1),
751 ['Decl', 'notp', ['TypeDecl', ['IdentifierType', ['char']]]])
752 self.assertEqual(self.get_decl(d2, 2),
753 ['Decl', 'ar',
754 ['ArrayDecl', '4',
755 ['TypeDecl', ['IdentifierType', ['char']]]]])
756
757 def test_invalid_multiple_types_error(self):
758 bad = [
759 'int enum {ab, cd} fubr;',
760 'enum kid char brbr;']
761
762 for b in bad:
763 self.assertRaises(ParseError, self.parse, b)
764
765 def test_decl_inits(self):
766 d1 = 'int a = 16;'
eli.benderskyf890a862010-10-30 12:13:23 +0200767 #~ self.parse(d1).show()
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300768 self.assertEqual(self.get_decl(d1),
769 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
770 self.assertEqual(self.get_decl_init(d1),
771 ['Constant', 'int', '16'])
772
773 d2 = 'long ar[] = {7, 8, 9};'
eli.benderskyf890a862010-10-30 12:13:23 +0200774 #~ self.parse(d2).show()
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300775 self.assertEqual(self.get_decl(d2),
776 ['Decl', 'ar',
777 ['ArrayDecl', '',
778 ['TypeDecl', ['IdentifierType', ['long']]]]])
779 self.assertEqual(self.get_decl_init(d2),
780 [ ['Constant', 'int', '7'],
781 ['Constant', 'int', '8'],
eli.benderskyf890a862010-10-30 12:13:23 +0200782 ['Constant', 'int', '9']])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300783
784 d3 = 'char p = j;'
785 self.assertEqual(self.get_decl(d3),
786 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['char']]]])
787 self.assertEqual(self.get_decl_init(d3),
788 ['ID', 'j'])
789
790 d4 = "char x = 'c', *p = {0, 1, 2, {4, 5}, 6};"
791 self.assertEqual(self.get_decl(d4, 0),
792 ['Decl', 'x', ['TypeDecl', ['IdentifierType', ['char']]]])
793 self.assertEqual(self.get_decl_init(d4, 0),
794 ['Constant', 'char', "'c'"])
795 self.assertEqual(self.get_decl(d4, 1),
796 ['Decl', 'p',
797 ['PtrDecl',
798 ['TypeDecl', ['IdentifierType', ['char']]]]])
eli.benderskyf890a862010-10-30 12:13:23 +0200799
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300800 self.assertEqual(self.get_decl_init(d4, 1),
801 [ ['Constant', 'int', '0'],
802 ['Constant', 'int', '1'],
803 ['Constant', 'int', '2'],
eli.benderskyf890a862010-10-30 12:13:23 +0200804 [['Constant', 'int', '4'],
805 ['Constant', 'int', '5']],
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300806 ['Constant', 'int', '6']])
eli.benderskyf890a862010-10-30 12:13:23 +0200807
808 def test_decl_named_inits(self):
809 d1 = 'int a = {.k = 16};'
810 self.assertEqual(self.get_decl_init(d1),
811 [( [['ID', 'k']],
812 ['Constant', 'int', '16'])])
813
814 d2 = 'int a = { [0].a = {1}, [1].a[0] = 2 };'
815 self.assertEqual(self.get_decl_init(d2),
816 [
817 ([['Constant', 'int', '0'], ['ID', 'a']],
818 [['Constant', 'int', '1']]),
819 ([['Constant', 'int', '1'], ['ID', 'a'], ['Constant', 'int', '0']],
820 ['Constant', 'int', '2'])])
821
822 d3 = 'int a = { .a = 1, .c = 3, 4, .b = 5};'
823 self.assertEqual(self.get_decl_init(d3),
824 [
825 ([['ID', 'a']], ['Constant', 'int', '1']),
826 ([['ID', 'c']], ['Constant', 'int', '3']),
827 ['Constant', 'int', '4'],
828 ([['ID', 'b']], ['Constant', 'int', '5'])])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300829
830 def test_function_definitions(self):
831 def parse_fdef(str):
832 return self.parse(str).ext[0]
833
834 def fdef_decl(fdef):
835 return expand_decl(fdef.decl)
836
837 f1 = parse_fdef('''
838 int factorial(int p)
839 {
840 return 3;
841 }
842 ''')
843
844 self.assertEqual(fdef_decl(f1),
845 ['Decl', 'factorial',
846 ['FuncDecl',
847 [['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]]],
848 ['TypeDecl', ['IdentifierType', ['int']]]]])
849
eli.benderskyef29ff92010-10-29 16:25:43 +0200850 self.assertEqual(type(f1.body.block_items[0]), Return)
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300851
852 f2 = parse_fdef('''
853 char* zzz(int p, char* c)
854 {
855 int a;
856 char b;
857
858 a = b + 2;
859 return 3;
860 }
861 ''')
862
863 self.assertEqual(fdef_decl(f2),
864 ['Decl', 'zzz',
865 ['FuncDecl',
866 [ ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]],
867 ['Decl', 'c', ['PtrDecl',
868 ['TypeDecl', ['IdentifierType', ['char']]]]]],
869 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
870
eli.benderskyef29ff92010-10-29 16:25:43 +0200871 self.assertEqual(list(map(type, f2.body.block_items)),
872 [Decl, Decl, Assignment, Return])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300873
874 f3 = parse_fdef('''
875 char* zzz(p, c)
876 long p, *c;
877 {
878 int a;
879 char b;
880
881 a = b + 2;
882 return 3;
883 }
884 ''')
885
886 self.assertEqual(fdef_decl(f3),
887 ['Decl', 'zzz',
888 ['FuncDecl',
889 [ ['ID', 'p'],
890 ['ID', 'c']],
891 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
892
eli.benderskyef29ff92010-10-29 16:25:43 +0200893 self.assertEqual(list(map(type, f3.body.block_items)),
894 [Decl, Decl, Assignment, Return])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300895
896 self.assertEqual(expand_decl(f3.param_decls[0]),
897 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['long']]]])
898 self.assertEqual(expand_decl(f3.param_decls[1]),
899 ['Decl', 'c', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['long']]]]])
900
eli.bendersky71540662010-07-03 12:58:52 +0200901 def test_unified_string_literals(self):
902 # simple string, for reference
903 d1 = self.get_decl_init('char* s = "hello";')
904 self.assertEqual(d1, ['Constant', 'string', '"hello"'])
905
906 d2 = self.get_decl_init('char* s = "hello" " world";')
907 self.assertEqual(d2, ['Constant', 'string', '"hello world"'])
908
909 # the test case from issue 6
910 d3 = self.parse(r'''
911 int main() {
912 fprintf(stderr,
913 "Wrong Params?\n"
914 "Usage:\n"
915 "%s <binary_file_path>\n",
916 argv[0]
917 );
918 }
919 ''')
920
921 self.assertEqual(
eli.benderskyef29ff92010-10-29 16:25:43 +0200922 d3.ext[0].body.block_items[0].args.exprs[1].value,
eli.bendersky71540662010-07-03 12:58:52 +0200923 r'"Wrong Params?\nUsage:\n%s <binary_file_path>\n"')
eli.bendersky4a89f112010-07-05 06:02:03 +0200924
925 d4 = self.get_decl_init('char* s = "" "foobar";')
926 self.assertEqual(d4, ['Constant', 'string', '"foobar"'])
927
928 d5 = self.get_decl_init(r'char* s = "foo\"" "bar";')
929 self.assertEqual(d5, ['Constant', 'string', r'"foo\"bar"'])
eli.bendersky71540662010-07-03 12:58:52 +0200930
eli.bendersky79d5cf62010-10-29 13:33:52 +0200931 def test_inline_specifier(self):
932 ps2 = self.parse('static inline void inlinefoo(void);')
933 self.assertEqual(ps2.ext[0].funcspec, ['inline'])
eli.bendersky2e907fa2010-10-29 15:51:07 +0200934
935 # variable length array
936 def test_vla(self):
937 ps2 = self.parse(r'''
938 int main() {
939 int size;
940 int var[size = 5];
941
942 int var2[*];
943 }
944 ''')
eli.benderskyef29ff92010-10-29 16:25:43 +0200945 self.failUnless(isinstance(ps2.ext[0].body.block_items[1].type.dim, Assignment))
946 self.failUnless(isinstance(ps2.ext[0].body.block_items[2].type.dim, ID))
eli.bendersky79d5cf62010-10-29 13:33:52 +0200947
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300948
949class TestCParser_whole_code(unittest.TestCase):
950 """ Testing of parsing whole chunks of code.
951
952 Since I don't want to rely on the structure of ASTs too
953 much, most of these tests are implemented with visitors.
954 """
955 def parse(self, txt, filename=''):
956 return self.cparser.parse(txt, filename)
957
958 def setUp(self):
959 self.cparser = _c_parser
960
961 # A simple helper visitor that lists the values of all the
962 # Constant nodes it sees.
963 #
964 class ConstantVisitor(NodeVisitor):
965 def __init__(self):
966 self.values = []
967
968 def visit_Constant(self, node):
969 self.values.append(node.value)
970
971 # This visitor counts the amount of references to the ID
972 # with the name provided to it in the constructor.
973 #
974 class IDNameCounter(NodeVisitor):
975 def __init__(self, name):
976 self.name = name
977 self.nrefs = 0
978
979 def visit_ID(self, node):
980 if node.name == self.name:
981 self.nrefs += 1
982
983 # Counts the amount of nodes of a given class
984 #
985 class NodeKlassCounter(NodeVisitor):
986 def __init__(self, node_klass):
987 self.klass = node_klass
988 self.n = 0
989
990 def generic_visit(self, node):
991 if node.__class__ == self.klass:
992 self.n += 1
993
994 NodeVisitor.generic_visit(self, node)
995
996 def assert_all_Constants(self, code, constants):
997 """ Asserts that the list of all Constant values (by
998 'preorder' appearance) in the chunk of code is as
999 given.
1000 """
eli.benderskyed890492010-06-25 08:25:55 +03001001 if isinstance(code, str):
1002 parsed = self.parse(code)
1003 else:
1004 parsed = code
1005
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001006 cv = self.ConstantVisitor()
1007 cv.visit(parsed)
1008 self.assertEqual(cv.values, constants)
1009
1010 def assert_num_ID_refs(self, code, name, num):
1011 """ Asserts the number of references to the ID with
1012 the given name.
1013 """
1014 if isinstance(code, str):
1015 parsed = self.parse(code)
1016 else:
1017 parsed = code
1018
1019 iv = self.IDNameCounter(name)
1020 iv.visit(parsed)
1021 self.assertEqual(iv.nrefs, num)
1022
1023 def assert_num_klass_nodes(self, code, klass, num):
1024 """ Asserts the amount of klass nodes in the code.
1025 """
1026 if isinstance(code, str):
1027 parsed = self.parse(code)
1028 else:
1029 parsed = code
1030
1031 cv = self.NodeKlassCounter(klass)
1032 cv.visit(parsed)
1033 self.assertEqual(cv.n, num)
1034
1035 def test_expressions(self):
1036 e1 = '''int k = (r + 10.0) >> 6 + 8 << (3 & 0x14);'''
1037 self.assert_all_Constants(e1, ['10.0', '6', '8', '3', '0x14'])
1038
1039 e2 = r'''char n = '\n', *prefix = "st_";'''
1040 self.assert_all_Constants(e2, [r"'\n'", '"st_"'])
1041
1042 def test_statements(self):
1043 s1 = r'''
1044 void foo(){
1045 if (sp == 1)
1046 if (optind >= argc ||
1047 argv[optind][0] != '-' || argv[optind][1] == '\0')
1048 return -1;
1049 else if (strcmp(argv[optind], "--") == 0) {
1050 optind++;
1051 return -1;
1052 }
1053 }
1054 '''
1055
1056 self.assert_all_Constants(s1,
1057 ['1', '0', r"'-'", '1', r"'\0'", '1', r'"--"', '0', '1'])
1058
1059 ps1 = self.parse(s1)
1060 self.assert_num_ID_refs(ps1, 'argv', 3)
1061 self.assert_num_ID_refs(ps1, 'optind', 5)
1062
1063 self.assert_num_klass_nodes(ps1, If, 3)
1064 self.assert_num_klass_nodes(ps1, Return, 2)
1065 self.assert_num_klass_nodes(ps1, FuncCall, 1) # strcmp
1066 self.assert_num_klass_nodes(ps1, BinaryOp, 7)
1067
1068 # In the following code, Hash and Node were defined as
1069 # int to pacify the parser that sees they're used as
1070 # types
1071 #
1072 s2 = r'''
1073 typedef int Hash, Node;
1074
1075 void HashDestroy(Hash* hash)
1076 {
1077 unsigned int i;
1078
1079 if (hash == NULL)
1080 return;
1081
1082 for (i = 0; i < hash->table_size; ++i)
1083 {
1084 Node* temp = hash->heads[i];
1085
1086 while (temp != NULL)
1087 {
1088 Node* temp2 = temp;
1089
1090 free(temp->entry->key);
1091 free(temp->entry->value);
1092 free(temp->entry);
1093
1094 temp = temp->next;
1095
1096 free(temp2);
1097 }
1098 }
1099
1100 free(hash->heads);
1101 hash->heads = NULL;
1102
1103 free(hash);
1104 }
1105 '''
1106
1107 ps2 = self.parse(s2)
1108 self.assert_num_klass_nodes(ps2, FuncCall, 6)
1109 self.assert_num_klass_nodes(ps2, FuncDef, 1)
1110 self.assert_num_klass_nodes(ps2, For, 1)
1111 self.assert_num_klass_nodes(ps2, While, 1)
1112 self.assert_num_klass_nodes(ps2, StructRef, 10)
1113
1114 # declarations don't count
1115 self.assert_num_ID_refs(ps2, 'hash', 6)
1116 self.assert_num_ID_refs(ps2, 'i', 4)
eli.benderskyed890492010-06-25 08:25:55 +03001117
1118 s3 = r'''
1119 void x(void) {
1120 int a, b;
1121 if (a < b)
1122 do {
1123 a = 0;
1124 } while (0);
1125 else if (a == b) {
1126 a = 1;
1127 }
1128 }
1129 '''
1130
1131 ps3 = self.parse(s3)
1132 self.assert_num_klass_nodes(ps3, DoWhile, 1)
1133 self.assert_num_ID_refs(ps3, 'a', 4)
1134 self.assert_all_Constants(ps3, ['0', '0', '1'])
eli.bendersky145890d2010-10-29 12:02:32 +02001135
1136 def test_for_statement(self):
1137 s2 = r'''
1138 void x(void)
1139 {
1140 int i;
1141 for (i = 0; i < 5; ++i) {
1142 x = 50;
1143 }
1144 }
1145 '''
1146 ps2 = self.parse(s2)
1147 self.assert_num_klass_nodes(ps2, For, 1)
1148 # here there are 3 refs to 'i' since the declaration doesn't count as
1149 # a ref in the visitor
1150 #
1151 self.assert_num_ID_refs(ps2, 'i', 3)
eli.benderskyed890492010-06-25 08:25:55 +03001152
eli.bendersky145890d2010-10-29 12:02:32 +02001153 s3 = r'''
1154 void x(void)
1155 {
1156 for (int i = 0; i < 5; ++i) {
1157 x = 50;
1158 }
1159 }
1160 '''
1161 ps3 = self.parse(s3)
eli.bendersky145890d2010-10-29 12:02:32 +02001162 self.assert_num_klass_nodes(ps3, For, 1)
1163 # here there are 2 refs to 'i' since the declaration doesn't count as
1164 # a ref in the visitor
1165 #
1166 self.assert_num_ID_refs(ps3, 'i', 2)
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001167
1168 def test_whole_file(self):
1169 # See how pycparser handles a whole, real C file.
1170 #
1171 filename = 'c_files/memmgr_with_h.c'
1172 code = open(filename, 'rU').read()
1173 p = self.parse(code)
1174
1175 self.assert_num_klass_nodes(p, FuncDef, 5)
1176
1177 # each FuncDef also has a FuncDecl. 4 declarations
1178 # + 5 definitions, overall 9
1179 self.assert_num_klass_nodes(p, FuncDecl, 9)
1180
1181 self.assert_num_klass_nodes(p, Typedef, 4)
1182
1183 self.assertEqual(p.ext[4].coord.line, 88)
1184 self.assertEqual(p.ext[4].coord.file, "./memmgr.h")
1185
1186 self.assertEqual(p.ext[6].coord.line, 10)
1187 self.assertEqual(p.ext[6].coord.file, "memmgr.c")
1188
1189 def test_whole_file_with_stdio(self):
1190 # Parse a whole file with stdio.h included by cpp
1191 #
1192 filename = 'c_files/cppd_with_stdio_h.c'
1193 code = open(filename, 'rU').read()
1194 p = self.parse(code)
1195
1196 self.failUnless(isinstance(p.ext[0], Typedef))
1197 self.assertEqual(p.ext[0].coord.line, 213)
1198 self.assertEqual(p.ext[0].coord.file, "D:\eli\cpp_stuff\libc_include/stddef.h")
1199
1200 self.failUnless(isinstance(p.ext[-1], FuncDef))
1201 self.assertEqual(p.ext[-1].coord.line, 15)
1202 self.assertEqual(p.ext[-1].coord.file, "example_c_file.c")
1203
1204 self.failUnless(isinstance(p.ext[-8], Typedef))
1205 self.failUnless(isinstance(p.ext[-8].type, TypeDecl))
1206 self.assertEqual(p.ext[-8].name, 'cookie_io_functions_t')
1207
1208
1209if __name__ == '__main__':
1210 #~ suite = unittest.TestLoader().loadTestsFromNames(
1211 #~ ['test_c_parser.TestCParser_fundamentals.test_typedef'])
1212
1213 #~ suite = unittest.TestLoader().loadTestsFromNames(
1214 #~ ['test_c_parser.TestCParser_whole_code.test_whole_file_with_stdio'])
1215
1216 #~ suite = unittest.TestLoader().loadTestsFromTestCase(
1217 #~ TestCParser_whole_code)
1218
1219 #~ unittest.TextTestRunner(verbosity=2).run(suite)
1220 unittest.main()