blob: dbf7533f71489481e9a50fa72e57ba3a5e39089b [file] [log] [blame]
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001#!/usr/bin/env python
2
3import pprint
4import re
Eli Benderskyd0973782012-01-19 08:09:33 +02005import os, sys
Eli Bendersky3921e8e2010-05-21 09:05:39 +03006import 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
Eli Bendersky3921e8e2010-05-21 09:05:39 +030014_c_parser = c_parser.CParser(
15 lex_optimize=False,
16 yacc_debug=True,
17 yacc_optimize=False,
18 yacctab='yacctab')
19
20
21def expand_decl(decl):
22 """ Converts the declaration into a nested list.
23 """
24 typ = type(decl)
25
26 if typ == TypeDecl:
27 return ['TypeDecl', expand_decl(decl.type)]
28 elif typ == IdentifierType:
29 return ['IdentifierType', decl.names]
30 elif typ == ID:
31 return ['ID', decl.name]
32 elif typ in [Struct, Union]:
33 decls = [expand_decl(d) for d in decl.decls or []]
34 return [typ.__name__, decl.name, decls]
35 else:
36 nested = expand_decl(decl.type)
37
38 if typ == Decl:
39 if decl.quals:
40 return ['Decl', decl.quals, decl.name, nested]
41 else:
42 return ['Decl', decl.name, nested]
43 elif typ == Typename: # for function parameters
44 if decl.quals:
45 return ['Typename', decl.quals, nested]
46 else:
47 return ['Typename', nested]
48 elif typ == ArrayDecl:
49 dimval = decl.dim.value if decl.dim else ''
50 return ['ArrayDecl', dimval, nested]
51 elif typ == PtrDecl:
52 return ['PtrDecl', nested]
53 elif typ == Typedef:
54 return ['Typedef', decl.name, nested]
55 elif typ == FuncDecl:
56 if decl.args:
57 params = [expand_decl(param) for param in decl.args.params]
58 else:
59 params = []
60 return ['FuncDecl', params, nested]
61
62
63def expand_init(init):
64 """ Converts an initialization into a nested list
65 """
66 typ = type(init)
67
eli.benderskyf890a862010-10-30 12:13:23 +020068 if typ == NamedInitializer:
69 des = [expand_init(dp) for dp in init.name]
70 return (des, expand_init(init.expr))
71 elif typ == ExprList:
72 return [expand_init(expr) for expr in init.exprs]
73 elif typ == Constant:
Eli Bendersky3921e8e2010-05-21 09:05:39 +030074 return ['Constant', init.type, init.value]
75 elif typ == ID:
76 return ['ID', init.name]
Eli Bendersky3921e8e2010-05-21 09:05:39 +030077
78
eli.bendersky85d2e732011-05-20 19:47:26 +030079class TestCParser_base(unittest.TestCase):
Eli Bendersky3921e8e2010-05-21 09:05:39 +030080 def parse(self, txt, filename=''):
81 return self.cparser.parse(txt, filename)
82
83 def setUp(self):
84 self.cparser = _c_parser
85
eli.bendersky85d2e732011-05-20 19:47:26 +030086
87class TestCParser_fundamentals(TestCParser_base):
Eli Bendersky3921e8e2010-05-21 09:05:39 +030088 def get_decl(self, txt, index=0):
89 """ Given a source and an index returns the expanded
90 declaration at that index.
91
92 FileAST holds a list of 'external declarations'.
93 index is the offset of the desired declaration in that
94 list.
95 """
96 t = self.parse(txt).ext[index]
97 return expand_decl(t)
98
99 def get_decl_init(self, txt, index=0):
100 """ Returns the expanded initializer of the declaration
101 at index.
102 """
103 t = self.parse(txt).ext[index]
104 return expand_init(t.init)
105
106 def test_FileAST(self):
107 t = self.parse('int a; char c;')
108 self.failUnless(isinstance(t, FileAST))
109 self.assertEqual(len(t.ext), 2)
eli.bendersky43cf0b22011-10-19 05:56:15 +0200110
111 # empty file
112 t2 = self.parse('')
113 self.failUnless(isinstance(t2, FileAST))
114 self.assertEqual(len(t2.ext), 0)
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300115
eli.bendersky38165b72011-02-04 08:13:39 +0200116 def test_empty_toplevel_decl(self):
117 code = 'int foo;;'
118 t = self.parse(code)
119 self.failUnless(isinstance(t, FileAST))
120 self.assertEqual(len(t.ext), 1)
121 self.assertEqual(self.get_decl(code),
122 ['Decl', 'foo',
123 ['TypeDecl', ['IdentifierType', ['int']]]])
124
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300125 def assert_coord(self, node, line, file=None):
126 self.assertEqual(node.coord.line, line)
127 if file:
128 self.assertEqual(node.coord.file, file)
129
130 def test_coords(self):
eli.bendersky38165b72011-02-04 08:13:39 +0200131 """ Tests the "coordinates" of parsed elements - file
132 name and line numbers, with modification insterted by
133 #line directives.
134 """
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300135 self.assert_coord(self.parse('int a;').ext[0], 1)
136
137 t1 = """
138 int a;
139 int b;\n\n
140 int c;
141 """
142 f1 = self.parse(t1, filename='test.c')
143 self.assert_coord(f1.ext[0], 2, 'test.c')
144 self.assert_coord(f1.ext[1], 3, 'test.c')
145 self.assert_coord(f1.ext[2], 6, 'test.c')
146
147 t1_1 = '''
148 int main() {
149 k = p;
150 printf("%d", b);
151 return 0;
152 }'''
153 f1_1 = self.parse(t1_1, filename='test.c')
eli.benderskyef29ff92010-10-29 16:25:43 +0200154 self.assert_coord(f1_1.ext[0].body.block_items[0], 3, 'test.c')
155 self.assert_coord(f1_1.ext[0].body.block_items[1], 4, 'test.c')
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200156
157 t1_2 = '''
158 int main () {
159 int p = (int) k;
160 }'''
161 f1_2 = self.parse(t1_2, filename='test.c')
162 # make sure that the Cast has a coord (issue 23)
163 self.assert_coord(f1_2.ext[0].body.block_items[0].init, 3, 'test.c')
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300164
165 t2 = """
166 #line 99
167 int c;
168 """
169 self.assert_coord(self.parse(t2).ext[0], 99)
170
171 t3 = """
172 int dsf;
173 char p;
174 #line 3000 "in.h"
175 char d;
176 """
177 f3 = self.parse(t3, filename='test.c')
178 self.assert_coord(f3.ext[0], 2, 'test.c')
179 self.assert_coord(f3.ext[1], 3, 'test.c')
180 self.assert_coord(f3.ext[2], 3000, 'in.h')
181
182 t4 = """
183 #line 20 "restore.h"
184 int maydler(char);
185
186 #line 30 "includes/daween.ph"
187 long j, k;
188
189 #line 50000
190 char* ro;
191 """
192 f4 = self.parse(t4, filename='myb.c')
193 self.assert_coord(f4.ext[0], 20, 'restore.h')
194 self.assert_coord(f4.ext[1], 30, 'includes/daween.ph')
195 self.assert_coord(f4.ext[2], 30, 'includes/daween.ph')
196 self.assert_coord(f4.ext[3], 50000, 'includes/daween.ph')
197
198 t5 = """
199 int
200 #line 99
201 c;
202 """
203 self.assert_coord(self.parse(t5).ext[0], 99)
204
205 def test_simple_decls(self):
206 self.assertEqual(self.get_decl('int a;'),
207 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
208
209 self.assertEqual(self.get_decl('unsigned int a;'),
Eli Bendersky68497c22012-01-19 06:04:58 +0200210 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['unsigned', 'int']]]])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300211
eli.benderskyaffe0322011-09-24 06:16:55 +0300212 self.assertEqual(self.get_decl('_Bool a;'),
213 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['_Bool']]]])
214
Eli Benderskyf4d73462012-01-19 05:56:27 +0200215 self.assertEqual(self.get_decl('float _Complex fcc;'),
Eli Bendersky68497c22012-01-19 06:04:58 +0200216 ['Decl', 'fcc', ['TypeDecl', ['IdentifierType', ['float', '_Complex']]]])
Eli Benderskyf4d73462012-01-19 05:56:27 +0200217
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300218 self.assertEqual(self.get_decl('char* string;'),
219 ['Decl', 'string',
220 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]])
221
222 self.assertEqual(self.get_decl('long ar[15];'),
223 ['Decl', 'ar',
224 ['ArrayDecl', '15',
225 ['TypeDecl', ['IdentifierType', ['long']]]]])
eli.bendersky98f45372010-10-30 09:46:29 +0200226
227 self.assertEqual(self.get_decl('long long ar[15];'),
228 ['Decl', 'ar',
229 ['ArrayDecl', '15',
eli.benderskyf890a862010-10-30 12:13:23 +0200230 ['TypeDecl', ['IdentifierType', ['long', 'long']]]]])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300231
232 self.assertEqual(self.get_decl('unsigned ar[];'),
233 ['Decl', 'ar',
234 ['ArrayDecl', '',
235 ['TypeDecl', ['IdentifierType', ['unsigned']]]]])
236
237 self.assertEqual(self.get_decl('int strlen(char* s);'),
238 ['Decl', 'strlen',
239 ['FuncDecl',
240 [['Decl', 's',
241 ['PtrDecl',
242 ['TypeDecl', ['IdentifierType', ['char']]]]]],
243 ['TypeDecl', ['IdentifierType', ['int']]]]])
244
245 self.assertEqual(self.get_decl('int strcmp(char* s1, char* s2);'),
246 ['Decl', 'strcmp',
247 ['FuncDecl',
248 [ ['Decl', 's1',
249 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
250 ['Decl', 's2',
251 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]
252 ],
253 ['TypeDecl', ['IdentifierType', ['int']]]]])
254
255 def test_nested_decls(self): # the fun begins
256 self.assertEqual(self.get_decl('char** ar2D;'),
257 ['Decl', 'ar2D',
258 ['PtrDecl', ['PtrDecl',
259 ['TypeDecl', ['IdentifierType', ['char']]]]]])
260
261 self.assertEqual(self.get_decl('int (*a)[1][2];'),
262 ['Decl', 'a',
263 ['PtrDecl',
264 ['ArrayDecl', '1',
265 ['ArrayDecl', '2',
266 ['TypeDecl', ['IdentifierType', ['int']]]]]]])
267
268 self.assertEqual(self.get_decl('int *a[1][2];'),
269 ['Decl', 'a',
270 ['ArrayDecl', '1',
271 ['ArrayDecl', '2',
272 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['int']]]]]]])
273
274 self.assertEqual(self.get_decl('char ***ar3D[40];'),
275 ['Decl', 'ar3D',
276 ['ArrayDecl', '40',
277 ['PtrDecl', ['PtrDecl', ['PtrDecl',
278 ['TypeDecl', ['IdentifierType', ['char']]]]]]]])
279
280 self.assertEqual(self.get_decl('char (***ar3D)[40];'),
281 ['Decl', 'ar3D',
282 ['PtrDecl', ['PtrDecl', ['PtrDecl',
283 ['ArrayDecl', '40', ['TypeDecl', ['IdentifierType', ['char']]]]]]]])
284
285 self.assertEqual(self.get_decl('int (*x[4])(char, int);'),
286 ['Decl', 'x',
287 ['ArrayDecl', '4',
288 ['PtrDecl',
289 ['FuncDecl',
290 [ ['Typename', ['TypeDecl', ['IdentifierType', ['char']]]],
291 ['Typename', ['TypeDecl', ['IdentifierType', ['int']]]]],
292 ['TypeDecl', ['IdentifierType', ['int']]]]]]])
293
294 self.assertEqual(self.get_decl('char *(*(**foo [][8])())[];'),
295 ['Decl', 'foo',
296 ['ArrayDecl', '',
297 ['ArrayDecl', '8',
298 ['PtrDecl', ['PtrDecl',
299 ['FuncDecl',
300 [],
301 ['PtrDecl',
302 ['ArrayDecl', '',
303 ['PtrDecl',
304 ['TypeDecl',
305 ['IdentifierType', ['char']]]]]]]]]]]])
306
307 # explore named and unnamed function pointer parameters,
308 # with and without qualifiers
309 #
310
311 # unnamed w/o quals
312 self.assertEqual(self.get_decl('int (*k)(int);'),
313 ['Decl', 'k',
314 ['PtrDecl',
315 ['FuncDecl',
316 [['Typename', ['TypeDecl', ['IdentifierType', ['int']]]]],
317 ['TypeDecl', ['IdentifierType', ['int']]]]]])
318
319 # unnamed w/ quals
320 self.assertEqual(self.get_decl('int (*k)(const int);'),
321 ['Decl', 'k',
322 ['PtrDecl',
323 ['FuncDecl',
324 [['Typename', ['const'], ['TypeDecl', ['IdentifierType', ['int']]]]],
325 ['TypeDecl', ['IdentifierType', ['int']]]]]])
326
327 # named w/o quals
328 self.assertEqual(self.get_decl('int (*k)(int q);'),
329 ['Decl', 'k',
330 ['PtrDecl',
331 ['FuncDecl',
332 [['Decl', 'q', ['TypeDecl', ['IdentifierType', ['int']]]]],
333 ['TypeDecl', ['IdentifierType', ['int']]]]]])
334
335 # named w/ quals
336 self.assertEqual(self.get_decl('int (*k)(const volatile int q);'),
337 ['Decl', 'k',
338 ['PtrDecl',
339 ['FuncDecl',
Eli Bendersky68497c22012-01-19 06:04:58 +0200340 [['Decl', ['const', 'volatile'], 'q',
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300341 ['TypeDecl', ['IdentifierType', ['int']]]]],
342 ['TypeDecl', ['IdentifierType', ['int']]]]]])
343
eli.bendersky79d5cf62010-10-29 13:33:52 +0200344 # restrict qualifier
345 self.assertEqual(self.get_decl('int (*k)(restrict int* q);'),
346 ['Decl', 'k',
347 ['PtrDecl',
348 ['FuncDecl',
349 [['Decl', ['restrict'], 'q',
350 ['PtrDecl',
351 ['TypeDecl', ['IdentifierType', ['int']]]]]],
352 ['TypeDecl', ['IdentifierType', ['int']]]]]])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300353
354 def test_qualifiers_storage_specifiers(self):
355 def assert_qs(txt, index, quals, storage):
356 d = self.parse(txt).ext[index]
357 self.assertEqual(d.quals, quals)
358 self.assertEqual(d.storage, storage)
359
360 assert_qs("extern int p;", 0, [], ['extern'])
361 assert_qs("const long p = 6;", 0, ['const'], [])
362
363 d1 = "static const int p, q, r;"
364 for i in range(3):
365 assert_qs(d1, i, ['const'], ['static'])
366
367 d2 = "static char * const p;"
368 assert_qs(d2, 0, [], ['static'])
369 pdecl = self.parse(d2).ext[0].type
370 self.failUnless(isinstance(pdecl, PtrDecl))
371 self.assertEqual(pdecl.quals, ['const'])
372
373 def test_sizeof(self):
374 e = """
375 void foo()
376 {
377 int a = sizeof k;
378 int b = sizeof(int);
eli.benderskyc51e1d32011-02-04 08:52:33 +0200379 int c = sizeof(int**);;
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300380
381 char* p = "just to make sure this parses w/o error...";
382 int d = sizeof(int());
383 }
384 """
385 compound = self.parse(e).ext[0].body
386
eli.benderskyef29ff92010-10-29 16:25:43 +0200387 s1 = compound.block_items[0].init
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300388 self.assertTrue(isinstance(s1, UnaryOp))
389 self.assertEqual(s1.op, 'sizeof')
390 self.assertTrue(isinstance(s1.expr, ID))
391 self.assertEqual(s1.expr.name, 'k')
392
eli.benderskyef29ff92010-10-29 16:25:43 +0200393 s2 = compound.block_items[1].init
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300394 self.assertEqual(expand_decl(s2.expr),
395 ['Typename', ['TypeDecl', ['IdentifierType', ['int']]]])
396
eli.benderskyef29ff92010-10-29 16:25:43 +0200397 s3 = compound.block_items[2].init
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300398 self.assertEqual(expand_decl(s3.expr),
399 ['Typename',
400 ['PtrDecl',
401 ['PtrDecl',
402 ['TypeDecl',
403 ['IdentifierType', ['int']]]]]])
404
eli.bendersky9f481562010-10-30 15:50:47 +0200405 # The C99 compound literal feature
406 #
eli.benderskyf890a862010-10-30 12:13:23 +0200407 def test_compound_literals(self):
eli.bendersky9f481562010-10-30 15:50:47 +0200408 ps1 = self.parse(r'''
eli.benderskyf890a862010-10-30 12:13:23 +0200409 void foo() {
eli.bendersky9f481562010-10-30 15:50:47 +0200410 p = (long long){k};
411 tc = (struct jk){.a = {1, 2}, .b[0] = t};
412 }''')
eli.benderskyf890a862010-10-30 12:13:23 +0200413
eli.bendersky9f481562010-10-30 15:50:47 +0200414 compound = ps1.ext[0].body.block_items[0].rvalue
415 self.assertEqual(expand_decl(compound.type),
416 ['Typename', ['TypeDecl', ['IdentifierType', ['long', 'long']]]])
417 self.assertEqual(expand_init(compound.init),
418 [['ID', 'k']])
419
420 compound = ps1.ext[0].body.block_items[1].rvalue
421 self.assertEqual(expand_decl(compound.type),
422 ['Typename', ['TypeDecl', ['Struct', 'jk', []]]])
423 self.assertEqual(expand_init(compound.init),
424 [
425 ([['ID', 'a']], [['Constant', 'int', '1'], ['Constant', 'int', '2']]),
426 ([['ID', 'b'], ['Constant', 'int', '0']], ['ID', 't'])])
eli.benderskyf890a862010-10-30 12:13:23 +0200427
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300428 def test_enums(self):
429 e1 = "enum mycolor op;"
430 e1_type = self.parse(e1).ext[0].type.type
431
432 self.assertTrue(isinstance(e1_type, Enum))
433 self.assertEqual(e1_type.name, 'mycolor')
434 self.assertEqual(e1_type.values, None)
435
436 e2 = "enum mysize {large=20, small, medium} shoes;"
437 e2_type = self.parse(e2).ext[0].type.type
438
439 self.assertTrue(isinstance(e2_type, Enum))
440 self.assertEqual(e2_type.name, 'mysize')
441
442 e2_elist = e2_type.values
443 self.assertTrue(isinstance(e2_elist, EnumeratorList))
444
445 for e2_eval in e2_elist.enumerators:
446 self.assertTrue(isinstance(e2_eval, Enumerator))
447
448 self.assertEqual(e2_elist.enumerators[0].name, 'large')
449 self.assertEqual(e2_elist.enumerators[0].value.value, '20')
450 self.assertEqual(e2_elist.enumerators[2].name, 'medium')
451 self.assertEqual(e2_elist.enumerators[2].value, None)
452
453 # enum with trailing comma (C99 feature)
454 e3 = """
455 enum
456 {
457 red,
458 blue,
459 green,
460 } color;
461 """
462
463 e3_type = self.parse(e3).ext[0].type.type
464 self.assertTrue(isinstance(e3_type, Enum))
465 e3_elist = e3_type.values
466 self.assertTrue(isinstance(e3_elist, EnumeratorList))
467
468 for e3_eval in e3_elist.enumerators:
469 self.assertTrue(isinstance(e3_eval, Enumerator))
470
471 self.assertEqual(e3_elist.enumerators[0].name, 'red')
472 self.assertEqual(e3_elist.enumerators[0].value, None)
473 self.assertEqual(e3_elist.enumerators[1].name, 'blue')
474 self.assertEqual(e3_elist.enumerators[2].name, 'green')
475
476 def test_typedef(self):
477 # without typedef, error
478 s1 = """
479 node k;
480 """
481 self.assertRaises(ParseError, self.parse, s1)
482
483 # now with typedef, works
484 s2 = """
485 typedef void* node;
486 node k;
487 """
488 ps2 = self.parse(s2)
489 self.assertEqual(expand_decl(ps2.ext[0]),
490 ['Typedef', 'node',
491 ['PtrDecl',
492 ['TypeDecl', ['IdentifierType', ['void']]]]])
493
494 self.assertEqual(expand_decl(ps2.ext[1]),
495 ['Decl', 'k',
496 ['TypeDecl', ['IdentifierType', ['node']]]])
497
498 s3 = """
499 typedef int T;
500 typedef T *pT;
501
502 pT aa, bb;
503 """
504 ps3 = self.parse(s3)
505 self.assertEqual(expand_decl(ps3.ext[3]),
506 ['Decl', 'bb',
507 ['TypeDecl', ['IdentifierType', ['pT']]]])
508
509 s4 = '''
510 typedef char* __builtin_va_list;
511 typedef __builtin_va_list __gnuc_va_list;
512 '''
513 ps4 = self.parse(s4)
514 self.assertEqual(expand_decl(ps4.ext[1]),
515 ['Typedef', '__gnuc_va_list',
516 ['TypeDecl',
517 ['IdentifierType', ['__builtin_va_list']]]])
518
519 s5 = '''typedef struct tagHash Hash;'''
520 ps5 = self.parse(s5)
521 self.assertEqual(expand_decl(ps5.ext[0]),
522 ['Typedef', 'Hash', ['TypeDecl', ['Struct', 'tagHash', []]]])
523
524 def test_struct_union(self):
525 s1 = """
526 struct {
527 int id;
528 char* name;
529 } joe;
530 """
531
532 self.assertEqual(expand_decl(self.parse(s1).ext[0]),
533 ['Decl', 'joe',
534 ['TypeDecl', ['Struct', None,
535 [ ['Decl', 'id',
536 ['TypeDecl',
537 ['IdentifierType', ['int']]]],
538 ['Decl', 'name',
539 ['PtrDecl',
540 ['TypeDecl',
541 ['IdentifierType', ['char']]]]]]]]])
542
543 s2 = """
544 struct node p;
545 """
546 self.assertEqual(expand_decl(self.parse(s2).ext[0]),
547 ['Decl', 'p',
548 ['TypeDecl', ['Struct', 'node', []]]])
549
550 s21 = """
551 union pri ra;
552 """
553 self.assertEqual(expand_decl(self.parse(s21).ext[0]),
554 ['Decl', 'ra',
555 ['TypeDecl', ['Union', 'pri', []]]])
556
557 s3 = """
558 struct node* p;
559 """
560 self.assertEqual(expand_decl(self.parse(s3).ext[0]),
561 ['Decl', 'p',
562 ['PtrDecl',
563 ['TypeDecl', ['Struct', 'node', []]]]])
564
565 s4 = """
566 struct node;
567 """
568 self.assertEqual(expand_decl(self.parse(s4).ext[0]),
569 ['Decl', None,
570 ['Struct', 'node', []]])
571
572 s5 = """
573 union
574 {
575 struct
576 {
577 int type;
578 } n;
579
580 struct
581 {
582 int type;
583 int intnode;
584 } ni;
585 } u;
586 """
587 self.assertEqual(expand_decl(self.parse(s5).ext[0]),
588 ['Decl', 'u',
589 ['TypeDecl',
590 ['Union', None,
591 [['Decl', 'n',
592 ['TypeDecl',
593 ['Struct', None,
594 [['Decl', 'type',
595 ['TypeDecl', ['IdentifierType', ['int']]]]]]]],
596 ['Decl', 'ni',
597 ['TypeDecl',
598 ['Struct', None,
599 [['Decl', 'type',
600 ['TypeDecl', ['IdentifierType', ['int']]]],
601 ['Decl', 'intnode',
602 ['TypeDecl', ['IdentifierType', ['int']]]]]]]]]]]])
603
604 s6 = """
605 typedef struct foo_tag
606 {
607 void* data;
608 } foo, *pfoo;
609 """
610 s6_ast = self.parse(s6)
611
612 self.assertEqual(expand_decl(s6_ast.ext[0]),
613 ['Typedef', 'foo',
614 ['TypeDecl',
615 ['Struct', 'foo_tag',
616 [['Decl', 'data',
617 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]])
618
619 self.assertEqual(expand_decl(s6_ast.ext[1]),
620 ['Typedef', 'pfoo',
621 ['PtrDecl',
622 ['TypeDecl',
623 ['Struct', 'foo_tag',
624 [['Decl', 'data',
625 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]]])
626
627 s7 = r"""
628 struct _on_exit_args {
629 void * _fnargs[32];
630 void * _dso_handle[32];
631
632 long _fntypes;
633 #line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
634
635 long _is_cxa;
636 };
637 """
638
639 s7_ast = self.parse(s7, filename='test.c')
640 self.assert_coord(s7_ast.ext[0].type.decls[2], 6, 'test.c')
641 self.assert_coord(s7_ast.ext[0].type.decls[3], 78,
642 r'D:\eli\cpp_stuff\libc_include/sys/reent.h')
643
644 s8 = """
645 typedef enum tagReturnCode {SUCCESS, FAIL} ReturnCode;
646
647 typedef struct tagEntry
648 {
649 char* key;
650 char* value;
651 } Entry;
652
653
654 typedef struct tagNode
655 {
656 Entry* entry;
657
658 struct tagNode* next;
659 } Node;
660
661 typedef struct tagHash
662 {
663 unsigned int table_size;
664
665 Node** heads;
666
667 } Hash;
668 """
669 s8_ast = self.parse(s8)
670 self.assertEqual(expand_decl(s8_ast.ext[3]),
671 ['Typedef', 'Hash',
672 ['TypeDecl', ['Struct', 'tagHash',
673 [['Decl', 'table_size',
Eli Bendersky68497c22012-01-19 06:04:58 +0200674 ['TypeDecl', ['IdentifierType', ['unsigned', 'int']]]],
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300675 ['Decl', 'heads',
676 ['PtrDecl', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['Node']]]]]]]]]])
677
eli.bendersky697ecc52011-02-10 07:05:13 +0200678 def test_anonymous_struct_union(self):
679 s1 = """
680 union
681 {
682 union
683 {
684 int i;
685 long l;
686 };
687
688 struct
689 {
690 int type;
691 int intnode;
692 };
693 } u;
694 """
695
696 self.assertEqual(expand_decl(self.parse(s1).ext[0]),
697 ['Decl', 'u',
698 ['TypeDecl',
699 ['Union', None,
700 [['Decl', None,
701 ['Union', None,
702 [['Decl', 'i',
703 ['TypeDecl',
704 ['IdentifierType', ['int']]]],
705 ['Decl', 'l',
706 ['TypeDecl',
707 ['IdentifierType', ['long']]]]]]],
708 ['Decl', None,
709 ['Struct', None,
710 [['Decl', 'type',
711 ['TypeDecl',
712 ['IdentifierType', ['int']]]],
713 ['Decl', 'intnode',
714 ['TypeDecl',
715 ['IdentifierType', ['int']]]]]]]]]]])
716
717 s2 = """
718 struct
719 {
720 int i;
721 union
722 {
723 int id;
724 char* name;
725 };
726 float f;
727 } joe;
728 """
729
730 self.assertEqual(expand_decl(self.parse(s2).ext[0]),
731 ['Decl', 'joe',
732 ['TypeDecl',
733 ['Struct', None,
734 [['Decl', 'i',
735 ['TypeDecl',
736 ['IdentifierType', ['int']]]],
737 ['Decl', None,
738 ['Union', None,
739 [['Decl', 'id',
740 ['TypeDecl',
741 ['IdentifierType', ['int']]]],
742 ['Decl', 'name',
743 ['PtrDecl',
744 ['TypeDecl',
745 ['IdentifierType', ['char']]]]]]]],
746 ['Decl', 'f',
747 ['TypeDecl',
748 ['IdentifierType', ['float']]]]]]]])
749
750 # ISO/IEC 9899:201x Commitee Draft 2010-11-16, N1539
751 # section 6.7.2.1, par. 19, example 1
752 s3 = """
753 struct v {
754 union {
755 struct { int i, j; };
756 struct { long k, l; } w;
757 };
758 int m;
759 } v1;
760 """
761
762 self.assertEqual(expand_decl(self.parse(s3).ext[0]),
763 ['Decl', 'v1',
764 ['TypeDecl',
765 ['Struct', 'v',
766 [['Decl', None,
767 ['Union', None,
768 [['Decl', None,
769 ['Struct', None,
770 [['Decl', 'i',
771 ['TypeDecl',
772 ['IdentifierType', ['int']]]],
773 ['Decl', 'j',
774 ['TypeDecl',
775 ['IdentifierType', ['int']]]]]]],
776 ['Decl', 'w',
777 ['TypeDecl',
778 ['Struct', None,
779 [['Decl', 'k',
780 ['TypeDecl',
781 ['IdentifierType', ['long']]]],
782 ['Decl', 'l',
783 ['TypeDecl',
784 ['IdentifierType', ['long']]]]]]]]]]],
785 ['Decl', 'm',
786 ['TypeDecl',
787 ['IdentifierType', ['int']]]]]]]])
788
eli.benderskydce29a02011-02-10 07:55:00 +0200789 s4 = """
790 struct v {
791 int i;
792 float;
793 } v2;"""
eli.bendersky6b011792011-06-22 17:50:56 +0300794 # just make sure this doesn't raise ParseError
795 self.parse(s4)
eli.benderskydce29a02011-02-10 07:55:00 +0200796
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200797 def test_struct_bitfields(self):
eli.bendersky38ed9a92010-10-09 09:29:59 +0200798 # a struct with two bitfields, one unnamed
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200799 s1 = """
800 struct {
801 int k:6;
802 int :2;
803 } joe;
804 """
805
806 parsed_struct = self.parse(s1).ext[0]
807
eli.bendersky38ed9a92010-10-09 09:29:59 +0200808 # We can see here the name of the decl for the unnamed bitfield is
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200809 # None, but expand_decl doesn't show bitfield widths
810 # ...
811 self.assertEqual(expand_decl(parsed_struct),
812 ['Decl', 'joe',
813 ['TypeDecl', ['Struct', None,
814 [ ['Decl', 'k',
815 ['TypeDecl',
816 ['IdentifierType', ['int']]]],
817 ['Decl', None,
818 ['TypeDecl',
819 ['IdentifierType', ['int']]]]]]]])
820
821 # ...
822 # so we test them manually
823 self.assertEqual(parsed_struct.type.type.decls[0].bitsize.value, '6')
824 self.assertEqual(parsed_struct.type.type.decls[1].bitsize.value, '2')
825
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300826 def test_tags_namespace(self):
827 """ Tests that the tags of structs/unions/enums reside in a separate namespace and
828 can be named after existing types.
829 """
830 s1 = """
831 typedef int tagEntry;
832
833 struct tagEntry
834 {
835 char* key;
836 char* value;
837 } Entry;
838 """
839
840 s1_ast = self.parse(s1)
841 self.assertEqual(expand_decl(s1_ast.ext[1]),
842 ['Decl', 'Entry',
843 ['TypeDecl', ['Struct', 'tagEntry',
844 [['Decl', 'key',
845 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
846 ['Decl', 'value',
847 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
848
849 s2 = """
850 struct tagEntry;
851
852 typedef struct tagEntry tagEntry;
853
854 struct tagEntry
855 {
856 char* key;
857 char* value;
858 } Entry;
859 """
860
861 s2_ast = self.parse(s2)
862 self.assertEqual(expand_decl(s2_ast.ext[2]),
863 ['Decl', 'Entry',
864 ['TypeDecl', ['Struct', 'tagEntry',
865 [['Decl', 'key',
866 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
867 ['Decl', 'value',
868 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
869
870 s3 = """
871 typedef int mytag;
872
873 enum mytag {ABC, CDE};
874 enum mytag joe;
875 """
876
877 s3_type = self.parse(s3).ext[1].type
878
879 self.assertTrue(isinstance(s3_type, Enum))
880 self.assertEqual(s3_type.name, 'mytag')
881
882 def test_multi_decls(self):
883 d1 = 'int a, b;'
884
885 self.assertEqual(self.get_decl(d1, 0),
886 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
887 self.assertEqual(self.get_decl(d1, 1),
888 ['Decl', 'b', ['TypeDecl', ['IdentifierType', ['int']]]])
889
890 d2 = 'char* p, notp, ar[4];'
891 self.assertEqual(self.get_decl(d2, 0),
892 ['Decl', 'p',
893 ['PtrDecl',
894 ['TypeDecl', ['IdentifierType', ['char']]]]])
895 self.assertEqual(self.get_decl(d2, 1),
896 ['Decl', 'notp', ['TypeDecl', ['IdentifierType', ['char']]]])
897 self.assertEqual(self.get_decl(d2, 2),
898 ['Decl', 'ar',
899 ['ArrayDecl', '4',
900 ['TypeDecl', ['IdentifierType', ['char']]]]])
901
902 def test_invalid_multiple_types_error(self):
903 bad = [
904 'int enum {ab, cd} fubr;',
905 'enum kid char brbr;']
906
907 for b in bad:
908 self.assertRaises(ParseError, self.parse, b)
909
910 def test_decl_inits(self):
911 d1 = 'int a = 16;'
eli.benderskyf890a862010-10-30 12:13:23 +0200912 #~ self.parse(d1).show()
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300913 self.assertEqual(self.get_decl(d1),
914 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
915 self.assertEqual(self.get_decl_init(d1),
916 ['Constant', 'int', '16'])
917
918 d2 = 'long ar[] = {7, 8, 9};'
eli.benderskyf890a862010-10-30 12:13:23 +0200919 #~ self.parse(d2).show()
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300920 self.assertEqual(self.get_decl(d2),
921 ['Decl', 'ar',
922 ['ArrayDecl', '',
923 ['TypeDecl', ['IdentifierType', ['long']]]]])
924 self.assertEqual(self.get_decl_init(d2),
925 [ ['Constant', 'int', '7'],
926 ['Constant', 'int', '8'],
eli.benderskyf890a862010-10-30 12:13:23 +0200927 ['Constant', 'int', '9']])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300928
929 d3 = 'char p = j;'
930 self.assertEqual(self.get_decl(d3),
931 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['char']]]])
932 self.assertEqual(self.get_decl_init(d3),
933 ['ID', 'j'])
934
935 d4 = "char x = 'c', *p = {0, 1, 2, {4, 5}, 6};"
936 self.assertEqual(self.get_decl(d4, 0),
937 ['Decl', 'x', ['TypeDecl', ['IdentifierType', ['char']]]])
938 self.assertEqual(self.get_decl_init(d4, 0),
939 ['Constant', 'char', "'c'"])
940 self.assertEqual(self.get_decl(d4, 1),
941 ['Decl', 'p',
942 ['PtrDecl',
943 ['TypeDecl', ['IdentifierType', ['char']]]]])
eli.benderskyf890a862010-10-30 12:13:23 +0200944
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300945 self.assertEqual(self.get_decl_init(d4, 1),
946 [ ['Constant', 'int', '0'],
947 ['Constant', 'int', '1'],
948 ['Constant', 'int', '2'],
eli.benderskyf890a862010-10-30 12:13:23 +0200949 [['Constant', 'int', '4'],
950 ['Constant', 'int', '5']],
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300951 ['Constant', 'int', '6']])
eli.benderskyf890a862010-10-30 12:13:23 +0200952
953 def test_decl_named_inits(self):
954 d1 = 'int a = {.k = 16};'
955 self.assertEqual(self.get_decl_init(d1),
956 [( [['ID', 'k']],
957 ['Constant', 'int', '16'])])
958
959 d2 = 'int a = { [0].a = {1}, [1].a[0] = 2 };'
960 self.assertEqual(self.get_decl_init(d2),
961 [
962 ([['Constant', 'int', '0'], ['ID', 'a']],
963 [['Constant', 'int', '1']]),
964 ([['Constant', 'int', '1'], ['ID', 'a'], ['Constant', 'int', '0']],
965 ['Constant', 'int', '2'])])
966
967 d3 = 'int a = { .a = 1, .c = 3, 4, .b = 5};'
968 self.assertEqual(self.get_decl_init(d3),
969 [
970 ([['ID', 'a']], ['Constant', 'int', '1']),
971 ([['ID', 'c']], ['Constant', 'int', '3']),
972 ['Constant', 'int', '4'],
973 ([['ID', 'b']], ['Constant', 'int', '5'])])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300974
975 def test_function_definitions(self):
976 def parse_fdef(str):
977 return self.parse(str).ext[0]
978
979 def fdef_decl(fdef):
980 return expand_decl(fdef.decl)
981
982 f1 = parse_fdef('''
983 int factorial(int p)
984 {
985 return 3;
986 }
987 ''')
988
989 self.assertEqual(fdef_decl(f1),
990 ['Decl', 'factorial',
991 ['FuncDecl',
992 [['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]]],
993 ['TypeDecl', ['IdentifierType', ['int']]]]])
994
eli.benderskyef29ff92010-10-29 16:25:43 +0200995 self.assertEqual(type(f1.body.block_items[0]), Return)
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300996
997 f2 = parse_fdef('''
998 char* zzz(int p, char* c)
999 {
1000 int a;
1001 char b;
1002
1003 a = b + 2;
1004 return 3;
1005 }
1006 ''')
1007
1008 self.assertEqual(fdef_decl(f2),
1009 ['Decl', 'zzz',
1010 ['FuncDecl',
1011 [ ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]],
1012 ['Decl', 'c', ['PtrDecl',
1013 ['TypeDecl', ['IdentifierType', ['char']]]]]],
1014 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
1015
eli.benderskyef29ff92010-10-29 16:25:43 +02001016 self.assertEqual(list(map(type, f2.body.block_items)),
1017 [Decl, Decl, Assignment, Return])
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001018
1019 f3 = parse_fdef('''
1020 char* zzz(p, c)
1021 long p, *c;
1022 {
1023 int a;
1024 char b;
1025
1026 a = b + 2;
1027 return 3;
1028 }
1029 ''')
1030
1031 self.assertEqual(fdef_decl(f3),
1032 ['Decl', 'zzz',
1033 ['FuncDecl',
1034 [ ['ID', 'p'],
1035 ['ID', 'c']],
1036 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
1037
eli.benderskyef29ff92010-10-29 16:25:43 +02001038 self.assertEqual(list(map(type, f3.body.block_items)),
1039 [Decl, Decl, Assignment, Return])
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001040
1041 self.assertEqual(expand_decl(f3.param_decls[0]),
1042 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['long']]]])
1043 self.assertEqual(expand_decl(f3.param_decls[1]),
1044 ['Decl', 'c', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['long']]]]])
1045
eli.bendersky71540662010-07-03 12:58:52 +02001046 def test_unified_string_literals(self):
1047 # simple string, for reference
1048 d1 = self.get_decl_init('char* s = "hello";')
1049 self.assertEqual(d1, ['Constant', 'string', '"hello"'])
1050
1051 d2 = self.get_decl_init('char* s = "hello" " world";')
1052 self.assertEqual(d2, ['Constant', 'string', '"hello world"'])
1053
1054 # the test case from issue 6
1055 d3 = self.parse(r'''
1056 int main() {
1057 fprintf(stderr,
1058 "Wrong Params?\n"
1059 "Usage:\n"
1060 "%s <binary_file_path>\n",
1061 argv[0]
1062 );
1063 }
1064 ''')
1065
1066 self.assertEqual(
eli.benderskyef29ff92010-10-29 16:25:43 +02001067 d3.ext[0].body.block_items[0].args.exprs[1].value,
eli.bendersky71540662010-07-03 12:58:52 +02001068 r'"Wrong Params?\nUsage:\n%s <binary_file_path>\n"')
eli.bendersky4a89f112010-07-05 06:02:03 +02001069
1070 d4 = self.get_decl_init('char* s = "" "foobar";')
1071 self.assertEqual(d4, ['Constant', 'string', '"foobar"'])
1072
1073 d5 = self.get_decl_init(r'char* s = "foo\"" "bar";')
1074 self.assertEqual(d5, ['Constant', 'string', r'"foo\"bar"'])
eli.bendersky71540662010-07-03 12:58:52 +02001075
eli.bendersky79d5cf62010-10-29 13:33:52 +02001076 def test_inline_specifier(self):
1077 ps2 = self.parse('static inline void inlinefoo(void);')
1078 self.assertEqual(ps2.ext[0].funcspec, ['inline'])
eli.bendersky2e907fa2010-10-29 15:51:07 +02001079
1080 # variable length array
1081 def test_vla(self):
1082 ps2 = self.parse(r'''
1083 int main() {
1084 int size;
1085 int var[size = 5];
1086
1087 int var2[*];
1088 }
1089 ''')
eli.benderskyef29ff92010-10-29 16:25:43 +02001090 self.failUnless(isinstance(ps2.ext[0].body.block_items[1].type.dim, Assignment))
1091 self.failUnless(isinstance(ps2.ext[0].body.block_items[2].type.dim, ID))
eli.bendersky79d5cf62010-10-29 13:33:52 +02001092
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001093
eli.bendersky85d2e732011-05-20 19:47:26 +03001094class TestCParser_whole_code(TestCParser_base):
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001095 """ Testing of parsing whole chunks of code.
1096
1097 Since I don't want to rely on the structure of ASTs too
1098 much, most of these tests are implemented with visitors.
1099 """
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001100 # A simple helper visitor that lists the values of all the
1101 # Constant nodes it sees.
1102 #
1103 class ConstantVisitor(NodeVisitor):
1104 def __init__(self):
1105 self.values = []
1106
1107 def visit_Constant(self, node):
1108 self.values.append(node.value)
1109
1110 # This visitor counts the amount of references to the ID
1111 # with the name provided to it in the constructor.
1112 #
1113 class IDNameCounter(NodeVisitor):
1114 def __init__(self, name):
1115 self.name = name
1116 self.nrefs = 0
1117
1118 def visit_ID(self, node):
1119 if node.name == self.name:
1120 self.nrefs += 1
1121
1122 # Counts the amount of nodes of a given class
1123 #
1124 class NodeKlassCounter(NodeVisitor):
1125 def __init__(self, node_klass):
1126 self.klass = node_klass
1127 self.n = 0
1128
1129 def generic_visit(self, node):
1130 if node.__class__ == self.klass:
1131 self.n += 1
1132
1133 NodeVisitor.generic_visit(self, node)
1134
1135 def assert_all_Constants(self, code, constants):
1136 """ Asserts that the list of all Constant values (by
1137 'preorder' appearance) in the chunk of code is as
1138 given.
1139 """
eli.benderskyed890492010-06-25 08:25:55 +03001140 if isinstance(code, str):
1141 parsed = self.parse(code)
1142 else:
1143 parsed = code
1144
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001145 cv = self.ConstantVisitor()
1146 cv.visit(parsed)
1147 self.assertEqual(cv.values, constants)
1148
1149 def assert_num_ID_refs(self, code, name, num):
1150 """ Asserts the number of references to the ID with
1151 the given name.
1152 """
1153 if isinstance(code, str):
1154 parsed = self.parse(code)
1155 else:
1156 parsed = code
1157
1158 iv = self.IDNameCounter(name)
1159 iv.visit(parsed)
1160 self.assertEqual(iv.nrefs, num)
1161
1162 def assert_num_klass_nodes(self, code, klass, num):
1163 """ Asserts the amount of klass nodes in the code.
1164 """
1165 if isinstance(code, str):
1166 parsed = self.parse(code)
1167 else:
1168 parsed = code
1169
1170 cv = self.NodeKlassCounter(klass)
1171 cv.visit(parsed)
1172 self.assertEqual(cv.n, num)
1173
1174 def test_expressions(self):
1175 e1 = '''int k = (r + 10.0) >> 6 + 8 << (3 & 0x14);'''
1176 self.assert_all_Constants(e1, ['10.0', '6', '8', '3', '0x14'])
1177
1178 e2 = r'''char n = '\n', *prefix = "st_";'''
1179 self.assert_all_Constants(e2, [r"'\n'", '"st_"'])
1180
1181 def test_statements(self):
1182 s1 = r'''
1183 void foo(){
1184 if (sp == 1)
1185 if (optind >= argc ||
1186 argv[optind][0] != '-' || argv[optind][1] == '\0')
1187 return -1;
1188 else if (strcmp(argv[optind], "--") == 0) {
1189 optind++;
1190 return -1;
1191 }
1192 }
1193 '''
1194
1195 self.assert_all_Constants(s1,
1196 ['1', '0', r"'-'", '1', r"'\0'", '1', r'"--"', '0', '1'])
1197
1198 ps1 = self.parse(s1)
1199 self.assert_num_ID_refs(ps1, 'argv', 3)
1200 self.assert_num_ID_refs(ps1, 'optind', 5)
1201
1202 self.assert_num_klass_nodes(ps1, If, 3)
1203 self.assert_num_klass_nodes(ps1, Return, 2)
1204 self.assert_num_klass_nodes(ps1, FuncCall, 1) # strcmp
1205 self.assert_num_klass_nodes(ps1, BinaryOp, 7)
1206
1207 # In the following code, Hash and Node were defined as
1208 # int to pacify the parser that sees they're used as
1209 # types
1210 #
1211 s2 = r'''
1212 typedef int Hash, Node;
1213
1214 void HashDestroy(Hash* hash)
1215 {
1216 unsigned int i;
1217
1218 if (hash == NULL)
1219 return;
1220
1221 for (i = 0; i < hash->table_size; ++i)
1222 {
1223 Node* temp = hash->heads[i];
1224
1225 while (temp != NULL)
1226 {
1227 Node* temp2 = temp;
1228
1229 free(temp->entry->key);
1230 free(temp->entry->value);
1231 free(temp->entry);
1232
1233 temp = temp->next;
1234
1235 free(temp2);
1236 }
1237 }
1238
1239 free(hash->heads);
1240 hash->heads = NULL;
1241
1242 free(hash);
1243 }
1244 '''
1245
1246 ps2 = self.parse(s2)
1247 self.assert_num_klass_nodes(ps2, FuncCall, 6)
1248 self.assert_num_klass_nodes(ps2, FuncDef, 1)
1249 self.assert_num_klass_nodes(ps2, For, 1)
1250 self.assert_num_klass_nodes(ps2, While, 1)
1251 self.assert_num_klass_nodes(ps2, StructRef, 10)
1252
1253 # declarations don't count
1254 self.assert_num_ID_refs(ps2, 'hash', 6)
1255 self.assert_num_ID_refs(ps2, 'i', 4)
eli.benderskyed890492010-06-25 08:25:55 +03001256
1257 s3 = r'''
1258 void x(void) {
1259 int a, b;
1260 if (a < b)
1261 do {
1262 a = 0;
1263 } while (0);
1264 else if (a == b) {
1265 a = 1;
1266 }
1267 }
1268 '''
1269
1270 ps3 = self.parse(s3)
1271 self.assert_num_klass_nodes(ps3, DoWhile, 1)
1272 self.assert_num_ID_refs(ps3, 'a', 4)
1273 self.assert_all_Constants(ps3, ['0', '0', '1'])
eli.bendersky91c0aa32011-10-16 05:50:43 +02001274
1275 def test_empty_statement(self):
1276 s1 = r'''
1277 void foo(void){
1278 ;
1279 return;
1280 }
1281 '''
1282 ps1 = self.parse(s1)
1283 self.assert_num_klass_nodes(ps1, EmptyStatement, 1)
1284 self.assert_num_klass_nodes(ps1, Return, 1)
eli.bendersky145890d2010-10-29 12:02:32 +02001285
Ben5cd3fd62012-02-03 06:02:40 +02001286 def test_switch_statement(self):
Eli Bendersky12f0c9d2012-02-03 11:22:25 +02001287 def assert_case_node(node, const_value):
1288 self.failUnless(isinstance(node, Case))
1289 self.failUnless(isinstance(node.expr, Constant))
1290 self.assertEqual(node.expr.value, const_value)
1291
1292 def assert_default_node(node):
1293 self.failUnless(isinstance(node, Default))
1294
Ben5cd3fd62012-02-03 06:02:40 +02001295 s1 = r'''
1296 int foo(void) {
1297 switch (myvar) {
1298 case 10:
1299 k = 10;
1300 p = k + 1;
1301 return 10;
1302 case 20:
1303 case 30:
1304 return 20;
1305 default:
1306 break;
1307 }
1308 return 0;
1309 }
1310 '''
1311 ps1 = self.parse(s1)
Eli Bendersky12f0c9d2012-02-03 11:22:25 +02001312 switch = ps1.ext[0].body.block_items[0]
1313
1314 block = switch.stmt.block_items
1315 assert_case_node(block[0], '10')
1316 self.assertEqual(len(block[0].stmts), 3)
1317 assert_case_node(block[1], '20')
1318 self.assertEqual(len(block[1].stmts), 0)
1319 assert_case_node(block[2], '30')
1320 self.assertEqual(len(block[2].stmts), 1)
1321 assert_default_node(block[3])
1322
1323 s2 = r'''
1324 int foo(void) {
1325 switch (myvar) {
1326 default:
1327 joe = moe;
1328 return 10;
1329 case 10:
1330 case 20:
1331 case 30:
1332 case 40:
1333 break;
1334 }
1335 return 0;
1336 }
1337 '''
1338 ps2 = self.parse(s2)
1339 switch = ps2.ext[0].body.block_items[0]
1340
1341 block = switch.stmt.block_items
1342 assert_default_node(block[0])
1343 self.assertEqual(len(block[0].stmts), 2)
1344 assert_case_node(block[1], '10')
1345 self.assertEqual(len(block[1].stmts), 0)
1346 assert_case_node(block[2], '20')
1347 self.assertEqual(len(block[1].stmts), 0)
1348 assert_case_node(block[3], '30')
1349 self.assertEqual(len(block[1].stmts), 0)
1350 assert_case_node(block[4], '40')
1351 self.assertEqual(len(block[4].stmts), 1)
Ben5cd3fd62012-02-03 06:02:40 +02001352
eli.bendersky145890d2010-10-29 12:02:32 +02001353 def test_for_statement(self):
1354 s2 = r'''
1355 void x(void)
1356 {
1357 int i;
1358 for (i = 0; i < 5; ++i) {
1359 x = 50;
1360 }
1361 }
1362 '''
1363 ps2 = self.parse(s2)
1364 self.assert_num_klass_nodes(ps2, For, 1)
1365 # here there are 3 refs to 'i' since the declaration doesn't count as
1366 # a ref in the visitor
1367 #
1368 self.assert_num_ID_refs(ps2, 'i', 3)
eli.benderskyed890492010-06-25 08:25:55 +03001369
eli.bendersky145890d2010-10-29 12:02:32 +02001370 s3 = r'''
1371 void x(void)
1372 {
1373 for (int i = 0; i < 5; ++i) {
1374 x = 50;
1375 }
1376 }
1377 '''
1378 ps3 = self.parse(s3)
eli.bendersky145890d2010-10-29 12:02:32 +02001379 self.assert_num_klass_nodes(ps3, For, 1)
1380 # here there are 2 refs to 'i' since the declaration doesn't count as
1381 # a ref in the visitor
1382 #
1383 self.assert_num_ID_refs(ps3, 'i', 2)
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001384
Eli Benderskyd0973782012-01-19 08:09:33 +02001385 def _open_c_file(self, name):
1386 """ Find a c file by name, taking into account the current dir can be
1387 in a couple of typical places
1388 """
1389 fullnames = [
1390 os.path.join('c_files', name),
1391 os.path.join('tests', 'c_files', name)]
1392 for fullname in fullnames:
1393 if os.path.exists(fullname):
1394 return open(fullname, 'rU')
1395 assert False, "Unreachable"
1396
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001397 def test_whole_file(self):
1398 # See how pycparser handles a whole, real C file.
1399 #
Eli Benderskyd0973782012-01-19 08:09:33 +02001400 code = self._open_c_file('memmgr_with_h.c').read()
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001401 p = self.parse(code)
1402
1403 self.assert_num_klass_nodes(p, FuncDef, 5)
1404
1405 # each FuncDef also has a FuncDecl. 4 declarations
1406 # + 5 definitions, overall 9
1407 self.assert_num_klass_nodes(p, FuncDecl, 9)
1408
1409 self.assert_num_klass_nodes(p, Typedef, 4)
1410
1411 self.assertEqual(p.ext[4].coord.line, 88)
1412 self.assertEqual(p.ext[4].coord.file, "./memmgr.h")
1413
1414 self.assertEqual(p.ext[6].coord.line, 10)
1415 self.assertEqual(p.ext[6].coord.file, "memmgr.c")
1416
1417 def test_whole_file_with_stdio(self):
1418 # Parse a whole file with stdio.h included by cpp
1419 #
Eli Benderskyd0973782012-01-19 08:09:33 +02001420 code = self._open_c_file('cppd_with_stdio_h.c').read()
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001421 p = self.parse(code)
1422
1423 self.failUnless(isinstance(p.ext[0], Typedef))
1424 self.assertEqual(p.ext[0].coord.line, 213)
1425 self.assertEqual(p.ext[0].coord.file, "D:\eli\cpp_stuff\libc_include/stddef.h")
1426
1427 self.failUnless(isinstance(p.ext[-1], FuncDef))
1428 self.assertEqual(p.ext[-1].coord.line, 15)
1429 self.assertEqual(p.ext[-1].coord.file, "example_c_file.c")
1430
1431 self.failUnless(isinstance(p.ext[-8], Typedef))
1432 self.failUnless(isinstance(p.ext[-8].type, TypeDecl))
1433 self.assertEqual(p.ext[-8].name, 'cookie_io_functions_t')
eli.bendersky85d2e732011-05-20 19:47:26 +03001434
1435
1436class TestCParser_typenames(TestCParser_base):
1437 """ Test issues related to the typedef-name problem.
1438 """
1439 def test_innerscope_typedef(self):
1440 # should fail since TT is not a type in bar
1441 s1 = r'''
1442 void foo() {
1443 typedef char TT;
1444 TT x;
1445 }
1446 void bar() {
1447 TT y;
1448 }
1449 '''
1450 self.assertRaises(ParseError, self.parse, s1)
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001451
eli.bendersky85d2e732011-05-20 19:47:26 +03001452 # should succeed since TT is not a type in bar
1453 s2 = r'''
1454 void foo() {
1455 typedef char TT;
1456 TT x;
1457 }
1458 void bar() {
1459 unsigned TT;
1460 }
1461 '''
1462 self.failUnless(isinstance(self.parse(s2), FileAST))
1463
1464
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001465
1466if __name__ == '__main__':
1467 #~ suite = unittest.TestLoader().loadTestsFromNames(
1468 #~ ['test_c_parser.TestCParser_fundamentals.test_typedef'])
1469
1470 #~ suite = unittest.TestLoader().loadTestsFromNames(
1471 #~ ['test_c_parser.TestCParser_whole_code.test_whole_file_with_stdio'])
1472
1473 #~ suite = unittest.TestLoader().loadTestsFromTestCase(
1474 #~ TestCParser_whole_code)
1475
1476 #~ unittest.TextTestRunner(verbosity=2).run(suite)
1477 unittest.main()