blob: f14d542ab12f4a6123ba05eb232db9f2a3a28f21 [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 Benderskybf4fae82012-01-24 06:06:24 +0200116 # First statement empty
117 t = self.parse('; char c;')
118 self.assertEqual(len(t.ext), 1)
119
eli.bendersky38165b72011-02-04 08:13:39 +0200120 def test_empty_toplevel_decl(self):
121 code = 'int foo;;'
122 t = self.parse(code)
123 self.failUnless(isinstance(t, FileAST))
124 self.assertEqual(len(t.ext), 1)
125 self.assertEqual(self.get_decl(code),
126 ['Decl', 'foo',
127 ['TypeDecl', ['IdentifierType', ['int']]]])
128
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300129 def assert_coord(self, node, line, file=None):
130 self.assertEqual(node.coord.line, line)
131 if file:
132 self.assertEqual(node.coord.file, file)
133
134 def test_coords(self):
eli.bendersky38165b72011-02-04 08:13:39 +0200135 """ Tests the "coordinates" of parsed elements - file
136 name and line numbers, with modification insterted by
137 #line directives.
138 """
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300139 self.assert_coord(self.parse('int a;').ext[0], 1)
140
141 t1 = """
142 int a;
143 int b;\n\n
144 int c;
145 """
146 f1 = self.parse(t1, filename='test.c')
147 self.assert_coord(f1.ext[0], 2, 'test.c')
148 self.assert_coord(f1.ext[1], 3, 'test.c')
149 self.assert_coord(f1.ext[2], 6, 'test.c')
150
151 t1_1 = '''
152 int main() {
153 k = p;
154 printf("%d", b);
155 return 0;
156 }'''
157 f1_1 = self.parse(t1_1, filename='test.c')
eli.benderskyef29ff92010-10-29 16:25:43 +0200158 self.assert_coord(f1_1.ext[0].body.block_items[0], 3, 'test.c')
159 self.assert_coord(f1_1.ext[0].body.block_items[1], 4, 'test.c')
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200160
161 t1_2 = '''
162 int main () {
163 int p = (int) k;
164 }'''
165 f1_2 = self.parse(t1_2, filename='test.c')
166 # make sure that the Cast has a coord (issue 23)
167 self.assert_coord(f1_2.ext[0].body.block_items[0].init, 3, 'test.c')
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300168
169 t2 = """
170 #line 99
171 int c;
172 """
173 self.assert_coord(self.parse(t2).ext[0], 99)
174
175 t3 = """
176 int dsf;
177 char p;
178 #line 3000 "in.h"
179 char d;
180 """
181 f3 = self.parse(t3, filename='test.c')
182 self.assert_coord(f3.ext[0], 2, 'test.c')
183 self.assert_coord(f3.ext[1], 3, 'test.c')
184 self.assert_coord(f3.ext[2], 3000, 'in.h')
185
186 t4 = """
187 #line 20 "restore.h"
188 int maydler(char);
189
190 #line 30 "includes/daween.ph"
191 long j, k;
192
193 #line 50000
194 char* ro;
195 """
196 f4 = self.parse(t4, filename='myb.c')
197 self.assert_coord(f4.ext[0], 20, 'restore.h')
198 self.assert_coord(f4.ext[1], 30, 'includes/daween.ph')
199 self.assert_coord(f4.ext[2], 30, 'includes/daween.ph')
200 self.assert_coord(f4.ext[3], 50000, 'includes/daween.ph')
201
202 t5 = """
203 int
204 #line 99
205 c;
206 """
207 self.assert_coord(self.parse(t5).ext[0], 99)
208
209 def test_simple_decls(self):
210 self.assertEqual(self.get_decl('int a;'),
211 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
212
213 self.assertEqual(self.get_decl('unsigned int a;'),
Eli Bendersky68497c22012-01-19 06:04:58 +0200214 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['unsigned', 'int']]]])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300215
eli.benderskyaffe0322011-09-24 06:16:55 +0300216 self.assertEqual(self.get_decl('_Bool a;'),
217 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['_Bool']]]])
218
Eli Benderskyf4d73462012-01-19 05:56:27 +0200219 self.assertEqual(self.get_decl('float _Complex fcc;'),
Eli Bendersky68497c22012-01-19 06:04:58 +0200220 ['Decl', 'fcc', ['TypeDecl', ['IdentifierType', ['float', '_Complex']]]])
Eli Benderskyf4d73462012-01-19 05:56:27 +0200221
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300222 self.assertEqual(self.get_decl('char* string;'),
223 ['Decl', 'string',
224 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]])
225
226 self.assertEqual(self.get_decl('long ar[15];'),
227 ['Decl', 'ar',
228 ['ArrayDecl', '15',
229 ['TypeDecl', ['IdentifierType', ['long']]]]])
eli.bendersky98f45372010-10-30 09:46:29 +0200230
231 self.assertEqual(self.get_decl('long long ar[15];'),
232 ['Decl', 'ar',
233 ['ArrayDecl', '15',
eli.benderskyf890a862010-10-30 12:13:23 +0200234 ['TypeDecl', ['IdentifierType', ['long', 'long']]]]])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300235
236 self.assertEqual(self.get_decl('unsigned ar[];'),
237 ['Decl', 'ar',
238 ['ArrayDecl', '',
239 ['TypeDecl', ['IdentifierType', ['unsigned']]]]])
240
241 self.assertEqual(self.get_decl('int strlen(char* s);'),
242 ['Decl', 'strlen',
243 ['FuncDecl',
244 [['Decl', 's',
245 ['PtrDecl',
246 ['TypeDecl', ['IdentifierType', ['char']]]]]],
247 ['TypeDecl', ['IdentifierType', ['int']]]]])
248
249 self.assertEqual(self.get_decl('int strcmp(char* s1, char* s2);'),
250 ['Decl', 'strcmp',
251 ['FuncDecl',
252 [ ['Decl', 's1',
253 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
254 ['Decl', 's2',
255 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]
256 ],
257 ['TypeDecl', ['IdentifierType', ['int']]]]])
258
259 def test_nested_decls(self): # the fun begins
260 self.assertEqual(self.get_decl('char** ar2D;'),
261 ['Decl', 'ar2D',
262 ['PtrDecl', ['PtrDecl',
263 ['TypeDecl', ['IdentifierType', ['char']]]]]])
264
265 self.assertEqual(self.get_decl('int (*a)[1][2];'),
266 ['Decl', 'a',
267 ['PtrDecl',
268 ['ArrayDecl', '1',
269 ['ArrayDecl', '2',
270 ['TypeDecl', ['IdentifierType', ['int']]]]]]])
271
272 self.assertEqual(self.get_decl('int *a[1][2];'),
273 ['Decl', 'a',
274 ['ArrayDecl', '1',
275 ['ArrayDecl', '2',
276 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['int']]]]]]])
277
278 self.assertEqual(self.get_decl('char ***ar3D[40];'),
279 ['Decl', 'ar3D',
280 ['ArrayDecl', '40',
281 ['PtrDecl', ['PtrDecl', ['PtrDecl',
282 ['TypeDecl', ['IdentifierType', ['char']]]]]]]])
283
284 self.assertEqual(self.get_decl('char (***ar3D)[40];'),
285 ['Decl', 'ar3D',
286 ['PtrDecl', ['PtrDecl', ['PtrDecl',
287 ['ArrayDecl', '40', ['TypeDecl', ['IdentifierType', ['char']]]]]]]])
288
289 self.assertEqual(self.get_decl('int (*x[4])(char, int);'),
290 ['Decl', 'x',
291 ['ArrayDecl', '4',
292 ['PtrDecl',
293 ['FuncDecl',
294 [ ['Typename', ['TypeDecl', ['IdentifierType', ['char']]]],
295 ['Typename', ['TypeDecl', ['IdentifierType', ['int']]]]],
296 ['TypeDecl', ['IdentifierType', ['int']]]]]]])
297
298 self.assertEqual(self.get_decl('char *(*(**foo [][8])())[];'),
299 ['Decl', 'foo',
300 ['ArrayDecl', '',
301 ['ArrayDecl', '8',
302 ['PtrDecl', ['PtrDecl',
303 ['FuncDecl',
304 [],
305 ['PtrDecl',
306 ['ArrayDecl', '',
307 ['PtrDecl',
308 ['TypeDecl',
309 ['IdentifierType', ['char']]]]]]]]]]]])
310
311 # explore named and unnamed function pointer parameters,
312 # with and without qualifiers
313 #
314
315 # unnamed w/o quals
316 self.assertEqual(self.get_decl('int (*k)(int);'),
317 ['Decl', 'k',
318 ['PtrDecl',
319 ['FuncDecl',
320 [['Typename', ['TypeDecl', ['IdentifierType', ['int']]]]],
321 ['TypeDecl', ['IdentifierType', ['int']]]]]])
322
323 # unnamed w/ quals
324 self.assertEqual(self.get_decl('int (*k)(const int);'),
325 ['Decl', 'k',
326 ['PtrDecl',
327 ['FuncDecl',
328 [['Typename', ['const'], ['TypeDecl', ['IdentifierType', ['int']]]]],
329 ['TypeDecl', ['IdentifierType', ['int']]]]]])
330
331 # named w/o quals
332 self.assertEqual(self.get_decl('int (*k)(int q);'),
333 ['Decl', 'k',
334 ['PtrDecl',
335 ['FuncDecl',
336 [['Decl', 'q', ['TypeDecl', ['IdentifierType', ['int']]]]],
337 ['TypeDecl', ['IdentifierType', ['int']]]]]])
338
339 # named w/ quals
340 self.assertEqual(self.get_decl('int (*k)(const volatile int q);'),
341 ['Decl', 'k',
342 ['PtrDecl',
343 ['FuncDecl',
Eli Bendersky68497c22012-01-19 06:04:58 +0200344 [['Decl', ['const', 'volatile'], 'q',
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300345 ['TypeDecl', ['IdentifierType', ['int']]]]],
346 ['TypeDecl', ['IdentifierType', ['int']]]]]])
347
eli.bendersky79d5cf62010-10-29 13:33:52 +0200348 # restrict qualifier
349 self.assertEqual(self.get_decl('int (*k)(restrict int* q);'),
350 ['Decl', 'k',
351 ['PtrDecl',
352 ['FuncDecl',
353 [['Decl', ['restrict'], 'q',
354 ['PtrDecl',
355 ['TypeDecl', ['IdentifierType', ['int']]]]]],
356 ['TypeDecl', ['IdentifierType', ['int']]]]]])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300357
358 def test_qualifiers_storage_specifiers(self):
359 def assert_qs(txt, index, quals, storage):
360 d = self.parse(txt).ext[index]
361 self.assertEqual(d.quals, quals)
362 self.assertEqual(d.storage, storage)
363
364 assert_qs("extern int p;", 0, [], ['extern'])
365 assert_qs("const long p = 6;", 0, ['const'], [])
366
367 d1 = "static const int p, q, r;"
368 for i in range(3):
369 assert_qs(d1, i, ['const'], ['static'])
370
371 d2 = "static char * const p;"
372 assert_qs(d2, 0, [], ['static'])
373 pdecl = self.parse(d2).ext[0].type
374 self.failUnless(isinstance(pdecl, PtrDecl))
375 self.assertEqual(pdecl.quals, ['const'])
376
377 def test_sizeof(self):
378 e = """
379 void foo()
380 {
381 int a = sizeof k;
382 int b = sizeof(int);
eli.benderskyc51e1d32011-02-04 08:52:33 +0200383 int c = sizeof(int**);;
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300384
385 char* p = "just to make sure this parses w/o error...";
386 int d = sizeof(int());
387 }
388 """
389 compound = self.parse(e).ext[0].body
390
eli.benderskyef29ff92010-10-29 16:25:43 +0200391 s1 = compound.block_items[0].init
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300392 self.assertTrue(isinstance(s1, UnaryOp))
393 self.assertEqual(s1.op, 'sizeof')
394 self.assertTrue(isinstance(s1.expr, ID))
395 self.assertEqual(s1.expr.name, 'k')
396
eli.benderskyef29ff92010-10-29 16:25:43 +0200397 s2 = compound.block_items[1].init
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300398 self.assertEqual(expand_decl(s2.expr),
399 ['Typename', ['TypeDecl', ['IdentifierType', ['int']]]])
400
eli.benderskyef29ff92010-10-29 16:25:43 +0200401 s3 = compound.block_items[2].init
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300402 self.assertEqual(expand_decl(s3.expr),
403 ['Typename',
404 ['PtrDecl',
405 ['PtrDecl',
406 ['TypeDecl',
407 ['IdentifierType', ['int']]]]]])
408
eli.bendersky9f481562010-10-30 15:50:47 +0200409 # The C99 compound literal feature
410 #
eli.benderskyf890a862010-10-30 12:13:23 +0200411 def test_compound_literals(self):
eli.bendersky9f481562010-10-30 15:50:47 +0200412 ps1 = self.parse(r'''
eli.benderskyf890a862010-10-30 12:13:23 +0200413 void foo() {
eli.bendersky9f481562010-10-30 15:50:47 +0200414 p = (long long){k};
415 tc = (struct jk){.a = {1, 2}, .b[0] = t};
416 }''')
eli.benderskyf890a862010-10-30 12:13:23 +0200417
eli.bendersky9f481562010-10-30 15:50:47 +0200418 compound = ps1.ext[0].body.block_items[0].rvalue
419 self.assertEqual(expand_decl(compound.type),
420 ['Typename', ['TypeDecl', ['IdentifierType', ['long', 'long']]]])
421 self.assertEqual(expand_init(compound.init),
422 [['ID', 'k']])
423
424 compound = ps1.ext[0].body.block_items[1].rvalue
425 self.assertEqual(expand_decl(compound.type),
426 ['Typename', ['TypeDecl', ['Struct', 'jk', []]]])
427 self.assertEqual(expand_init(compound.init),
428 [
429 ([['ID', 'a']], [['Constant', 'int', '1'], ['Constant', 'int', '2']]),
430 ([['ID', 'b'], ['Constant', 'int', '0']], ['ID', 't'])])
eli.benderskyf890a862010-10-30 12:13:23 +0200431
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300432 def test_enums(self):
433 e1 = "enum mycolor op;"
434 e1_type = self.parse(e1).ext[0].type.type
435
436 self.assertTrue(isinstance(e1_type, Enum))
437 self.assertEqual(e1_type.name, 'mycolor')
438 self.assertEqual(e1_type.values, None)
439
440 e2 = "enum mysize {large=20, small, medium} shoes;"
441 e2_type = self.parse(e2).ext[0].type.type
442
443 self.assertTrue(isinstance(e2_type, Enum))
444 self.assertEqual(e2_type.name, 'mysize')
445
446 e2_elist = e2_type.values
447 self.assertTrue(isinstance(e2_elist, EnumeratorList))
448
449 for e2_eval in e2_elist.enumerators:
450 self.assertTrue(isinstance(e2_eval, Enumerator))
451
452 self.assertEqual(e2_elist.enumerators[0].name, 'large')
453 self.assertEqual(e2_elist.enumerators[0].value.value, '20')
454 self.assertEqual(e2_elist.enumerators[2].name, 'medium')
455 self.assertEqual(e2_elist.enumerators[2].value, None)
456
457 # enum with trailing comma (C99 feature)
458 e3 = """
459 enum
460 {
461 red,
462 blue,
463 green,
464 } color;
465 """
466
467 e3_type = self.parse(e3).ext[0].type.type
468 self.assertTrue(isinstance(e3_type, Enum))
469 e3_elist = e3_type.values
470 self.assertTrue(isinstance(e3_elist, EnumeratorList))
471
472 for e3_eval in e3_elist.enumerators:
473 self.assertTrue(isinstance(e3_eval, Enumerator))
474
475 self.assertEqual(e3_elist.enumerators[0].name, 'red')
476 self.assertEqual(e3_elist.enumerators[0].value, None)
477 self.assertEqual(e3_elist.enumerators[1].name, 'blue')
478 self.assertEqual(e3_elist.enumerators[2].name, 'green')
479
480 def test_typedef(self):
481 # without typedef, error
482 s1 = """
483 node k;
484 """
485 self.assertRaises(ParseError, self.parse, s1)
486
487 # now with typedef, works
488 s2 = """
489 typedef void* node;
490 node k;
491 """
492 ps2 = self.parse(s2)
493 self.assertEqual(expand_decl(ps2.ext[0]),
494 ['Typedef', 'node',
495 ['PtrDecl',
496 ['TypeDecl', ['IdentifierType', ['void']]]]])
497
498 self.assertEqual(expand_decl(ps2.ext[1]),
499 ['Decl', 'k',
500 ['TypeDecl', ['IdentifierType', ['node']]]])
501
502 s3 = """
503 typedef int T;
504 typedef T *pT;
505
506 pT aa, bb;
507 """
508 ps3 = self.parse(s3)
509 self.assertEqual(expand_decl(ps3.ext[3]),
510 ['Decl', 'bb',
511 ['TypeDecl', ['IdentifierType', ['pT']]]])
512
513 s4 = '''
514 typedef char* __builtin_va_list;
515 typedef __builtin_va_list __gnuc_va_list;
516 '''
517 ps4 = self.parse(s4)
518 self.assertEqual(expand_decl(ps4.ext[1]),
519 ['Typedef', '__gnuc_va_list',
520 ['TypeDecl',
521 ['IdentifierType', ['__builtin_va_list']]]])
522
523 s5 = '''typedef struct tagHash Hash;'''
524 ps5 = self.parse(s5)
525 self.assertEqual(expand_decl(ps5.ext[0]),
526 ['Typedef', 'Hash', ['TypeDecl', ['Struct', 'tagHash', []]]])
527
528 def test_struct_union(self):
529 s1 = """
530 struct {
531 int id;
532 char* name;
533 } joe;
534 """
535
536 self.assertEqual(expand_decl(self.parse(s1).ext[0]),
537 ['Decl', 'joe',
538 ['TypeDecl', ['Struct', None,
539 [ ['Decl', 'id',
540 ['TypeDecl',
541 ['IdentifierType', ['int']]]],
542 ['Decl', 'name',
543 ['PtrDecl',
544 ['TypeDecl',
545 ['IdentifierType', ['char']]]]]]]]])
546
547 s2 = """
548 struct node p;
549 """
550 self.assertEqual(expand_decl(self.parse(s2).ext[0]),
551 ['Decl', 'p',
552 ['TypeDecl', ['Struct', 'node', []]]])
553
554 s21 = """
555 union pri ra;
556 """
557 self.assertEqual(expand_decl(self.parse(s21).ext[0]),
558 ['Decl', 'ra',
559 ['TypeDecl', ['Union', 'pri', []]]])
560
561 s3 = """
562 struct node* p;
563 """
564 self.assertEqual(expand_decl(self.parse(s3).ext[0]),
565 ['Decl', 'p',
566 ['PtrDecl',
567 ['TypeDecl', ['Struct', 'node', []]]]])
568
569 s4 = """
570 struct node;
571 """
572 self.assertEqual(expand_decl(self.parse(s4).ext[0]),
573 ['Decl', None,
574 ['Struct', 'node', []]])
575
576 s5 = """
577 union
578 {
579 struct
580 {
581 int type;
582 } n;
583
584 struct
585 {
586 int type;
587 int intnode;
588 } ni;
589 } u;
590 """
591 self.assertEqual(expand_decl(self.parse(s5).ext[0]),
592 ['Decl', 'u',
593 ['TypeDecl',
594 ['Union', None,
595 [['Decl', 'n',
596 ['TypeDecl',
597 ['Struct', None,
598 [['Decl', 'type',
599 ['TypeDecl', ['IdentifierType', ['int']]]]]]]],
600 ['Decl', 'ni',
601 ['TypeDecl',
602 ['Struct', None,
603 [['Decl', 'type',
604 ['TypeDecl', ['IdentifierType', ['int']]]],
605 ['Decl', 'intnode',
606 ['TypeDecl', ['IdentifierType', ['int']]]]]]]]]]]])
607
608 s6 = """
609 typedef struct foo_tag
610 {
611 void* data;
612 } foo, *pfoo;
613 """
614 s6_ast = self.parse(s6)
615
616 self.assertEqual(expand_decl(s6_ast.ext[0]),
617 ['Typedef', 'foo',
618 ['TypeDecl',
619 ['Struct', 'foo_tag',
620 [['Decl', 'data',
621 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]])
622
623 self.assertEqual(expand_decl(s6_ast.ext[1]),
624 ['Typedef', 'pfoo',
625 ['PtrDecl',
626 ['TypeDecl',
627 ['Struct', 'foo_tag',
628 [['Decl', 'data',
629 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]]])
630
631 s7 = r"""
632 struct _on_exit_args {
633 void * _fnargs[32];
634 void * _dso_handle[32];
635
636 long _fntypes;
637 #line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
638
639 long _is_cxa;
640 };
641 """
642
643 s7_ast = self.parse(s7, filename='test.c')
644 self.assert_coord(s7_ast.ext[0].type.decls[2], 6, 'test.c')
645 self.assert_coord(s7_ast.ext[0].type.decls[3], 78,
646 r'D:\eli\cpp_stuff\libc_include/sys/reent.h')
647
648 s8 = """
649 typedef enum tagReturnCode {SUCCESS, FAIL} ReturnCode;
650
651 typedef struct tagEntry
652 {
653 char* key;
654 char* value;
655 } Entry;
656
657
658 typedef struct tagNode
659 {
660 Entry* entry;
661
662 struct tagNode* next;
663 } Node;
664
665 typedef struct tagHash
666 {
667 unsigned int table_size;
668
669 Node** heads;
670
671 } Hash;
672 """
673 s8_ast = self.parse(s8)
674 self.assertEqual(expand_decl(s8_ast.ext[3]),
675 ['Typedef', 'Hash',
676 ['TypeDecl', ['Struct', 'tagHash',
677 [['Decl', 'table_size',
Eli Bendersky68497c22012-01-19 06:04:58 +0200678 ['TypeDecl', ['IdentifierType', ['unsigned', 'int']]]],
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300679 ['Decl', 'heads',
680 ['PtrDecl', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['Node']]]]]]]]]])
681
eli.bendersky697ecc52011-02-10 07:05:13 +0200682 def test_anonymous_struct_union(self):
683 s1 = """
684 union
685 {
686 union
687 {
688 int i;
689 long l;
690 };
691
692 struct
693 {
694 int type;
695 int intnode;
696 };
697 } u;
698 """
699
700 self.assertEqual(expand_decl(self.parse(s1).ext[0]),
701 ['Decl', 'u',
702 ['TypeDecl',
703 ['Union', None,
704 [['Decl', None,
705 ['Union', None,
706 [['Decl', 'i',
707 ['TypeDecl',
708 ['IdentifierType', ['int']]]],
709 ['Decl', 'l',
710 ['TypeDecl',
711 ['IdentifierType', ['long']]]]]]],
712 ['Decl', None,
713 ['Struct', None,
714 [['Decl', 'type',
715 ['TypeDecl',
716 ['IdentifierType', ['int']]]],
717 ['Decl', 'intnode',
718 ['TypeDecl',
719 ['IdentifierType', ['int']]]]]]]]]]])
720
721 s2 = """
722 struct
723 {
724 int i;
725 union
726 {
727 int id;
728 char* name;
729 };
730 float f;
731 } joe;
732 """
733
734 self.assertEqual(expand_decl(self.parse(s2).ext[0]),
735 ['Decl', 'joe',
736 ['TypeDecl',
737 ['Struct', None,
738 [['Decl', 'i',
739 ['TypeDecl',
740 ['IdentifierType', ['int']]]],
741 ['Decl', None,
742 ['Union', None,
743 [['Decl', 'id',
744 ['TypeDecl',
745 ['IdentifierType', ['int']]]],
746 ['Decl', 'name',
747 ['PtrDecl',
748 ['TypeDecl',
749 ['IdentifierType', ['char']]]]]]]],
750 ['Decl', 'f',
751 ['TypeDecl',
752 ['IdentifierType', ['float']]]]]]]])
753
754 # ISO/IEC 9899:201x Commitee Draft 2010-11-16, N1539
755 # section 6.7.2.1, par. 19, example 1
756 s3 = """
757 struct v {
758 union {
759 struct { int i, j; };
760 struct { long k, l; } w;
761 };
762 int m;
763 } v1;
764 """
765
766 self.assertEqual(expand_decl(self.parse(s3).ext[0]),
767 ['Decl', 'v1',
768 ['TypeDecl',
769 ['Struct', 'v',
770 [['Decl', None,
771 ['Union', None,
772 [['Decl', None,
773 ['Struct', None,
774 [['Decl', 'i',
775 ['TypeDecl',
776 ['IdentifierType', ['int']]]],
777 ['Decl', 'j',
778 ['TypeDecl',
779 ['IdentifierType', ['int']]]]]]],
780 ['Decl', 'w',
781 ['TypeDecl',
782 ['Struct', None,
783 [['Decl', 'k',
784 ['TypeDecl',
785 ['IdentifierType', ['long']]]],
786 ['Decl', 'l',
787 ['TypeDecl',
788 ['IdentifierType', ['long']]]]]]]]]]],
789 ['Decl', 'm',
790 ['TypeDecl',
791 ['IdentifierType', ['int']]]]]]]])
792
eli.benderskydce29a02011-02-10 07:55:00 +0200793 s4 = """
794 struct v {
795 int i;
796 float;
797 } v2;"""
eli.bendersky6b011792011-06-22 17:50:56 +0300798 # just make sure this doesn't raise ParseError
799 self.parse(s4)
eli.benderskydce29a02011-02-10 07:55:00 +0200800
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200801 def test_struct_bitfields(self):
eli.bendersky38ed9a92010-10-09 09:29:59 +0200802 # a struct with two bitfields, one unnamed
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200803 s1 = """
804 struct {
805 int k:6;
806 int :2;
807 } joe;
808 """
809
810 parsed_struct = self.parse(s1).ext[0]
811
eli.bendersky38ed9a92010-10-09 09:29:59 +0200812 # We can see here the name of the decl for the unnamed bitfield is
eli.bendersky0e0a71f2010-10-09 08:32:00 +0200813 # None, but expand_decl doesn't show bitfield widths
814 # ...
815 self.assertEqual(expand_decl(parsed_struct),
816 ['Decl', 'joe',
817 ['TypeDecl', ['Struct', None,
818 [ ['Decl', 'k',
819 ['TypeDecl',
820 ['IdentifierType', ['int']]]],
821 ['Decl', None,
822 ['TypeDecl',
823 ['IdentifierType', ['int']]]]]]]])
824
825 # ...
826 # so we test them manually
827 self.assertEqual(parsed_struct.type.type.decls[0].bitsize.value, '6')
828 self.assertEqual(parsed_struct.type.type.decls[1].bitsize.value, '2')
829
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300830 def test_tags_namespace(self):
831 """ Tests that the tags of structs/unions/enums reside in a separate namespace and
832 can be named after existing types.
833 """
834 s1 = """
835 typedef int tagEntry;
836
837 struct tagEntry
838 {
839 char* key;
840 char* value;
841 } Entry;
842 """
843
844 s1_ast = self.parse(s1)
845 self.assertEqual(expand_decl(s1_ast.ext[1]),
846 ['Decl', 'Entry',
847 ['TypeDecl', ['Struct', 'tagEntry',
848 [['Decl', 'key',
849 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
850 ['Decl', 'value',
851 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
852
853 s2 = """
854 struct tagEntry;
855
856 typedef struct tagEntry tagEntry;
857
858 struct tagEntry
859 {
860 char* key;
861 char* value;
862 } Entry;
863 """
864
865 s2_ast = self.parse(s2)
866 self.assertEqual(expand_decl(s2_ast.ext[2]),
867 ['Decl', 'Entry',
868 ['TypeDecl', ['Struct', 'tagEntry',
869 [['Decl', 'key',
870 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
871 ['Decl', 'value',
872 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
873
874 s3 = """
875 typedef int mytag;
876
877 enum mytag {ABC, CDE};
878 enum mytag joe;
879 """
880
881 s3_type = self.parse(s3).ext[1].type
882
883 self.assertTrue(isinstance(s3_type, Enum))
884 self.assertEqual(s3_type.name, 'mytag')
885
886 def test_multi_decls(self):
887 d1 = 'int a, b;'
888
889 self.assertEqual(self.get_decl(d1, 0),
890 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
891 self.assertEqual(self.get_decl(d1, 1),
892 ['Decl', 'b', ['TypeDecl', ['IdentifierType', ['int']]]])
893
894 d2 = 'char* p, notp, ar[4];'
895 self.assertEqual(self.get_decl(d2, 0),
896 ['Decl', 'p',
897 ['PtrDecl',
898 ['TypeDecl', ['IdentifierType', ['char']]]]])
899 self.assertEqual(self.get_decl(d2, 1),
900 ['Decl', 'notp', ['TypeDecl', ['IdentifierType', ['char']]]])
901 self.assertEqual(self.get_decl(d2, 2),
902 ['Decl', 'ar',
903 ['ArrayDecl', '4',
904 ['TypeDecl', ['IdentifierType', ['char']]]]])
905
906 def test_invalid_multiple_types_error(self):
907 bad = [
908 'int enum {ab, cd} fubr;',
909 'enum kid char brbr;']
910
911 for b in bad:
912 self.assertRaises(ParseError, self.parse, b)
913
914 def test_decl_inits(self):
915 d1 = 'int a = 16;'
eli.benderskyf890a862010-10-30 12:13:23 +0200916 #~ self.parse(d1).show()
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300917 self.assertEqual(self.get_decl(d1),
918 ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
919 self.assertEqual(self.get_decl_init(d1),
920 ['Constant', 'int', '16'])
921
922 d2 = 'long ar[] = {7, 8, 9};'
eli.benderskyf890a862010-10-30 12:13:23 +0200923 #~ self.parse(d2).show()
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300924 self.assertEqual(self.get_decl(d2),
925 ['Decl', 'ar',
926 ['ArrayDecl', '',
927 ['TypeDecl', ['IdentifierType', ['long']]]]])
928 self.assertEqual(self.get_decl_init(d2),
929 [ ['Constant', 'int', '7'],
930 ['Constant', 'int', '8'],
eli.benderskyf890a862010-10-30 12:13:23 +0200931 ['Constant', 'int', '9']])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300932
933 d3 = 'char p = j;'
934 self.assertEqual(self.get_decl(d3),
935 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['char']]]])
936 self.assertEqual(self.get_decl_init(d3),
937 ['ID', 'j'])
938
939 d4 = "char x = 'c', *p = {0, 1, 2, {4, 5}, 6};"
940 self.assertEqual(self.get_decl(d4, 0),
941 ['Decl', 'x', ['TypeDecl', ['IdentifierType', ['char']]]])
942 self.assertEqual(self.get_decl_init(d4, 0),
943 ['Constant', 'char', "'c'"])
944 self.assertEqual(self.get_decl(d4, 1),
945 ['Decl', 'p',
946 ['PtrDecl',
947 ['TypeDecl', ['IdentifierType', ['char']]]]])
eli.benderskyf890a862010-10-30 12:13:23 +0200948
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300949 self.assertEqual(self.get_decl_init(d4, 1),
950 [ ['Constant', 'int', '0'],
951 ['Constant', 'int', '1'],
952 ['Constant', 'int', '2'],
eli.benderskyf890a862010-10-30 12:13:23 +0200953 [['Constant', 'int', '4'],
954 ['Constant', 'int', '5']],
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300955 ['Constant', 'int', '6']])
eli.benderskyf890a862010-10-30 12:13:23 +0200956
957 def test_decl_named_inits(self):
958 d1 = 'int a = {.k = 16};'
959 self.assertEqual(self.get_decl_init(d1),
960 [( [['ID', 'k']],
961 ['Constant', 'int', '16'])])
962
963 d2 = 'int a = { [0].a = {1}, [1].a[0] = 2 };'
964 self.assertEqual(self.get_decl_init(d2),
965 [
966 ([['Constant', 'int', '0'], ['ID', 'a']],
967 [['Constant', 'int', '1']]),
968 ([['Constant', 'int', '1'], ['ID', 'a'], ['Constant', 'int', '0']],
969 ['Constant', 'int', '2'])])
970
971 d3 = 'int a = { .a = 1, .c = 3, 4, .b = 5};'
972 self.assertEqual(self.get_decl_init(d3),
973 [
974 ([['ID', 'a']], ['Constant', 'int', '1']),
975 ([['ID', 'c']], ['Constant', 'int', '3']),
976 ['Constant', 'int', '4'],
977 ([['ID', 'b']], ['Constant', 'int', '5'])])
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300978
979 def test_function_definitions(self):
980 def parse_fdef(str):
981 return self.parse(str).ext[0]
982
983 def fdef_decl(fdef):
984 return expand_decl(fdef.decl)
985
986 f1 = parse_fdef('''
987 int factorial(int p)
988 {
989 return 3;
990 }
991 ''')
992
993 self.assertEqual(fdef_decl(f1),
994 ['Decl', 'factorial',
995 ['FuncDecl',
996 [['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]]],
997 ['TypeDecl', ['IdentifierType', ['int']]]]])
998
eli.benderskyef29ff92010-10-29 16:25:43 +0200999 self.assertEqual(type(f1.body.block_items[0]), Return)
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001000
1001 f2 = parse_fdef('''
1002 char* zzz(int p, char* c)
1003 {
1004 int a;
1005 char b;
1006
1007 a = b + 2;
1008 return 3;
1009 }
1010 ''')
1011
1012 self.assertEqual(fdef_decl(f2),
1013 ['Decl', 'zzz',
1014 ['FuncDecl',
1015 [ ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]],
1016 ['Decl', 'c', ['PtrDecl',
1017 ['TypeDecl', ['IdentifierType', ['char']]]]]],
1018 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
1019
eli.benderskyef29ff92010-10-29 16:25:43 +02001020 self.assertEqual(list(map(type, f2.body.block_items)),
1021 [Decl, Decl, Assignment, Return])
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001022
1023 f3 = parse_fdef('''
1024 char* zzz(p, c)
1025 long p, *c;
1026 {
1027 int a;
1028 char b;
1029
1030 a = b + 2;
1031 return 3;
1032 }
1033 ''')
1034
1035 self.assertEqual(fdef_decl(f3),
1036 ['Decl', 'zzz',
1037 ['FuncDecl',
1038 [ ['ID', 'p'],
1039 ['ID', 'c']],
1040 ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
1041
eli.benderskyef29ff92010-10-29 16:25:43 +02001042 self.assertEqual(list(map(type, f3.body.block_items)),
1043 [Decl, Decl, Assignment, Return])
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001044
1045 self.assertEqual(expand_decl(f3.param_decls[0]),
1046 ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['long']]]])
1047 self.assertEqual(expand_decl(f3.param_decls[1]),
1048 ['Decl', 'c', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['long']]]]])
1049
eli.bendersky71540662010-07-03 12:58:52 +02001050 def test_unified_string_literals(self):
1051 # simple string, for reference
1052 d1 = self.get_decl_init('char* s = "hello";')
1053 self.assertEqual(d1, ['Constant', 'string', '"hello"'])
1054
1055 d2 = self.get_decl_init('char* s = "hello" " world";')
1056 self.assertEqual(d2, ['Constant', 'string', '"hello world"'])
1057
1058 # the test case from issue 6
1059 d3 = self.parse(r'''
1060 int main() {
1061 fprintf(stderr,
1062 "Wrong Params?\n"
1063 "Usage:\n"
1064 "%s <binary_file_path>\n",
1065 argv[0]
1066 );
1067 }
1068 ''')
1069
1070 self.assertEqual(
eli.benderskyef29ff92010-10-29 16:25:43 +02001071 d3.ext[0].body.block_items[0].args.exprs[1].value,
eli.bendersky71540662010-07-03 12:58:52 +02001072 r'"Wrong Params?\nUsage:\n%s <binary_file_path>\n"')
eli.bendersky4a89f112010-07-05 06:02:03 +02001073
1074 d4 = self.get_decl_init('char* s = "" "foobar";')
1075 self.assertEqual(d4, ['Constant', 'string', '"foobar"'])
1076
1077 d5 = self.get_decl_init(r'char* s = "foo\"" "bar";')
1078 self.assertEqual(d5, ['Constant', 'string', r'"foo\"bar"'])
eli.bendersky71540662010-07-03 12:58:52 +02001079
eli.bendersky79d5cf62010-10-29 13:33:52 +02001080 def test_inline_specifier(self):
1081 ps2 = self.parse('static inline void inlinefoo(void);')
1082 self.assertEqual(ps2.ext[0].funcspec, ['inline'])
eli.bendersky2e907fa2010-10-29 15:51:07 +02001083
1084 # variable length array
1085 def test_vla(self):
1086 ps2 = self.parse(r'''
1087 int main() {
1088 int size;
1089 int var[size = 5];
1090
1091 int var2[*];
1092 }
1093 ''')
eli.benderskyef29ff92010-10-29 16:25:43 +02001094 self.failUnless(isinstance(ps2.ext[0].body.block_items[1].type.dim, Assignment))
1095 self.failUnless(isinstance(ps2.ext[0].body.block_items[2].type.dim, ID))
eli.bendersky79d5cf62010-10-29 13:33:52 +02001096
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001097
eli.bendersky85d2e732011-05-20 19:47:26 +03001098class TestCParser_whole_code(TestCParser_base):
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001099 """ Testing of parsing whole chunks of code.
1100
1101 Since I don't want to rely on the structure of ASTs too
1102 much, most of these tests are implemented with visitors.
1103 """
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001104 # A simple helper visitor that lists the values of all the
1105 # Constant nodes it sees.
1106 #
1107 class ConstantVisitor(NodeVisitor):
1108 def __init__(self):
1109 self.values = []
1110
1111 def visit_Constant(self, node):
1112 self.values.append(node.value)
1113
1114 # This visitor counts the amount of references to the ID
1115 # with the name provided to it in the constructor.
1116 #
1117 class IDNameCounter(NodeVisitor):
1118 def __init__(self, name):
1119 self.name = name
1120 self.nrefs = 0
1121
1122 def visit_ID(self, node):
1123 if node.name == self.name:
1124 self.nrefs += 1
1125
1126 # Counts the amount of nodes of a given class
1127 #
1128 class NodeKlassCounter(NodeVisitor):
1129 def __init__(self, node_klass):
1130 self.klass = node_klass
1131 self.n = 0
1132
1133 def generic_visit(self, node):
1134 if node.__class__ == self.klass:
1135 self.n += 1
1136
1137 NodeVisitor.generic_visit(self, node)
1138
1139 def assert_all_Constants(self, code, constants):
1140 """ Asserts that the list of all Constant values (by
1141 'preorder' appearance) in the chunk of code is as
1142 given.
1143 """
eli.benderskyed890492010-06-25 08:25:55 +03001144 if isinstance(code, str):
1145 parsed = self.parse(code)
1146 else:
1147 parsed = code
1148
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001149 cv = self.ConstantVisitor()
1150 cv.visit(parsed)
1151 self.assertEqual(cv.values, constants)
1152
1153 def assert_num_ID_refs(self, code, name, num):
1154 """ Asserts the number of references to the ID with
1155 the given name.
1156 """
1157 if isinstance(code, str):
1158 parsed = self.parse(code)
1159 else:
1160 parsed = code
1161
1162 iv = self.IDNameCounter(name)
1163 iv.visit(parsed)
1164 self.assertEqual(iv.nrefs, num)
1165
1166 def assert_num_klass_nodes(self, code, klass, num):
1167 """ Asserts the amount of klass nodes in the code.
1168 """
1169 if isinstance(code, str):
1170 parsed = self.parse(code)
1171 else:
1172 parsed = code
1173
1174 cv = self.NodeKlassCounter(klass)
1175 cv.visit(parsed)
1176 self.assertEqual(cv.n, num)
1177
1178 def test_expressions(self):
1179 e1 = '''int k = (r + 10.0) >> 6 + 8 << (3 & 0x14);'''
1180 self.assert_all_Constants(e1, ['10.0', '6', '8', '3', '0x14'])
1181
1182 e2 = r'''char n = '\n', *prefix = "st_";'''
1183 self.assert_all_Constants(e2, [r"'\n'", '"st_"'])
1184
1185 def test_statements(self):
1186 s1 = r'''
1187 void foo(){
1188 if (sp == 1)
1189 if (optind >= argc ||
1190 argv[optind][0] != '-' || argv[optind][1] == '\0')
1191 return -1;
1192 else if (strcmp(argv[optind], "--") == 0) {
1193 optind++;
1194 return -1;
1195 }
1196 }
1197 '''
1198
1199 self.assert_all_Constants(s1,
1200 ['1', '0', r"'-'", '1', r"'\0'", '1', r'"--"', '0', '1'])
1201
1202 ps1 = self.parse(s1)
1203 self.assert_num_ID_refs(ps1, 'argv', 3)
1204 self.assert_num_ID_refs(ps1, 'optind', 5)
1205
1206 self.assert_num_klass_nodes(ps1, If, 3)
1207 self.assert_num_klass_nodes(ps1, Return, 2)
1208 self.assert_num_klass_nodes(ps1, FuncCall, 1) # strcmp
1209 self.assert_num_klass_nodes(ps1, BinaryOp, 7)
1210
1211 # In the following code, Hash and Node were defined as
1212 # int to pacify the parser that sees they're used as
1213 # types
1214 #
1215 s2 = r'''
1216 typedef int Hash, Node;
1217
1218 void HashDestroy(Hash* hash)
1219 {
1220 unsigned int i;
1221
1222 if (hash == NULL)
1223 return;
1224
1225 for (i = 0; i < hash->table_size; ++i)
1226 {
1227 Node* temp = hash->heads[i];
1228
1229 while (temp != NULL)
1230 {
1231 Node* temp2 = temp;
1232
1233 free(temp->entry->key);
1234 free(temp->entry->value);
1235 free(temp->entry);
1236
1237 temp = temp->next;
1238
1239 free(temp2);
1240 }
1241 }
1242
1243 free(hash->heads);
1244 hash->heads = NULL;
1245
1246 free(hash);
1247 }
1248 '''
1249
1250 ps2 = self.parse(s2)
1251 self.assert_num_klass_nodes(ps2, FuncCall, 6)
1252 self.assert_num_klass_nodes(ps2, FuncDef, 1)
1253 self.assert_num_klass_nodes(ps2, For, 1)
1254 self.assert_num_klass_nodes(ps2, While, 1)
1255 self.assert_num_klass_nodes(ps2, StructRef, 10)
1256
1257 # declarations don't count
1258 self.assert_num_ID_refs(ps2, 'hash', 6)
1259 self.assert_num_ID_refs(ps2, 'i', 4)
eli.benderskyed890492010-06-25 08:25:55 +03001260
1261 s3 = r'''
1262 void x(void) {
1263 int a, b;
1264 if (a < b)
1265 do {
1266 a = 0;
1267 } while (0);
1268 else if (a == b) {
1269 a = 1;
1270 }
1271 }
1272 '''
1273
1274 ps3 = self.parse(s3)
1275 self.assert_num_klass_nodes(ps3, DoWhile, 1)
1276 self.assert_num_ID_refs(ps3, 'a', 4)
1277 self.assert_all_Constants(ps3, ['0', '0', '1'])
eli.bendersky91c0aa32011-10-16 05:50:43 +02001278
1279 def test_empty_statement(self):
1280 s1 = r'''
1281 void foo(void){
1282 ;
1283 return;
1284 }
1285 '''
1286 ps1 = self.parse(s1)
1287 self.assert_num_klass_nodes(ps1, EmptyStatement, 1)
1288 self.assert_num_klass_nodes(ps1, Return, 1)
eli.bendersky145890d2010-10-29 12:02:32 +02001289
1290 def test_for_statement(self):
1291 s2 = r'''
1292 void x(void)
1293 {
1294 int i;
1295 for (i = 0; i < 5; ++i) {
1296 x = 50;
1297 }
1298 }
1299 '''
1300 ps2 = self.parse(s2)
1301 self.assert_num_klass_nodes(ps2, For, 1)
1302 # here there are 3 refs to 'i' since the declaration doesn't count as
1303 # a ref in the visitor
1304 #
1305 self.assert_num_ID_refs(ps2, 'i', 3)
eli.benderskyed890492010-06-25 08:25:55 +03001306
eli.bendersky145890d2010-10-29 12:02:32 +02001307 s3 = r'''
1308 void x(void)
1309 {
1310 for (int i = 0; i < 5; ++i) {
1311 x = 50;
1312 }
1313 }
1314 '''
1315 ps3 = self.parse(s3)
eli.bendersky145890d2010-10-29 12:02:32 +02001316 self.assert_num_klass_nodes(ps3, For, 1)
1317 # here there are 2 refs to 'i' since the declaration doesn't count as
1318 # a ref in the visitor
1319 #
1320 self.assert_num_ID_refs(ps3, 'i', 2)
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001321
Eli Benderskyd0973782012-01-19 08:09:33 +02001322 def _open_c_file(self, name):
1323 """ Find a c file by name, taking into account the current dir can be
1324 in a couple of typical places
1325 """
1326 fullnames = [
1327 os.path.join('c_files', name),
1328 os.path.join('tests', 'c_files', name)]
1329 for fullname in fullnames:
1330 if os.path.exists(fullname):
1331 return open(fullname, 'rU')
1332 assert False, "Unreachable"
1333
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001334 def test_whole_file(self):
1335 # See how pycparser handles a whole, real C file.
1336 #
Eli Benderskyd0973782012-01-19 08:09:33 +02001337 code = self._open_c_file('memmgr_with_h.c').read()
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001338 p = self.parse(code)
1339
1340 self.assert_num_klass_nodes(p, FuncDef, 5)
1341
1342 # each FuncDef also has a FuncDecl. 4 declarations
1343 # + 5 definitions, overall 9
1344 self.assert_num_klass_nodes(p, FuncDecl, 9)
1345
1346 self.assert_num_klass_nodes(p, Typedef, 4)
1347
1348 self.assertEqual(p.ext[4].coord.line, 88)
1349 self.assertEqual(p.ext[4].coord.file, "./memmgr.h")
1350
1351 self.assertEqual(p.ext[6].coord.line, 10)
1352 self.assertEqual(p.ext[6].coord.file, "memmgr.c")
1353
1354 def test_whole_file_with_stdio(self):
1355 # Parse a whole file with stdio.h included by cpp
1356 #
Eli Benderskyd0973782012-01-19 08:09:33 +02001357 code = self._open_c_file('cppd_with_stdio_h.c').read()
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001358 p = self.parse(code)
1359
1360 self.failUnless(isinstance(p.ext[0], Typedef))
1361 self.assertEqual(p.ext[0].coord.line, 213)
1362 self.assertEqual(p.ext[0].coord.file, "D:\eli\cpp_stuff\libc_include/stddef.h")
1363
1364 self.failUnless(isinstance(p.ext[-1], FuncDef))
1365 self.assertEqual(p.ext[-1].coord.line, 15)
1366 self.assertEqual(p.ext[-1].coord.file, "example_c_file.c")
1367
1368 self.failUnless(isinstance(p.ext[-8], Typedef))
1369 self.failUnless(isinstance(p.ext[-8].type, TypeDecl))
1370 self.assertEqual(p.ext[-8].name, 'cookie_io_functions_t')
eli.bendersky85d2e732011-05-20 19:47:26 +03001371
1372
1373class TestCParser_typenames(TestCParser_base):
1374 """ Test issues related to the typedef-name problem.
1375 """
1376 def test_innerscope_typedef(self):
1377 # should fail since TT is not a type in bar
1378 s1 = r'''
1379 void foo() {
1380 typedef char TT;
1381 TT x;
1382 }
1383 void bar() {
1384 TT y;
1385 }
1386 '''
1387 self.assertRaises(ParseError, self.parse, s1)
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001388
eli.bendersky85d2e732011-05-20 19:47:26 +03001389 # should succeed since TT is not a type in bar
1390 s2 = r'''
1391 void foo() {
1392 typedef char TT;
1393 TT x;
1394 }
1395 void bar() {
1396 unsigned TT;
1397 }
1398 '''
1399 self.failUnless(isinstance(self.parse(s2), FileAST))
1400
1401
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001402
1403if __name__ == '__main__':
1404 #~ suite = unittest.TestLoader().loadTestsFromNames(
1405 #~ ['test_c_parser.TestCParser_fundamentals.test_typedef'])
1406
1407 #~ suite = unittest.TestLoader().loadTestsFromNames(
1408 #~ ['test_c_parser.TestCParser_whole_code.test_whole_file_with_stdio'])
1409
1410 #~ suite = unittest.TestLoader().loadTestsFromTestCase(
1411 #~ TestCParser_whole_code)
1412
1413 #~ unittest.TextTestRunner(verbosity=2).run(suite)
1414 unittest.main()