#!/usr/bin/env python

import os
import io
import unittest
from pycparser import c_parser
from pycparser.c_ast import *

ParseError = c_parser.ParseError

_c_parser = c_parser.CParser()


def expand_decl(decl):
    """Converts the declaration into a nested list."""
    typ = type(decl)

    if typ == TypeDecl:
        return ["TypeDecl", expand_decl(decl.type)]
    elif typ == IdentifierType:
        return ["IdentifierType", decl.names]
    elif typ == ID:
        return ["ID", decl.name]
    elif typ in [Struct, Union]:
        decls = [expand_decl(d) for d in decl.decls or []]
        return [typ.__name__, decl.name, decls]
    elif typ == Enum:
        if decl.values is None:
            values = None
        else:
            assert isinstance(decl.values, EnumeratorList)
            values = [enum.name for enum in decl.values.enumerators]
        return ["Enum", decl.name, values]
    elif typ == Alignas:
        return ["Alignas", expand_init(decl.alignment)]
    elif typ == StaticAssert:
        if decl.message:
            return ["StaticAssert", decl.cond.value, decl.message.value]
        else:
            return ["StaticAssert", decl.cond.value]
    else:
        nested = expand_decl(decl.type)

        if typ == Decl:
            r = ["Decl"]
            if decl.quals:
                r.append(decl.quals)
            if decl.align:
                r.append(expand_decl(decl.align[0]))
            r.extend([decl.name, nested])
            return r
        elif typ == Typename:  # for function parameters
            if decl.quals:
                return ["Typename", decl.quals, nested]
            else:
                return ["Typename", nested]
        elif typ == ArrayDecl:
            dimval = decl.dim.value if decl.dim else ""
            return ["ArrayDecl", dimval, decl.dim_quals, nested]
        elif typ == PtrDecl:
            if decl.quals:
                return ["PtrDecl", decl.quals, nested]
            else:
                return ["PtrDecl", nested]
        elif typ == Typedef:
            return ["Typedef", decl.name, nested]
        elif typ == FuncDecl:
            if decl.args:
                params = [expand_decl(param) for param in decl.args.params]
            else:
                params = []
            return ["FuncDecl", params, nested]


def expand_init(init):
    """Converts an initialization into a nested list"""
    typ = type(init)

    if typ == NamedInitializer:
        des = [expand_init(dp) for dp in init.name]
        return (des, expand_init(init.expr))
    elif typ in (InitList, ExprList):
        return [expand_init(expr) for expr in init.exprs]
    elif typ == Constant:
        return ["Constant", init.type, init.value]
    elif typ == ID:
        return ["ID", init.name]
    elif typ == Decl:
        return ["Decl", init.name]
    elif typ == UnaryOp:
        return ["UnaryOp", init.op, expand_decl(init.expr)]
    elif typ == BinaryOp:
        return ["BinaryOp", expand_init(init.left), init.op, expand_init(init.right)]
    elif typ == Compound:
        blocks = []
        if init.block_items:
            blocks = [expand_init(i) for i in init.block_items]
        return ["Compound", blocks]
    elif typ == Typename:
        return expand_decl(init)
    else:
        # Fallback to type name
        return [typ.__name__]


class TestCParser_base(unittest.TestCase):
    def parse(self, txt, filename=""):
        return self.cparser.parse(txt, filename)

    def setUp(self):
        self.cparser = _c_parser

    def assert_coord(self, node, line, column=None, file=None):
        self.assertEqual(node.coord.line, line)
        if column is not None:
            self.assertEqual(node.coord.column, column)
        if file:
            self.assertEqual(node.coord.file, file)


class TestCParser_fundamentals(TestCParser_base):
    def get_decl(self, txt, index=0):
        """Given a source and an index returns the expanded
        declaration at that index.

        FileAST holds a list of 'external declarations'.
        index is the offset of the desired declaration in that
        list.
        """
        t = self.parse(txt).ext[index]
        return expand_decl(t)

    def get_decl_init(self, txt, index=0):
        """Returns the expanded initializer of the declaration
        at index.
        """
        t = self.parse(txt).ext[index]
        return expand_init(t.init)

    def test_FileAST(self):
        t = self.parse("int a; char c;")
        self.assertIsInstance(t, FileAST)
        self.assertEqual(len(t.ext), 2)

        # empty file
        t2 = self.parse("")
        self.assertIsInstance(t2, FileAST)
        self.assertEqual(len(t2.ext), 0)

    def test_empty_toplevel_decl(self):
        code = "int foo;;"
        t = self.parse(code)
        self.assertIsInstance(t, FileAST)
        self.assertEqual(len(t.ext), 1)
        self.assertEqual(
            self.get_decl(code),
            ["Decl", "foo", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )

    def test_initial_semi(self):
        t = self.parse(";")
        self.assertEqual(len(t.ext), 0)
        t = self.parse(";int foo;")
        self.assertEqual(len(t.ext), 1)
        self.assertEqual(
            expand_decl(t.ext[0]),
            ["Decl", "foo", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )

    def test_coords(self):
        """Tests the "coordinates" of parsed elements - file
        name, line and column numbers, with modification
        inserted by #line directives.
        """
        self.assert_coord(self.parse("int a;").ext[0], 1, 5)

        t1 = """
        int a;
        int b;\n\n
        int c;
        """
        f1 = self.parse(t1, filename="test.c")
        self.assert_coord(f1.ext[0], 2, 13, "test.c")
        self.assert_coord(f1.ext[1], 3, 13, "test.c")
        self.assert_coord(f1.ext[2], 6, 13, "test.c")

        t1_1 = """
        int main() {
            k = p;
            printf("%d", b);
            return 0;
        }"""
        f1_1 = self.parse(t1_1, filename="test.c")
        self.assert_coord(f1_1.ext[0].body.block_items[0], 3, 13, "test.c")
        self.assert_coord(f1_1.ext[0].body.block_items[1], 4, 13, "test.c")

        t1_2 = """
        int main () {
            int p = (int) k;
        }"""
        f1_2 = self.parse(t1_2, filename="test.c")
        # make sure that the Cast has a coord (issue 23)
        self.assert_coord(f1_2.ext[0].body.block_items[0].init, 3, 21, file="test.c")

        t2 = """
        #line 99
        int c;
        """
        self.assert_coord(self.parse(t2).ext[0], 99, 13)

        t3 = """
        int dsf;
        char p;
        #line 3000 "in.h"
        char d;
        """
        f3 = self.parse(t3, filename="test.c")
        self.assert_coord(f3.ext[0], 2, 13, "test.c")
        self.assert_coord(f3.ext[1], 3, 14, "test.c")
        self.assert_coord(f3.ext[2], 3000, 14, "in.h")

        t4 = """
        #line 20 "restore.h"
        int maydler(char);

        #line 30 "includes/daween.ph"
        long j, k;

        #line 50000
        char* ro;
        """
        f4 = self.parse(t4, filename="myb.c")
        self.assert_coord(f4.ext[0], 20, 13, "restore.h")
        self.assert_coord(f4.ext[1], 30, 14, "includes/daween.ph")
        self.assert_coord(f4.ext[2], 30, 17, "includes/daween.ph")
        self.assert_coord(f4.ext[3], 50000, 13, "includes/daween.ph")

        t5 = """
        int
        #line 99
        c;
        """
        self.assert_coord(self.parse(t5).ext[0], 99, 9)

        # coord for ellipsis
        t6 = """
        int foo(int j,
                ...) {
        }"""
        self.assert_coord(self.parse(t6).ext[0].decl.type.args.params[1], 3, 17)

    def test_forloop_coord(self):
        t = """\
        void foo() {
            for(int z=0; z<4;
                z++){}
        }
        """
        s = self.parse(t, filename="f.c")
        forloop = s.ext[0].body.block_items[0]
        self.assert_coord(forloop.init, 2, 13, "f.c")
        self.assert_coord(forloop.cond, 2, 26, "f.c")
        self.assert_coord(forloop.next, 3, 17, "f.c")

    def test_simple_decls(self):
        self.assertEqual(
            self.get_decl("int a;"),
            ["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )

        self.assertEqual(
            self.get_decl("unsigned int a;"),
            ["Decl", "a", ["TypeDecl", ["IdentifierType", ["unsigned", "int"]]]],
        )

        self.assertEqual(
            self.get_decl("_Bool a;"),
            ["Decl", "a", ["TypeDecl", ["IdentifierType", ["_Bool"]]]],
        )

        self.assertEqual(
            self.get_decl("float _Complex fcc;"),
            ["Decl", "fcc", ["TypeDecl", ["IdentifierType", ["float", "_Complex"]]]],
        )

        self.assertEqual(
            self.get_decl("char* string;"),
            ["Decl", "string", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]]],
        )

        self.assertEqual(
            self.get_decl("long ar[15];"),
            [
                "Decl",
                "ar",
                ["ArrayDecl", "15", [], ["TypeDecl", ["IdentifierType", ["long"]]]],
            ],
        )

        self.assertEqual(
            self.get_decl("long long ar[15];"),
            [
                "Decl",
                "ar",
                [
                    "ArrayDecl",
                    "15",
                    [],
                    ["TypeDecl", ["IdentifierType", ["long", "long"]]],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("unsigned ar[];"),
            [
                "Decl",
                "ar",
                ["ArrayDecl", "", [], ["TypeDecl", ["IdentifierType", ["unsigned"]]]],
            ],
        )

        self.assertEqual(
            self.get_decl("int strlen(char* s);"),
            [
                "Decl",
                "strlen",
                [
                    "FuncDecl",
                    [
                        [
                            "Decl",
                            "s",
                            ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("int strcmp(char* s1, char* s2);"),
            [
                "Decl",
                "strcmp",
                [
                    "FuncDecl",
                    [
                        [
                            "Decl",
                            "s1",
                            ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                        ],
                        [
                            "Decl",
                            "s2",
                            ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                        ],
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

        # function return values and parameters may not have type information
        self.assertEqual(
            self.get_decl("extern foobar(foo, bar);"),
            [
                "Decl",
                "foobar",
                [
                    "FuncDecl",
                    [["ID", "foo"], ["ID", "bar"]],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

    def test_int128(self):
        self.assertEqual(
            self.get_decl("__int128 a;"),
            ["Decl", "a", ["TypeDecl", ["IdentifierType", ["__int128"]]]],
        )

    def test_nested_decls(self):  # the fun begins
        self.assertEqual(
            self.get_decl("char** ar2D;"),
            [
                "Decl",
                "ar2D",
                ["PtrDecl", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]]],
            ],
        )

        self.assertEqual(
            self.get_decl("int (*a)[1][2];"),
            [
                "Decl",
                "a",
                [
                    "PtrDecl",
                    [
                        "ArrayDecl",
                        "1",
                        [],
                        [
                            "ArrayDecl",
                            "2",
                            [],
                            ["TypeDecl", ["IdentifierType", ["int"]]],
                        ],
                    ],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("int *a[1][2];"),
            [
                "Decl",
                "a",
                [
                    "ArrayDecl",
                    "1",
                    [],
                    [
                        "ArrayDecl",
                        "2",
                        [],
                        ["PtrDecl", ["TypeDecl", ["IdentifierType", ["int"]]]],
                    ],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("char* const* p;"),
            [
                "Decl",
                "p",
                [
                    "PtrDecl",
                    ["PtrDecl", ["const"], ["TypeDecl", ["IdentifierType", ["char"]]]],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("const char* const* p;"),
            [
                "Decl",
                ["const"],
                "p",
                [
                    "PtrDecl",
                    ["PtrDecl", ["const"], ["TypeDecl", ["IdentifierType", ["char"]]]],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("char* * const p;"),
            [
                "Decl",
                "p",
                [
                    "PtrDecl",
                    ["const"],
                    ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("char ***ar3D[40];"),
            [
                "Decl",
                "ar3D",
                [
                    "ArrayDecl",
                    "40",
                    [],
                    [
                        "PtrDecl",
                        [
                            "PtrDecl",
                            ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                        ],
                    ],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("char (***ar3D)[40];"),
            [
                "Decl",
                "ar3D",
                [
                    "PtrDecl",
                    [
                        "PtrDecl",
                        [
                            "PtrDecl",
                            [
                                "ArrayDecl",
                                "40",
                                [],
                                ["TypeDecl", ["IdentifierType", ["char"]]],
                            ],
                        ],
                    ],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("int (*const*const x)(char, int);"),
            [
                "Decl",
                "x",
                [
                    "PtrDecl",
                    ["const"],
                    [
                        "PtrDecl",
                        ["const"],
                        [
                            "FuncDecl",
                            [
                                [
                                    "Typename",
                                    ["TypeDecl", ["IdentifierType", ["char"]]],
                                ],
                                ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]],
                            ],
                            ["TypeDecl", ["IdentifierType", ["int"]]],
                        ],
                    ],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("int (*x[4])(char, int);"),
            [
                "Decl",
                "x",
                [
                    "ArrayDecl",
                    "4",
                    [],
                    [
                        "PtrDecl",
                        [
                            "FuncDecl",
                            [
                                [
                                    "Typename",
                                    ["TypeDecl", ["IdentifierType", ["char"]]],
                                ],
                                ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]],
                            ],
                            ["TypeDecl", ["IdentifierType", ["int"]]],
                        ],
                    ],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("char *(*(**foo [][8])())[];"),
            [
                "Decl",
                "foo",
                [
                    "ArrayDecl",
                    "",
                    [],
                    [
                        "ArrayDecl",
                        "8",
                        [],
                        [
                            "PtrDecl",
                            [
                                "PtrDecl",
                                [
                                    "FuncDecl",
                                    [],
                                    [
                                        "PtrDecl",
                                        [
                                            "ArrayDecl",
                                            "",
                                            [],
                                            [
                                                "PtrDecl",
                                                [
                                                    "TypeDecl",
                                                    ["IdentifierType", ["char"]],
                                                ],
                                            ],
                                        ],
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        )

        # explore named and unnamed function pointer parameters,
        # with and without qualifiers

        # unnamed w/o quals
        self.assertEqual(
            self.get_decl("int (*k)(int);"),
            [
                "Decl",
                "k",
                [
                    "PtrDecl",
                    [
                        "FuncDecl",
                        [["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]]],
                        ["TypeDecl", ["IdentifierType", ["int"]]],
                    ],
                ],
            ],
        )

        # unnamed w/ quals
        self.assertEqual(
            self.get_decl("int (*k)(const int);"),
            [
                "Decl",
                "k",
                [
                    "PtrDecl",
                    [
                        "FuncDecl",
                        [
                            [
                                "Typename",
                                ["const"],
                                ["TypeDecl", ["IdentifierType", ["int"]]],
                            ]
                        ],
                        ["TypeDecl", ["IdentifierType", ["int"]]],
                    ],
                ],
            ],
        )

        # named w/o quals
        self.assertEqual(
            self.get_decl("int (*k)(int q);"),
            [
                "Decl",
                "k",
                [
                    "PtrDecl",
                    [
                        "FuncDecl",
                        [["Decl", "q", ["TypeDecl", ["IdentifierType", ["int"]]]]],
                        ["TypeDecl", ["IdentifierType", ["int"]]],
                    ],
                ],
            ],
        )

        # named w/ quals
        self.assertEqual(
            self.get_decl("int (*k)(const volatile int q);"),
            [
                "Decl",
                "k",
                [
                    "PtrDecl",
                    [
                        "FuncDecl",
                        [
                            [
                                "Decl",
                                ["const", "volatile"],
                                "q",
                                ["TypeDecl", ["IdentifierType", ["int"]]],
                            ]
                        ],
                        ["TypeDecl", ["IdentifierType", ["int"]]],
                    ],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("int (*k)(_Atomic volatile int q);"),
            [
                "Decl",
                "k",
                [
                    "PtrDecl",
                    [
                        "FuncDecl",
                        [
                            [
                                "Decl",
                                ["_Atomic", "volatile"],
                                "q",
                                ["TypeDecl", ["IdentifierType", ["int"]]],
                            ]
                        ],
                        ["TypeDecl", ["IdentifierType", ["int"]]],
                    ],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("int (*k)(const volatile int* q);"),
            [
                "Decl",
                "k",
                [
                    "PtrDecl",
                    [
                        "FuncDecl",
                        [
                            [
                                "Decl",
                                ["const", "volatile"],
                                "q",
                                ["PtrDecl", ["TypeDecl", ["IdentifierType", ["int"]]]],
                            ]
                        ],
                        ["TypeDecl", ["IdentifierType", ["int"]]],
                    ],
                ],
            ],
        )

        # restrict qualifier
        self.assertEqual(
            self.get_decl("int (*k)(restrict int* q);"),
            [
                "Decl",
                "k",
                [
                    "PtrDecl",
                    [
                        "FuncDecl",
                        [
                            [
                                "Decl",
                                ["restrict"],
                                "q",
                                ["PtrDecl", ["TypeDecl", ["IdentifierType", ["int"]]]],
                            ]
                        ],
                        ["TypeDecl", ["IdentifierType", ["int"]]],
                    ],
                ],
            ],
        )

    def test_func_decls_with_array_dim_qualifiers(self):
        # named function parameter
        self.assertEqual(
            self.get_decl("int zz(int p[static 10]);"),
            [
                "Decl",
                "zz",
                [
                    "FuncDecl",
                    [
                        [
                            "Decl",
                            "p",
                            [
                                "ArrayDecl",
                                "10",
                                ["static"],
                                ["TypeDecl", ["IdentifierType", ["int"]]],
                            ],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )
        # anonymous function parameter
        self.assertEqual(
            self.get_decl("int zz(int [static 10]);"),
            [
                "Decl",
                "zz",
                [
                    "FuncDecl",
                    [
                        [
                            "Typename",
                            [
                                "ArrayDecl",
                                "10",
                                ["static"],
                                ["TypeDecl", ["IdentifierType", ["int"]]],
                            ],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )
        self.assertEqual(
            self.get_decl("int zz(int [static const restrict 10]);"),
            [
                "Decl",
                "zz",
                [
                    "FuncDecl",
                    [
                        [
                            "Typename",
                            [
                                "ArrayDecl",
                                "10",
                                ["static", "const", "restrict"],
                                ["TypeDecl", ["IdentifierType", ["int"]]],
                            ],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("int zz(int p[const 10]);"),
            [
                "Decl",
                "zz",
                [
                    "FuncDecl",
                    [
                        [
                            "Decl",
                            "p",
                            [
                                "ArrayDecl",
                                "10",
                                ["const"],
                                ["TypeDecl", ["IdentifierType", ["int"]]],
                            ],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("int zz(int p[restrict][5]);"),
            [
                "Decl",
                "zz",
                [
                    "FuncDecl",
                    [
                        [
                            "Decl",
                            "p",
                            [
                                "ArrayDecl",
                                "",
                                ["restrict"],
                                [
                                    "ArrayDecl",
                                    "5",
                                    [],
                                    ["TypeDecl", ["IdentifierType", ["int"]]],
                                ],
                            ],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("int zz(int p[const restrict static 10][5]);"),
            [
                "Decl",
                "zz",
                [
                    "FuncDecl",
                    [
                        [
                            "Decl",
                            "p",
                            [
                                "ArrayDecl",
                                "10",
                                ["const", "restrict", "static"],
                                [
                                    "ArrayDecl",
                                    "5",
                                    [],
                                    ["TypeDecl", ["IdentifierType", ["int"]]],
                                ],
                            ],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

        # unnamed function parameter
        self.assertEqual(
            self.get_decl("int zz(int [const 10]);"),
            [
                "Decl",
                "zz",
                [
                    "FuncDecl",
                    [
                        [
                            "Typename",
                            [
                                "ArrayDecl",
                                "10",
                                ["const"],
                                ["TypeDecl", ["IdentifierType", ["int"]]],
                            ],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("int zz(int [restrict][5]);"),
            [
                "Decl",
                "zz",
                [
                    "FuncDecl",
                    [
                        [
                            "Typename",
                            [
                                "ArrayDecl",
                                "",
                                ["restrict"],
                                [
                                    "ArrayDecl",
                                    "5",
                                    [],
                                    ["TypeDecl", ["IdentifierType", ["int"]]],
                                ],
                            ],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

        self.assertEqual(
            self.get_decl("int zz(int [const restrict volatile 10][5]);"),
            [
                "Decl",
                "zz",
                [
                    "FuncDecl",
                    [
                        [
                            "Typename",
                            [
                                "ArrayDecl",
                                "10",
                                ["const", "restrict", "volatile"],
                                [
                                    "ArrayDecl",
                                    "5",
                                    [],
                                    ["TypeDecl", ["IdentifierType", ["int"]]],
                                ],
                            ],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

    def test_qualifiers_storage_specifiers(self):
        def assert_qs(txt, index, quals, storage):
            d = self.parse(txt).ext[index]
            self.assertEqual(d.quals, quals)
            self.assertEqual(d.storage, storage)

        assert_qs("extern int p;", 0, [], ["extern"])
        assert_qs("_Thread_local int p;", 0, [], ["_Thread_local"])
        assert_qs("const long p = 6;", 0, ["const"], [])
        assert_qs("_Atomic int p;", 0, ["_Atomic"], [])
        assert_qs("_Atomic restrict int* p;", 0, ["_Atomic", "restrict"], [])

        d1 = "static const int p, q, r;"
        for i in range(3):
            assert_qs(d1, i, ["const"], ["static"])

        d2 = "static char * const p;"
        assert_qs(d2, 0, [], ["static"])
        pdecl = self.parse(d2).ext[0].type
        self.assertIsInstance(pdecl, PtrDecl)
        self.assertEqual(pdecl.quals, ["const"])

    def test_atomic_specifier(self):
        self.assertEqual(
            self.get_decl("_Atomic(int) ai;"),
            ["Decl", ["_Atomic"], "ai", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )

        self.assertEqual(
            self.get_decl("_Atomic(int*) ai;"),
            [
                "Decl",
                "ai",
                ["PtrDecl", ["_Atomic"], ["TypeDecl", ["IdentifierType", ["int"]]]],
            ],
        )

        self.assertEqual(
            self.get_decl("_Atomic(_Atomic(int)*) aai;"),
            [
                "Decl",
                ["_Atomic"],
                "aai",
                ["PtrDecl", ["_Atomic"], ["TypeDecl", ["IdentifierType", ["int"]]]],
            ],
        )

        # Multiple declarations with _Atomic(...)
        s = "_Atomic(int) foo, bar;"
        self.assertEqual(
            self.get_decl(s, 0),
            ["Decl", ["_Atomic"], "foo", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )
        self.assertEqual(
            self.get_decl(s, 1),
            ["Decl", ["_Atomic"], "bar", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )

        # typedefs with _Atomic specifiers.
        s = "typedef _Atomic(int) atomic_int;"
        self.assertEqual(
            self.get_decl(s, 0),
            ["Typedef", "atomic_int", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )

        s = "typedef _Atomic(_Atomic(_Atomic(int (*)(void)) *) *) t;"
        self.assertEqual(
            self.get_decl(s, 0),
            [
                "Typedef",
                "t",
                [
                    "PtrDecl",
                    ["_Atomic"],
                    [
                        "PtrDecl",
                        ["_Atomic"],
                        [
                            "PtrDecl",
                            ["_Atomic"],
                            [
                                "FuncDecl",
                                [
                                    [
                                        "Typename",
                                        ["TypeDecl", ["IdentifierType", ["void"]]],
                                    ]
                                ],
                                ["TypeDecl", ["IdentifierType", ["int"]]],
                            ],
                        ],
                    ],
                ],
            ],
        )

    def test_sizeof(self):
        e = """
            void foo()
            {
                int a = sizeof k;
                int b = sizeof(int);
                int c = sizeof(int**);;

                char* p = "just to make sure this parses w/o error...";
                int d = sizeof(int());
            }
        """
        compound = self.parse(e).ext[0].body

        s1 = compound.block_items[0].init
        self.assertIsInstance(s1, UnaryOp)
        self.assertEqual(s1.op, "sizeof")
        self.assertIsInstance(s1.expr, ID)
        self.assertEqual(s1.expr.name, "k")

        s2 = compound.block_items[1].init
        self.assertEqual(
            expand_decl(s2.expr),
            ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )

        s3 = compound.block_items[2].init
        self.assertEqual(
            expand_decl(s3.expr),
            [
                "Typename",
                ["PtrDecl", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["int"]]]]],
            ],
        )

    def test_alignof(self):
        r = self.parse("int a = _Alignof(int);")
        self.assertEqual(
            expand_decl(r.ext[0]),
            ["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )
        self.assertEqual(
            expand_init(r.ext[0].init),
            [
                "UnaryOp",
                "_Alignof",
                ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]],
            ],
        )

        self.assertEqual(
            expand_decl(self.parse("_Alignas(_Alignof(int)) char a;").ext[0]),
            [
                "Decl",
                [
                    "Alignas",
                    [
                        "UnaryOp",
                        "_Alignof",
                        ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]],
                    ],
                ],
                "a",
                ["TypeDecl", ["IdentifierType", ["char"]]],
            ],
        )

        self.assertEqual(
            expand_decl(self.parse("_Alignas(4) char a;").ext[0]),
            [
                "Decl",
                ["Alignas", ["Constant", "int", "4"]],
                "a",
                ["TypeDecl", ["IdentifierType", ["char"]]],
            ],
        )

        self.assertEqual(
            expand_decl(self.parse("_Alignas(int) char a;").ext[0]),
            [
                "Decl",
                ["Alignas", ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]]],
                "a",
                ["TypeDecl", ["IdentifierType", ["char"]]],
            ],
        )

    def test_alignas_with_typedef_in_struct(self):
        # Issue #472
        s = """
            typedef int test_int;
            typedef struct {
                _Alignas(int) test_int a1;
            } test_struct;
        """
        ast = self.parse(s)
        field = ast.ext[1].type.type.decls[0]
        self.assertEqual(field.name, "a1")
        self.assertTrue(hasattr(field, "align") and field.align is not None)
        self.assertEqual(
            expand_decl(field),
            [
                "Decl",
                ["Alignas", ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]]],
                "a1",
                ["TypeDecl", ["IdentifierType", ["test_int"]]],
            ],
        )

    def test_offsetof(self):
        def expand_ref(n):
            if isinstance(n, StructRef):
                return ["StructRef", expand_ref(n.name), expand_ref(n.field)]
            elif isinstance(n, ArrayRef):
                return ["ArrayRef", expand_ref(n.name), expand_ref(n.subscript)]
            elif isinstance(n, ID):
                return ["ID", n.name]
            elif isinstance(n, Constant):
                return ["Constant", n.type, n.value]
            else:
                raise TypeError("Unexpected type " + n.__class__.__name__)

        e = """
            void foo() {
                int a = offsetof(struct S, p);
                a.b = offsetof(struct sockaddr, sp) + strlen(bar);
                int a = offsetof(struct S, p.q.r);
                int a = offsetof(struct S, p[5].q[4][5]);
            }
            """
        compound = self.parse(e).ext[0].body
        s1 = compound.block_items[0].init
        self.assertIsInstance(s1, FuncCall)
        self.assertIsInstance(s1.name, ID)
        self.assertEqual(s1.name.name, "offsetof")
        self.assertIsInstance(s1.args.exprs[0], Typename)
        self.assertIsInstance(s1.args.exprs[1], ID)
        s3 = compound.block_items[2].init
        self.assertIsInstance(s3.args.exprs[1], StructRef)
        self.assertEqual(
            expand_ref(s3.args.exprs[1]),
            ["StructRef", ["StructRef", ["ID", "p"], ["ID", "q"]], ["ID", "r"]],
        )
        s4 = compound.block_items[3].init
        self.assertIsInstance(s4.args.exprs[1], ArrayRef)
        self.assertEqual(
            expand_ref(s4.args.exprs[1]),
            [
                "ArrayRef",
                [
                    "ArrayRef",
                    [
                        "StructRef",
                        ["ArrayRef", ["ID", "p"], ["Constant", "int", "5"]],
                        ["ID", "q"],
                    ],
                    ["Constant", "int", "4"],
                ],
                ["Constant", "int", "5"],
            ],
        )

    def test_compound_statement(self):
        e = """
            void foo() {
            }
            """
        compound = self.parse(e).ext[0].body
        self.assertIsInstance(compound, Compound)
        self.assert_coord(compound, 2)

    # The C99 compound literal feature
    #
    def test_compound_literals(self):
        ps1 = self.parse(r"""
            void foo() {
                p = (long long){k};
                tc = (struct jk){.a = {1, 2}, .b[0] = t};
            }""")

        compound = ps1.ext[0].body.block_items[0].rvalue
        self.assertEqual(
            expand_decl(compound.type),
            ["Typename", ["TypeDecl", ["IdentifierType", ["long", "long"]]]],
        )
        self.assertEqual(expand_init(compound.init), [["ID", "k"]])

        compound = ps1.ext[0].body.block_items[1].rvalue
        self.assertEqual(
            expand_decl(compound.type), ["Typename", ["TypeDecl", ["Struct", "jk", []]]]
        )
        self.assertEqual(
            expand_init(compound.init),
            [
                ([["ID", "a"]], [["Constant", "int", "1"], ["Constant", "int", "2"]]),
                ([["ID", "b"], ["Constant", "int", "0"]], ["ID", "t"]),
            ],
        )

    def test_parenthesized_compounds(self):
        e = self.parse(r"""
        void foo() {
            int a;
            ({});
            ({ 1; });
            ({ 1; 2; });
            int b = ({ 1; });
            int c, d = ({ int x = 1; x + 2; });
            a = ({ int x = 1; 2 * x; });
        }""")
        body = e.ext[0].body.block_items

        self.assertIsInstance(body[1], Compound)
        self.assertEqual(body[1].block_items, None)

        self.assertIsInstance(body[2], Compound)
        self.assertEqual(len(body[2].block_items), 1)
        self.assertIsInstance(body[2].block_items[0], Constant)

        self.assertIsInstance(body[3], Compound)
        self.assertEqual(len(body[3].block_items), 2)
        self.assertIsInstance(body[3].block_items[0], Constant)
        self.assertIsInstance(body[3].block_items[1], Constant)

        self.assertIsInstance(body[4], Decl)
        self.assertEqual(
            expand_init(body[4].init), ["Compound", [["Constant", "int", "1"]]]
        )

        self.assertIsInstance(body[5], Decl)
        self.assertEqual(body[5].init, None)

        self.assertIsInstance(body[6], Decl)
        self.assertEqual(
            expand_init(body[6].init),
            [
                "Compound",
                [
                    ["Decl", "x"],
                    ["BinaryOp", ["ID", "x"], "+", ["Constant", "int", "2"]],
                ],
            ],
        )

        self.assertIsInstance(body[7], Assignment)
        self.assertIsInstance(body[7].rvalue, Compound)
        self.assertEqual(
            expand_init(body[7].rvalue),
            [
                "Compound",
                [
                    ["Decl", "x"],
                    ["BinaryOp", ["Constant", "int", "2"], "*", ["ID", "x"]],
                ],
            ],
        )

    def test_enums(self):
        e1 = "enum mycolor op;"
        e1_type = self.parse(e1).ext[0].type.type

        self.assertIsInstance(e1_type, Enum)
        self.assertEqual(e1_type.name, "mycolor")
        self.assertEqual(e1_type.values, None)

        e2 = "enum mysize {large=20, small, medium} shoes;"
        e2_type = self.parse(e2).ext[0].type.type

        self.assertIsInstance(e2_type, Enum)
        self.assertEqual(e2_type.name, "mysize")

        e2_elist = e2_type.values
        self.assertIsInstance(e2_elist, EnumeratorList)

        for e2_eval in e2_elist.enumerators:
            self.assertIsInstance(e2_eval, Enumerator)

        self.assertEqual(e2_elist.enumerators[0].name, "large")
        self.assertEqual(e2_elist.enumerators[0].value.value, "20")
        self.assertEqual(e2_elist.enumerators[2].name, "medium")
        self.assertEqual(e2_elist.enumerators[2].value, None)

        # enum with trailing comma (C99 feature)
        e3 = """
            enum
            {
                red,
                blue,
                green,
            } color;
            """

        e3_type = self.parse(e3).ext[0].type.type
        self.assertIsInstance(e3_type, Enum)
        e3_elist = e3_type.values
        self.assertIsInstance(e3_elist, EnumeratorList)

        for e3_eval in e3_elist.enumerators:
            self.assertIsInstance(e3_eval, Enumerator)

        self.assertEqual(e3_elist.enumerators[0].name, "red")
        self.assertEqual(e3_elist.enumerators[0].value, None)
        self.assertEqual(e3_elist.enumerators[1].name, "blue")
        self.assertEqual(e3_elist.enumerators[2].name, "green")

    def test_typedef(self):
        # without typedef, error
        s1 = """
            node k;
        """
        self.assertRaises(ParseError, self.parse, s1)

        # now with typedef, works
        s2 = """
            typedef void* node;
            node k;
        """
        ps2 = self.parse(s2)
        self.assertEqual(
            expand_decl(ps2.ext[0]),
            [
                "Typedef",
                "node",
                ["PtrDecl", ["TypeDecl", ["IdentifierType", ["void"]]]],
            ],
        )

        self.assertEqual(
            expand_decl(ps2.ext[1]),
            ["Decl", "k", ["TypeDecl", ["IdentifierType", ["node"]]]],
        )

        s3 = """
            typedef int T;
            typedef T *pT;

            pT aa, bb;
        """
        ps3 = self.parse(s3)
        self.assertEqual(
            expand_decl(ps3.ext[3]),
            ["Decl", "bb", ["TypeDecl", ["IdentifierType", ["pT"]]]],
        )

        s4 = """
            typedef char* __builtin_va_list;
            typedef __builtin_va_list __gnuc_va_list;
        """
        ps4 = self.parse(s4)
        self.assertEqual(
            expand_decl(ps4.ext[1]),
            [
                "Typedef",
                "__gnuc_va_list",
                ["TypeDecl", ["IdentifierType", ["__builtin_va_list"]]],
            ],
        )

        s5 = """typedef struct tagHash Hash;"""
        ps5 = self.parse(s5)
        self.assertEqual(
            expand_decl(ps5.ext[0]),
            ["Typedef", "Hash", ["TypeDecl", ["Struct", "tagHash", []]]],
        )

        s6 = """typedef int (* const * const T)(void);"""
        ps6 = self.parse(s6)
        self.assertEqual(
            expand_decl(ps6.ext[0]),
            [
                "Typedef",
                "T",
                [
                    "PtrDecl",
                    ["const"],
                    [
                        "PtrDecl",
                        ["const"],
                        [
                            "FuncDecl",
                            [["Typename", ["TypeDecl", ["IdentifierType", ["void"]]]]],
                            ["TypeDecl", ["IdentifierType", ["int"]]],
                        ],
                    ],
                ],
            ],
        )

    def test_struct_union(self):
        s1 = """
            struct {
                int id;
                char* name;
            } joe;
            """

        self.assertEqual(
            expand_decl(self.parse(s1).ext[0]),
            [
                "Decl",
                "joe",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        None,
                        [
                            ["Decl", "id", ["TypeDecl", ["IdentifierType", ["int"]]]],
                            [
                                "Decl",
                                "name",
                                ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                            ],
                        ],
                    ],
                ],
            ],
        )

        s2 = """
            struct node p;
        """
        self.assertEqual(
            expand_decl(self.parse(s2).ext[0]),
            ["Decl", "p", ["TypeDecl", ["Struct", "node", []]]],
        )

        s21 = """
            union pri ra;
        """
        self.assertEqual(
            expand_decl(self.parse(s21).ext[0]),
            ["Decl", "ra", ["TypeDecl", ["Union", "pri", []]]],
        )

        s3 = """
            struct node* p;
        """
        self.assertEqual(
            expand_decl(self.parse(s3).ext[0]),
            ["Decl", "p", ["PtrDecl", ["TypeDecl", ["Struct", "node", []]]]],
        )

        s4 = """
            struct node;
        """
        self.assertEqual(
            expand_decl(self.parse(s4).ext[0]), ["Decl", None, ["Struct", "node", []]]
        )

        s5 = """
            union
            {
                struct
                {
                    int type;
                } n;

                struct
                {
                    int type;
                    int intnode;
                } ni;
            } u;
        """
        self.assertEqual(
            expand_decl(self.parse(s5).ext[0]),
            [
                "Decl",
                "u",
                [
                    "TypeDecl",
                    [
                        "Union",
                        None,
                        [
                            [
                                "Decl",
                                "n",
                                [
                                    "TypeDecl",
                                    [
                                        "Struct",
                                        None,
                                        [
                                            [
                                                "Decl",
                                                "type",
                                                [
                                                    "TypeDecl",
                                                    ["IdentifierType", ["int"]],
                                                ],
                                            ]
                                        ],
                                    ],
                                ],
                            ],
                            [
                                "Decl",
                                "ni",
                                [
                                    "TypeDecl",
                                    [
                                        "Struct",
                                        None,
                                        [
                                            [
                                                "Decl",
                                                "type",
                                                [
                                                    "TypeDecl",
                                                    ["IdentifierType", ["int"]],
                                                ],
                                            ],
                                            [
                                                "Decl",
                                                "intnode",
                                                [
                                                    "TypeDecl",
                                                    ["IdentifierType", ["int"]],
                                                ],
                                            ],
                                        ],
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        )

        s6 = """
            typedef struct foo_tag
            {
                void* data;
            } foo, *pfoo;
        """
        s6_ast = self.parse(s6)

        self.assertEqual(
            expand_decl(s6_ast.ext[0]),
            [
                "Typedef",
                "foo",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        "foo_tag",
                        [
                            [
                                "Decl",
                                "data",
                                ["PtrDecl", ["TypeDecl", ["IdentifierType", ["void"]]]],
                            ]
                        ],
                    ],
                ],
            ],
        )

        self.assertEqual(
            expand_decl(s6_ast.ext[1]),
            [
                "Typedef",
                "pfoo",
                [
                    "PtrDecl",
                    [
                        "TypeDecl",
                        [
                            "Struct",
                            "foo_tag",
                            [
                                [
                                    "Decl",
                                    "data",
                                    [
                                        "PtrDecl",
                                        ["TypeDecl", ["IdentifierType", ["void"]]],
                                    ],
                                ]
                            ],
                        ],
                    ],
                ],
            ],
        )

        s7 = r"""
            struct _on_exit_args {
                void *  _fnargs[32];
                void *  _dso_handle[32];

                long _fntypes;
                #line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h"

                long _is_cxa;
            };
        """

        s7_ast = self.parse(s7, filename="test.c")
        self.assert_coord(s7_ast.ext[0].type.decls[2], 6, 22, "test.c")
        self.assert_coord(
            s7_ast.ext[0].type.decls[3],
            78,
            22,
            r"D:\eli\cpp_stuff\libc_include/sys/reent.h",
        )

        s8 = """
            typedef enum tagReturnCode {SUCCESS, FAIL} ReturnCode;

            typedef struct tagEntry
            {
                char* key;
                char* value;
            } Entry;


            typedef struct tagNode
            {
                Entry* entry;

                struct tagNode* next;
            } Node;

            typedef struct tagHash
            {
                unsigned int table_size;

                Node** heads;

            } Hash;
        """
        s8_ast = self.parse(s8)
        self.assertEqual(
            expand_decl(s8_ast.ext[3]),
            [
                "Typedef",
                "Hash",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        "tagHash",
                        [
                            [
                                "Decl",
                                "table_size",
                                ["TypeDecl", ["IdentifierType", ["unsigned", "int"]]],
                            ],
                            [
                                "Decl",
                                "heads",
                                [
                                    "PtrDecl",
                                    [
                                        "PtrDecl",
                                        ["TypeDecl", ["IdentifierType", ["Node"]]],
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        )

    def test_struct_enum(self):
        s1 = """
            struct Foo {
                enum Bar { A = 1 };
            };
        """
        self.assertEqual(
            expand_decl(self.parse(s1).ext[0]),
            ["Decl", None, ["Struct", "Foo", [["Decl", None, ["Enum", "Bar", ["A"]]]]]],
        )
        s2 = """
            struct Foo {
                enum Bar { A = 1, B, C } bar;
                enum Baz { D = A } baz;
            } foo;
        """
        self.assertEqual(
            expand_decl(self.parse(s2).ext[0]),
            [
                "Decl",
                "foo",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        "Foo",
                        [
                            [
                                "Decl",
                                "bar",
                                ["TypeDecl", ["Enum", "Bar", ["A", "B", "C"]]],
                            ],
                            ["Decl", "baz", ["TypeDecl", ["Enum", "Baz", ["D"]]]],
                        ],
                    ],
                ],
            ],
        )

    def test_struct_with_extra_semis_inside(self):
        s1 = """
            struct {
                int a;;
            } foo;
        """
        s1_ast = self.parse(s1)
        self.assertEqual(
            expand_decl(s1_ast.ext[0]),
            [
                "Decl",
                "foo",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        None,
                        [["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]]],
                    ],
                ],
            ],
        )

        s2 = """
            struct {
                int a;;;;
                float b, c;
                ;;
                char d;
            } foo;
        """
        s2_ast = self.parse(s2)
        self.assertEqual(
            expand_decl(s2_ast.ext[0]),
            [
                "Decl",
                "foo",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        None,
                        [
                            ["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]],
                            ["Decl", "b", ["TypeDecl", ["IdentifierType", ["float"]]]],
                            ["Decl", "c", ["TypeDecl", ["IdentifierType", ["float"]]]],
                            ["Decl", "d", ["TypeDecl", ["IdentifierType", ["char"]]]],
                        ],
                    ],
                ],
            ],
        )

    def test_struct_with_initial_semi(self):
        s1 = """
            struct {
                ;int a;
            } foo;
        """
        s1_ast = self.parse(s1)
        self.assertEqual(
            expand_decl(s1_ast.ext[0]),
            [
                "Decl",
                "foo",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        None,
                        [["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]]],
                    ],
                ],
            ],
        )

    def test_anonymous_struct_union(self):
        s1 = """
            union
            {
                union
                {
                    int i;
                    long l;
                };

                struct
                {
                    int type;
                    int intnode;
                };
            } u;
        """

        self.assertEqual(
            expand_decl(self.parse(s1).ext[0]),
            [
                "Decl",
                "u",
                [
                    "TypeDecl",
                    [
                        "Union",
                        None,
                        [
                            [
                                "Decl",
                                None,
                                [
                                    "Union",
                                    None,
                                    [
                                        [
                                            "Decl",
                                            "i",
                                            ["TypeDecl", ["IdentifierType", ["int"]]],
                                        ],
                                        [
                                            "Decl",
                                            "l",
                                            ["TypeDecl", ["IdentifierType", ["long"]]],
                                        ],
                                    ],
                                ],
                            ],
                            [
                                "Decl",
                                None,
                                [
                                    "Struct",
                                    None,
                                    [
                                        [
                                            "Decl",
                                            "type",
                                            ["TypeDecl", ["IdentifierType", ["int"]]],
                                        ],
                                        [
                                            "Decl",
                                            "intnode",
                                            ["TypeDecl", ["IdentifierType", ["int"]]],
                                        ],
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        )

        s2 = """
            struct
            {
                int i;
                union
                {
                    int id;
                    char* name;
                };
                float f;
            } joe;
            """

        self.assertEqual(
            expand_decl(self.parse(s2).ext[0]),
            [
                "Decl",
                "joe",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        None,
                        [
                            ["Decl", "i", ["TypeDecl", ["IdentifierType", ["int"]]]],
                            [
                                "Decl",
                                None,
                                [
                                    "Union",
                                    None,
                                    [
                                        [
                                            "Decl",
                                            "id",
                                            ["TypeDecl", ["IdentifierType", ["int"]]],
                                        ],
                                        [
                                            "Decl",
                                            "name",
                                            [
                                                "PtrDecl",
                                                [
                                                    "TypeDecl",
                                                    ["IdentifierType", ["char"]],
                                                ],
                                            ],
                                        ],
                                    ],
                                ],
                            ],
                            ["Decl", "f", ["TypeDecl", ["IdentifierType", ["float"]]]],
                        ],
                    ],
                ],
            ],
        )

        # ISO/IEC 9899:201x Committee Draft 2010-11-16, N1539
        # section 6.7.2.1, par. 19, example 1
        s3 = """
            struct v {
                union {
                    struct { int i, j; };
                    struct { long k, l; } w;
                };
                int m;
            } v1;
            """

        self.assertEqual(
            expand_decl(self.parse(s3).ext[0]),
            [
                "Decl",
                "v1",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        "v",
                        [
                            [
                                "Decl",
                                None,
                                [
                                    "Union",
                                    None,
                                    [
                                        [
                                            "Decl",
                                            None,
                                            [
                                                "Struct",
                                                None,
                                                [
                                                    [
                                                        "Decl",
                                                        "i",
                                                        [
                                                            "TypeDecl",
                                                            ["IdentifierType", ["int"]],
                                                        ],
                                                    ],
                                                    [
                                                        "Decl",
                                                        "j",
                                                        [
                                                            "TypeDecl",
                                                            ["IdentifierType", ["int"]],
                                                        ],
                                                    ],
                                                ],
                                            ],
                                        ],
                                        [
                                            "Decl",
                                            "w",
                                            [
                                                "TypeDecl",
                                                [
                                                    "Struct",
                                                    None,
                                                    [
                                                        [
                                                            "Decl",
                                                            "k",
                                                            [
                                                                "TypeDecl",
                                                                [
                                                                    "IdentifierType",
                                                                    ["long"],
                                                                ],
                                                            ],
                                                        ],
                                                        [
                                                            "Decl",
                                                            "l",
                                                            [
                                                                "TypeDecl",
                                                                [
                                                                    "IdentifierType",
                                                                    ["long"],
                                                                ],
                                                            ],
                                                        ],
                                                    ],
                                                ],
                                            ],
                                        ],
                                    ],
                                ],
                            ],
                            ["Decl", "m", ["TypeDecl", ["IdentifierType", ["int"]]]],
                        ],
                    ],
                ],
            ],
        )

        s4 = """
            struct v {
                int i;
                float;
            } v2;"""
        # just make sure this doesn't raise ParseError
        self.parse(s4)

    def test_struct_members_namespace(self):
        """Tests that structure/union member names reside in a separate
        namespace and can be named after existing types.
        """
        s1 = """
                typedef int Name;
                typedef Name NameArray[10];

                struct {
                    Name Name;
                    Name NameArray[3];
                } sye;

                void main(void)
                {
                    sye.Name = 1;
                }
            """

        s1_ast = self.parse(s1)
        self.assertEqual(
            expand_decl(s1_ast.ext[2]),
            [
                "Decl",
                "sye",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        None,
                        [
                            [
                                "Decl",
                                "Name",
                                ["TypeDecl", ["IdentifierType", ["Name"]]],
                            ],
                            [
                                "Decl",
                                "NameArray",
                                [
                                    "ArrayDecl",
                                    "3",
                                    [],
                                    ["TypeDecl", ["IdentifierType", ["Name"]]],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        )
        self.assertEqual(s1_ast.ext[3].body.block_items[0].lvalue.field.name, "Name")

    def test_struct_bitfields(self):
        # a struct with two bitfields, one unnamed
        s1 = """
            struct {
                int k:6;
                int :2;
            } joe;
            """

        parsed_struct = self.parse(s1).ext[0]

        # We can see here the name of the decl for the unnamed bitfield is
        # None, but expand_decl doesn't show bitfield widths
        # ...
        self.assertEqual(
            expand_decl(parsed_struct),
            [
                "Decl",
                "joe",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        None,
                        [
                            ["Decl", "k", ["TypeDecl", ["IdentifierType", ["int"]]]],
                            ["Decl", None, ["TypeDecl", ["IdentifierType", ["int"]]]],
                        ],
                    ],
                ],
            ],
        )

        # ...
        # so we test them manually
        self.assertEqual(parsed_struct.type.type.decls[0].bitsize.value, "6")
        self.assertEqual(parsed_struct.type.type.decls[1].bitsize.value, "2")

    def test_struct_empty(self):
        """
        Tests that parsing an empty struct works.

        Empty structs do NOT follow C99 (See 6.2.5-20 of the C99 standard).
        This is nevertheless supported by some compilers (clang, gcc),
        especially when using FORTIFY code.
        Some compilers (visual) will fail to compile with an error.
        """
        # an empty struct. This is NOT C99 compliant
        s1 = """
                 struct foo { };
             """

        parsed_struct = self.parse(s1).ext[0]
        self.assertEqual(
            expand_decl(parsed_struct), ["Decl", None, ["Struct", "foo", []]]
        )

        s2 = """struct { } foo;"""
        parsed_struct = self.parse(s2).ext[0]
        self.assertEqual(
            expand_decl(parsed_struct),
            ["Decl", "foo", ["TypeDecl", ["Struct", None, []]]],
        )

        s3 = """union { } foo;"""
        parsed_struct = self.parse(s3).ext[0]
        self.assertEqual(
            expand_decl(parsed_struct),
            ["Decl", "foo", ["TypeDecl", ["Union", None, []]]],
        )

    def test_tags_namespace(self):
        """Tests that the tags of structs/unions/enums reside in a separate namespace and
        can be named after existing types.
        """
        s1 = """
                typedef int tagEntry;

                struct tagEntry
                {
                    char* key;
                    char* value;
                } Entry;
            """

        s1_ast = self.parse(s1)
        self.assertEqual(
            expand_decl(s1_ast.ext[1]),
            [
                "Decl",
                "Entry",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        "tagEntry",
                        [
                            [
                                "Decl",
                                "key",
                                ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                            ],
                            [
                                "Decl",
                                "value",
                                ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                            ],
                        ],
                    ],
                ],
            ],
        )

        s2 = """
                struct tagEntry;

                typedef struct tagEntry tagEntry;

                struct tagEntry
                {
                    char* key;
                    char* value;
                } Entry;
            """

        s2_ast = self.parse(s2)
        self.assertEqual(
            expand_decl(s2_ast.ext[2]),
            [
                "Decl",
                "Entry",
                [
                    "TypeDecl",
                    [
                        "Struct",
                        "tagEntry",
                        [
                            [
                                "Decl",
                                "key",
                                ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                            ],
                            [
                                "Decl",
                                "value",
                                ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                            ],
                        ],
                    ],
                ],
            ],
        )

        s3 = """
                typedef int mytag;

                enum mytag {ABC, CDE};
                enum mytag joe;
            """

        s3_type = self.parse(s3).ext[1].type

        self.assertIsInstance(s3_type, Enum)
        self.assertEqual(s3_type.name, "mytag")

    def test_multi_decls(self):
        d1 = "int a, b;"

        self.assertEqual(
            self.get_decl(d1, 0),
            ["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )
        self.assertEqual(
            self.get_decl(d1, 1),
            ["Decl", "b", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )

        d2 = "char* p, notp, ar[4];"
        self.assertEqual(
            self.get_decl(d2, 0),
            ["Decl", "p", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]]],
        )
        self.assertEqual(
            self.get_decl(d2, 1),
            ["Decl", "notp", ["TypeDecl", ["IdentifierType", ["char"]]]],
        )
        self.assertEqual(
            self.get_decl(d2, 2),
            [
                "Decl",
                "ar",
                ["ArrayDecl", "4", [], ["TypeDecl", ["IdentifierType", ["char"]]]],
            ],
        )

    def test_invalid_multiple_types_error(self):
        bad = ["int enum {ab, cd} fubr;", "enum kid char brbr;"]

        for b in bad:
            self.assertRaises(ParseError, self.parse, b)

    def test_invalid_typedef_storage_qual_error(self):
        """Tests that using typedef as a storage qualifier is correctly flagged
        as an error.
        """
        bad = "typedef const int foo(int a) { return 0; }"
        self.assertRaises(ParseError, self.parse, bad)

    def test_duplicate_typedef(self):
        """Tests that redeclarations of existing types are parsed correctly.
        This is non-standard, but allowed by many compilers.
        """
        d1 = """
            typedef int numbertype;
            typedef int numbertype;
        """

        self.assertEqual(
            self.get_decl(d1, 0),
            ["Typedef", "numbertype", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )
        self.assertEqual(
            self.get_decl(d1, 1),
            ["Typedef", "numbertype", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )

        d2 = """
            typedef int (*funcptr)(int x);
            typedef int (*funcptr)(int x);
        """
        self.assertEqual(
            self.get_decl(d2, 0),
            [
                "Typedef",
                "funcptr",
                [
                    "PtrDecl",
                    [
                        "FuncDecl",
                        [["Decl", "x", ["TypeDecl", ["IdentifierType", ["int"]]]]],
                        ["TypeDecl", ["IdentifierType", ["int"]]],
                    ],
                ],
            ],
        )
        self.assertEqual(
            self.get_decl(d2, 1),
            [
                "Typedef",
                "funcptr",
                [
                    "PtrDecl",
                    [
                        "FuncDecl",
                        [["Decl", "x", ["TypeDecl", ["IdentifierType", ["int"]]]]],
                        ["TypeDecl", ["IdentifierType", ["int"]]],
                    ],
                ],
            ],
        )

        d3 = """
            typedef int numberarray[5];
            typedef int numberarray[5];
        """
        self.assertEqual(
            self.get_decl(d3, 0),
            [
                "Typedef",
                "numberarray",
                ["ArrayDecl", "5", [], ["TypeDecl", ["IdentifierType", ["int"]]]],
            ],
        )
        self.assertEqual(
            self.get_decl(d3, 1),
            [
                "Typedef",
                "numberarray",
                ["ArrayDecl", "5", [], ["TypeDecl", ["IdentifierType", ["int"]]]],
            ],
        )

    def test_decl_inits(self):
        d1 = "int a = 16;"
        # ~ self.parse(d1).show()
        self.assertEqual(
            self.get_decl(d1), ["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]]
        )
        self.assertEqual(self.get_decl_init(d1), ["Constant", "int", "16"])

        d1_1 = "float f = 0xEF.56p1;"
        self.assertEqual(self.get_decl_init(d1_1), ["Constant", "double", "0xEF.56p1"])

        d1_2 = "int bitmask = 0b1001010;"
        self.assertEqual(self.get_decl_init(d1_2), ["Constant", "int", "0b1001010"])

        d2 = "long ar[] = {7, 8, 9};"
        self.assertEqual(
            self.get_decl(d2),
            [
                "Decl",
                "ar",
                ["ArrayDecl", "", [], ["TypeDecl", ["IdentifierType", ["long"]]]],
            ],
        )
        self.assertEqual(
            self.get_decl_init(d2),
            [
                ["Constant", "int", "7"],
                ["Constant", "int", "8"],
                ["Constant", "int", "9"],
            ],
        )

        d21 = "long ar[4] = {};"
        self.assertEqual(self.get_decl_init(d21), [])

        d3 = "char p = j;"
        self.assertEqual(
            self.get_decl(d3), ["Decl", "p", ["TypeDecl", ["IdentifierType", ["char"]]]]
        )
        self.assertEqual(self.get_decl_init(d3), ["ID", "j"])

        d4 = "char x = 'c', *p = {0, 1, 2, {4, 5}, 6};"
        self.assertEqual(
            self.get_decl(d4, 0),
            ["Decl", "x", ["TypeDecl", ["IdentifierType", ["char"]]]],
        )
        self.assertEqual(self.get_decl_init(d4, 0), ["Constant", "char", "'c'"])
        self.assertEqual(
            self.get_decl(d4, 1),
            ["Decl", "p", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]]],
        )

        self.assertEqual(
            self.get_decl_init(d4, 1),
            [
                ["Constant", "int", "0"],
                ["Constant", "int", "1"],
                ["Constant", "int", "2"],
                [["Constant", "int", "4"], ["Constant", "int", "5"]],
                ["Constant", "int", "6"],
            ],
        )

        d5 = "float d = 1.0;"
        self.assertEqual(self.get_decl_init(d5), ["Constant", "double", "1.0"])

        d51 = "float ld = 1.0l;"
        self.assertEqual(self.get_decl_init(d51), ["Constant", "long double", "1.0l"])

        d52 = "float ld = 1.0L;"
        self.assertEqual(self.get_decl_init(d52), ["Constant", "long double", "1.0L"])

        d53 = "float ld = 1.0f;"
        self.assertEqual(self.get_decl_init(d53), ["Constant", "float", "1.0f"])

        d54 = "float ld = 1.0F;"
        self.assertEqual(self.get_decl_init(d54), ["Constant", "float", "1.0F"])

        d55 = "float ld = 0xDE.38p0;"
        self.assertEqual(self.get_decl_init(d55), ["Constant", "double", "0xDE.38p0"])

        d56 = "float ld = 0xDE.38p0f;"
        self.assertEqual(self.get_decl_init(d56), ["Constant", "float", "0xDE.38p0f"])

        d57 = "float ld = 0xDE.38p0F;"
        self.assertEqual(self.get_decl_init(d57), ["Constant", "float", "0xDE.38p0F"])

        d58 = "float ld = 0xDE.38p0l;"
        self.assertEqual(
            self.get_decl_init(d58), ["Constant", "long double", "0xDE.38p0l"]
        )

        d59 = "float ld = 0xDE.38p0L;"
        self.assertEqual(
            self.get_decl_init(d59), ["Constant", "long double", "0xDE.38p0L"]
        )

        d6 = "int i = 1;"
        self.assertEqual(self.get_decl_init(d6), ["Constant", "int", "1"])

        d61 = "long int li = 1l;"
        self.assertEqual(self.get_decl_init(d61), ["Constant", "long int", "1l"])

        d62 = "unsigned int ui = 1u;"
        self.assertEqual(self.get_decl_init(d62), ["Constant", "unsigned int", "1u"])

        d63 = "unsigned long long int ulli = 1LLU;"
        self.assertEqual(
            self.get_decl_init(d63), ["Constant", "unsigned long long int", "1LLU"]
        )

    def test_decl_named_inits(self):
        d1 = "int a = {.k = 16};"
        self.assertEqual(
            self.get_decl_init(d1), [([["ID", "k"]], ["Constant", "int", "16"])]
        )

        d2 = "int a = { [0].a = {1}, [1].a[0] = 2 };"
        self.assertEqual(
            self.get_decl_init(d2),
            [
                ([["Constant", "int", "0"], ["ID", "a"]], [["Constant", "int", "1"]]),
                (
                    [["Constant", "int", "1"], ["ID", "a"], ["Constant", "int", "0"]],
                    ["Constant", "int", "2"],
                ),
            ],
        )

        d3 = "int a = { .a = 1, .c = 3, 4, .b = 5};"
        self.assertEqual(
            self.get_decl_init(d3),
            [
                ([["ID", "a"]], ["Constant", "int", "1"]),
                ([["ID", "c"]], ["Constant", "int", "3"]),
                ["Constant", "int", "4"],
                ([["ID", "b"]], ["Constant", "int", "5"]),
            ],
        )

    def test_function_definitions(self):
        def parse_fdef(str):
            return self.parse(str).ext[0]

        def fdef_decl(fdef):
            return expand_decl(fdef.decl)

        f1 = parse_fdef("""
        int factorial(int p)
        {
            return 3;
        }
        """)

        self.assertEqual(
            fdef_decl(f1),
            [
                "Decl",
                "factorial",
                [
                    "FuncDecl",
                    [["Decl", "p", ["TypeDecl", ["IdentifierType", ["int"]]]]],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

        self.assertEqual(type(f1.body.block_items[0]), Return)

        f2 = parse_fdef("""
        char* zzz(int p, char* c)
        {
            int a;
            char b;

            a = b + 2;
            return 3;
        }
        """)

        self.assertEqual(
            fdef_decl(f2),
            [
                "Decl",
                "zzz",
                [
                    "FuncDecl",
                    [
                        ["Decl", "p", ["TypeDecl", ["IdentifierType", ["int"]]]],
                        [
                            "Decl",
                            "c",
                            ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                        ],
                    ],
                    ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                ],
            ],
        )

        self.assertEqual(
            list(map(type, f2.body.block_items)), [Decl, Decl, Assignment, Return]
        )

        f3 = parse_fdef("""
        char* zzz(p, c)
        long p, *c;
        {
            int a;
            char b;

            a = b + 2;
            return 3;
        }
        """)

        self.assertEqual(
            fdef_decl(f3),
            [
                "Decl",
                "zzz",
                [
                    "FuncDecl",
                    [["ID", "p"], ["ID", "c"]],
                    ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]],
                ],
            ],
        )

        self.assertEqual(
            list(map(type, f3.body.block_items)), [Decl, Decl, Assignment, Return]
        )

        self.assertEqual(
            expand_decl(f3.param_decls[0]),
            ["Decl", "p", ["TypeDecl", ["IdentifierType", ["long"]]]],
        )
        self.assertEqual(
            expand_decl(f3.param_decls[1]),
            ["Decl", "c", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["long"]]]]],
        )

        # function return values and parameters may not have type information
        f4 = parse_fdef("""
        que(p)
        {
            return 3;
        }
        """)

        self.assertEqual(
            fdef_decl(f4),
            [
                "Decl",
                "que",
                ["FuncDecl", [["ID", "p"]], ["TypeDecl", ["IdentifierType", ["int"]]]],
            ],
        )

    def test_static_assert(self):
        f1 = self.parse("""
        _Static_assert(1, "123");
        int factorial(int p)
        {
            _Static_assert(2, "456");
            _Static_assert(3);
        }
        """)

        self.assertEqual(expand_decl(f1.ext[0]), ["StaticAssert", "1", '"123"'])
        self.assertEqual(
            expand_decl(f1.ext[1].body.block_items[0]), ["StaticAssert", "2", '"456"']
        )
        self.assertEqual(
            expand_decl(f1.ext[1].body.block_items[2]), ["StaticAssert", "3"]
        )

    def test_unified_string_literals(self):
        # simple string, for reference
        d1 = self.get_decl_init('char* s = "hello";')
        self.assertEqual(d1, ["Constant", "string", '"hello"'])

        d2 = self.get_decl_init('char* s = "hello" " world";')
        self.assertEqual(d2, ["Constant", "string", '"hello world"'])

        # the test case from issue 6
        d3 = self.parse(r"""
            int main() {
                fprintf(stderr,
                "Wrong Params?\n"
                "Usage:\n"
                "%s <binary_file_path>\n",
                argv[0]
                );
            }
        """)

        self.assertEqual(
            d3.ext[0].body.block_items[0].args.exprs[1].value,
            r'"Wrong Params?\nUsage:\n%s <binary_file_path>\n"',
        )

        d4 = self.get_decl_init('char* s = "" "foobar";')
        self.assertEqual(d4, ["Constant", "string", '"foobar"'])

        d5 = self.get_decl_init(r'char* s = "foo\"" "bar";')
        self.assertEqual(d5, ["Constant", "string", r'"foo\"bar"'])

        # This is not correct based on the the C spec, but testing it here to
        # see the behavior in action. Will have to fix this
        # for https://github.com/eliben/pycparser/issues/392
        #
        # The spec says in section 6.4.5 that "escape sequences are converted
        # into single members of the execution character set just prior to
        # adjacent string literal concatenation".
        d6 = self.get_decl_init(r'char* s = "\1" "23";')
        self.assertEqual(d6, ["Constant", "string", r'"\123"'])

    def test_unified_wstring_literals(self):
        d1 = self.get_decl_init('char* s = L"hello" L"world";')
        self.assertEqual(d1, ["Constant", "string", 'L"helloworld"'])

        d2 = self.get_decl_init('char* s = L"hello " L"world" L" and I";')
        self.assertEqual(d2, ["Constant", "string", 'L"hello world and I"'])

    def test_inline_specifier(self):
        ps2 = self.parse("static inline void inlinefoo(void);")
        self.assertEqual(ps2.ext[0].funcspec, ["inline"])

    def test_noreturn_specifier(self):
        ps2 = self.parse("static _Noreturn void noreturnfoo(void);")
        self.assertEqual(ps2.ext[0].funcspec, ["_Noreturn"])

    # variable length array
    def test_vla(self):
        ps2 = self.parse(r"""
            int main() {
                int size;
                int var[size = 5];

                int var2[*];
            }
        """)
        self.assertIsInstance(ps2.ext[0].body.block_items[1].type.dim, Assignment)
        self.assertIsInstance(ps2.ext[0].body.block_items[2].type.dim, ID)

    def test_pragma(self):
        s1 = r"""
            #pragma bar
            void main() {
                #pragma foo
                for(;;) {}
                #pragma baz
                {
                    int i = 0;
                }
                #pragma
            }
            struct s {
            #pragma baz
            } s;
            _Pragma("other \"string\"")
            """
        s1_ast = self.parse(s1)
        self.assertIsInstance(s1_ast.ext[0], Pragma)
        self.assertEqual(s1_ast.ext[0].string, "bar")
        self.assertEqual(s1_ast.ext[0].coord.line, 2)

        self.assertIsInstance(s1_ast.ext[1].body.block_items[0], Pragma)
        self.assertEqual(s1_ast.ext[1].body.block_items[0].string, "foo")
        self.assertEqual(s1_ast.ext[1].body.block_items[0].coord.line, 4)

        self.assertIsInstance(s1_ast.ext[1].body.block_items[2], Pragma)
        self.assertEqual(s1_ast.ext[1].body.block_items[2].string, "baz")
        self.assertEqual(s1_ast.ext[1].body.block_items[2].coord.line, 6)

        self.assertIsInstance(s1_ast.ext[1].body.block_items[4], Pragma)
        self.assertEqual(s1_ast.ext[1].body.block_items[4].string, "")
        self.assertEqual(s1_ast.ext[1].body.block_items[4].coord.line, 10)

        self.assertIsInstance(s1_ast.ext[2].type.type.decls[0], Pragma)
        self.assertEqual(s1_ast.ext[2].type.type.decls[0].string, "baz")
        self.assertEqual(s1_ast.ext[2].type.type.decls[0].coord.line, 13)

        self.assertIsInstance(s1_ast.ext[3], Pragma)
        self.assertEqual(s1_ast.ext[3].string.value, r'"other \"string\""')
        self.assertEqual(s1_ast.ext[3].coord.line, 15)

    def test_pragmacomp_or_statement(self):
        s1 = r"""
            void main() {
                int sum = 0;
                for (int i; i < 3; i++)
                    #pragma omp critical
                    sum += 1;

                while(sum < 10)
                    #pragma omp critical
                    sum += 1;

                mylabel:
                    #pragma foo
                    sum += 10;

                if (sum > 10)
                    #pragma bar
                    #pragma baz
                    sum = 10;

                switch (sum)
                case 10:
                    #pragma foo
                    sum = 20;
            }
        """
        s1_ast = self.parse(s1)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[1], For)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[1].stmt, Compound)
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[1].stmt.block_items[0], Pragma
        )
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[1].stmt.block_items[1], Assignment
        )
        self.assertIsInstance(s1_ast.ext[0].body.block_items[2], While)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[2].stmt, Compound)
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[2].stmt.block_items[0], Pragma
        )
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[2].stmt.block_items[1], Assignment
        )
        self.assertIsInstance(s1_ast.ext[0].body.block_items[3], Label)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[3].stmt, Compound)
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[3].stmt.block_items[0], Pragma
        )
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[3].stmt.block_items[1], Assignment
        )
        self.assertIsInstance(s1_ast.ext[0].body.block_items[4], If)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[4].iftrue, Compound)
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[4].iftrue.block_items[0], Pragma
        )
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[4].iftrue.block_items[1], Pragma
        )
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[4].iftrue.block_items[2], Assignment
        )
        self.assertIsInstance(s1_ast.ext[0].body.block_items[5], Switch)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[5].stmt.stmts[0], Compound)
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[5].stmt.stmts[0].block_items[0], Pragma
        )
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[5].stmt.stmts[0].block_items[1], Assignment
        )


class TestCParser_whole_code(TestCParser_base):
    """Testing of parsing whole chunks of code.

    Since I don't want to rely on the structure of ASTs too
    much, most of these tests are implemented with visitors.
    """

    # A simple helper visitor that lists the values of all the
    # Constant nodes it sees.
    #
    class ConstantVisitor(NodeVisitor):
        def __init__(self):
            self.values = []

        def visit_Constant(self, node):
            self.values.append(node.value)

    # This visitor counts the amount of references to the ID
    # with the name provided to it in the constructor.
    #
    class IDNameCounter(NodeVisitor):
        def __init__(self, name):
            self.name = name
            self.nrefs = 0

        def visit_ID(self, node):
            if node.name == self.name:
                self.nrefs += 1

    # Counts the amount of nodes of a given class
    #
    class NodeKlassCounter(NodeVisitor):
        def __init__(self, node_klass):
            self.klass = node_klass
            self.n = 0

        def generic_visit(self, node):
            if node.__class__ == self.klass:
                self.n += 1

            NodeVisitor.generic_visit(self, node)

    def assert_all_Constants(self, code, constants):
        """Asserts that the list of all Constant values (by
        'preorder' appearance) in the chunk of code is as
        given.
        """
        if isinstance(code, str):
            parsed = self.parse(code)
        else:
            parsed = code

        cv = self.ConstantVisitor()
        cv.visit(parsed)
        self.assertEqual(cv.values, constants)

    def assert_num_ID_refs(self, code, name, num):
        """Asserts the number of references to the ID with
        the given name.
        """
        if isinstance(code, str):
            parsed = self.parse(code)
        else:
            parsed = code

        iv = self.IDNameCounter(name)
        iv.visit(parsed)
        self.assertEqual(iv.nrefs, num)

    def assert_num_klass_nodes(self, code, klass, num):
        """Asserts the amount of klass nodes in the code."""
        if isinstance(code, str):
            parsed = self.parse(code)
        else:
            parsed = code

        cv = self.NodeKlassCounter(klass)
        cv.visit(parsed)
        self.assertEqual(cv.n, num)

    def test_expressions(self):
        e1 = """int k = (r + 10.0) >> 6 + 8 << (3 & 0x14);"""
        self.assert_all_Constants(e1, ["10.0", "6", "8", "3", "0x14"])

        e2 = r"""char n = '\n', *prefix = "st_";"""
        self.assert_all_Constants(e2, [r"'\n'", '"st_"'])

        s1 = r"""int main() {
                    int i = 5, j = 6, k = 1;
                    if ((i=j && k == 1) || k > j)
                        printf("Hello, world\n");
                    return 0;
                 }"""
        ps1 = self.parse(s1)
        self.assert_all_Constants(ps1, ["5", "6", "1", "1", '"Hello, world\\n"', "0"])
        self.assert_num_ID_refs(ps1, "i", 1)
        self.assert_num_ID_refs(ps1, "j", 2)

    def test_statements(self):
        s1 = r"""
            void foo(){
            if (sp == 1)
                if (optind >= argc ||
                    argv[optind][0] != '-' || argv[optind][1] == '\0')
                        return -1;
                else if (strcmp(argv[optind], "--") == 0) {
                    optind++;
                    return -1;
                }
            }
        """

        self.assert_all_Constants(
            s1, ["1", "0", r"'-'", "1", r"'\0'", "1", r'"--"', "0", "1"]
        )

        ps1 = self.parse(s1)
        self.assert_num_ID_refs(ps1, "argv", 3)
        self.assert_num_ID_refs(ps1, "optind", 5)

        self.assert_num_klass_nodes(ps1, If, 3)
        self.assert_num_klass_nodes(ps1, Return, 2)
        self.assert_num_klass_nodes(ps1, FuncCall, 1)  # strcmp
        self.assert_num_klass_nodes(ps1, BinaryOp, 7)

        # In the following code, Hash and Node were defined as
        # int to pacify the parser that sees they're used as
        # types
        #
        s2 = r"""
        typedef int Hash, Node;

        void HashDestroy(Hash* hash)
        {
            unsigned int i;

            if (hash == NULL)
                return;

            for (i = 0; i < hash->table_size; ++i)
            {
                Node* temp = hash->heads[i];

                while (temp != NULL)
                {
                    Node* temp2 = temp;

                    free(temp->entry->key);
                    free(temp->entry->value);
                    free(temp->entry);

                    temp = temp->next;

                    free(temp2);
                }
            }

            free(hash->heads);
            hash->heads = NULL;

            free(hash);
        }
        """

        ps2 = self.parse(s2)
        self.assert_num_klass_nodes(ps2, FuncCall, 6)
        self.assert_num_klass_nodes(ps2, FuncDef, 1)
        self.assert_num_klass_nodes(ps2, For, 1)
        self.assert_num_klass_nodes(ps2, While, 1)
        self.assert_num_klass_nodes(ps2, StructRef, 10)

        # declarations don't count
        self.assert_num_ID_refs(ps2, "hash", 6)
        self.assert_num_ID_refs(ps2, "i", 4)

        s3 = r"""
        void x(void) {
          int a, b;
          if (a < b)
            do {
              a = 0;
            } while (0);
          else if (a == b) {
            a = 1;
          }
        }
        """

        ps3 = self.parse(s3)
        self.assert_num_klass_nodes(ps3, DoWhile, 1)
        self.assert_num_ID_refs(ps3, "a", 4)
        self.assert_all_Constants(ps3, ["0", "0", "1"])

    def test_empty_statements(self):
        s1 = r"""
        void foo(void){
            ;
            return;;

            ;
        }
        """
        ps1 = self.parse(s1)
        self.assert_num_klass_nodes(ps1, EmptyStatement, 3)
        self.assert_num_klass_nodes(ps1, Return, 1)
        self.assert_coord(ps1.ext[0].body.block_items[0], 3)
        self.assert_coord(ps1.ext[0].body.block_items[1], 4)
        self.assert_coord(ps1.ext[0].body.block_items[2], 4)
        self.assert_coord(ps1.ext[0].body.block_items[3], 6)

    def test_switch_statement(self):
        def assert_case_node(node, const_value):
            self.assertIsInstance(node, Case)
            self.assertIsInstance(node.expr, Constant)
            self.assertEqual(node.expr.value, const_value)

        def assert_default_node(node):
            self.assertIsInstance(node, Default)

        s1 = r"""
        int foo(void) {
            switch (myvar) {
                case 10:
                    k = 10;
                    p = k + 1;
                    return 10;
                case 20:
                case 30:
                    return 20;
                default:
                    break;
            }
            return 0;
        }
        """
        ps1 = self.parse(s1)
        switch = ps1.ext[0].body.block_items[0]

        block = switch.stmt.block_items
        self.assertEqual(len(block), 4)
        assert_case_node(block[0], "10")
        self.assertEqual(len(block[0].stmts), 3)
        assert_case_node(block[1], "20")
        self.assertEqual(len(block[1].stmts), 0)
        assert_case_node(block[2], "30")
        self.assertEqual(len(block[2].stmts), 1)
        assert_default_node(block[3])

        s2 = r"""
        int foo(void) {
            switch (myvar) {
                default:
                    joe = moe;
                    return 10;
                case 10:
                case 20:
                case 30:
                case 40:
                    break;
            }
            return 0;
        }
        """
        ps2 = self.parse(s2)
        switch = ps2.ext[0].body.block_items[0]

        block = switch.stmt.block_items
        self.assertEqual(len(block), 5)
        assert_default_node(block[0])
        self.assertEqual(len(block[0].stmts), 2)
        assert_case_node(block[1], "10")
        self.assertEqual(len(block[1].stmts), 0)
        assert_case_node(block[2], "20")
        self.assertEqual(len(block[1].stmts), 0)
        assert_case_node(block[3], "30")
        self.assertEqual(len(block[1].stmts), 0)
        assert_case_node(block[4], "40")
        self.assertEqual(len(block[4].stmts), 1)

        s3 = r"""
        int foo(void) {
            switch (myvar) {
            }
            return 0;
        }
        """
        ps3 = self.parse(s3)
        switch = ps3.ext[0].body.block_items[0]

        self.assertEqual(switch.stmt.block_items, [])

    def test_for_statement(self):
        s2 = r"""
        void x(void)
        {
            int i;
            for (i = 0; i < 5; ++i) {
                x = 50;
            }
        }
        """
        ps2 = self.parse(s2)
        self.assert_num_klass_nodes(ps2, For, 1)
        # here there are 3 refs to 'i' since the declaration doesn't count as
        # a ref in the visitor
        #
        self.assert_num_ID_refs(ps2, "i", 3)

        s3 = r"""
        void x(void)
        {
            for (int i = 0; i < 5; ++i) {
                x = 50;
            }
        }
        """
        ps3 = self.parse(s3)
        self.assert_num_klass_nodes(ps3, For, 1)
        # here there are 2 refs to 'i' since the declaration doesn't count as
        # a ref in the visitor
        #
        self.assert_num_ID_refs(ps3, "i", 2)

        s4 = r"""
        void x(void) {
            for (int i = 0;;)
                i;
        }
        """
        ps4 = self.parse(s4)
        self.assert_num_ID_refs(ps4, "i", 1)

    def _open_c_file(self, name):
        """Find a c file by name, taking into account the current dir can be
        in a couple of typical places
        """
        testdir = os.path.dirname(__file__)
        name = os.path.join(testdir, "c_files", name)
        assert os.path.exists(name)
        return io.open(name)

    def test_whole_file(self):
        # See how pycparser handles a whole, real C file.
        #
        with self._open_c_file("memmgr_with_h.c") as f:
            code = f.read()
        p = self.parse(code)

        self.assert_num_klass_nodes(p, FuncDef, 5)

        # each FuncDef also has a FuncDecl. 4 declarations
        # + 5 definitions, overall 9
        self.assert_num_klass_nodes(p, FuncDecl, 9)

        self.assert_num_klass_nodes(p, Typedef, 4)

        self.assertEqual(p.ext[4].coord.line, 88)
        self.assertEqual(p.ext[4].coord.file, "./memmgr.h")

        self.assertEqual(p.ext[6].coord.line, 10)
        self.assertEqual(p.ext[6].coord.file, "memmgr.c")

    def test_whole_file_with_stdio(self):
        # Parse a whole file with stdio.h included by cpp
        #
        with self._open_c_file("cppd_with_stdio_h.c") as f:
            code = f.read()
        p = self.parse(code)

        self.assertIsInstance(p.ext[0], Typedef)
        self.assertEqual(p.ext[0].coord.line, 213)
        self.assertEqual(p.ext[0].coord.file, r"D:\eli\cpp_stuff\libc_include/stddef.h")

        self.assertIsInstance(p.ext[-1], FuncDef)
        self.assertEqual(p.ext[-1].coord.line, 15)
        self.assertEqual(p.ext[-1].coord.file, "example_c_file.c")

        self.assertIsInstance(p.ext[-8], Typedef)
        self.assertIsInstance(p.ext[-8].type, TypeDecl)
        self.assertEqual(p.ext[-8].name, "cookie_io_functions_t")


class TestCParser_typenames(TestCParser_base):
    """Test issues related to the typedef-name problem."""

    def test_innerscope_typedef(self):
        # should fail since TT is not a type in bar
        s1 = r"""
            void foo() {
              typedef char TT;
              TT x;
            }
            void bar() {
              TT y;
            }
            """
        self.assertRaises(ParseError, self.parse, s1)

        # should succeed since TT is not a type in bar
        s2 = r"""
            void foo() {
              typedef char TT;
              TT x;
            }
            void bar() {
                unsigned TT;
            }
            """
        self.assertIsInstance(self.parse(s2), FileAST)

    def test_ambiguous_parameters(self):
        # From ISO/IEC 9899:TC2, 6.7.5.3.11:
        # "If, in a parameter declaration, an identifier can be treated either
        #  as a typedef name or as a parameter name, it shall be taken as a
        #  typedef name."

        # foo takes an int named aa
        # bar takes a function taking a TT
        s1 = r"""
        typedef char TT;
        int foo(int (aa));
        int bar(int (TT));
        """
        s1_ast = self.parse(s1)
        self.assertEqual(
            expand_decl(s1_ast.ext[1].type.args.params[0]),
            ["Decl", "aa", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )
        self.assertEqual(
            expand_decl(s1_ast.ext[2].type.args.params[0]),
            [
                "Typename",
                [
                    "FuncDecl",
                    [["Typename", ["TypeDecl", ["IdentifierType", ["TT"]]]]],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

        # foo takes a function taking a char
        # bar takes a function taking a function taking a char
        s2 = r"""
        typedef char TT;
        int foo(int (aa (char)));
        int bar(int (TT (char)));
        """
        s2_ast = self.parse(s2)
        self.assertEqual(
            expand_decl(s2_ast.ext[1].type.args.params[0]),
            [
                "Decl",
                "aa",
                [
                    "FuncDecl",
                    [["Typename", ["TypeDecl", ["IdentifierType", ["char"]]]]],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )
        self.assertEqual(
            expand_decl(s2_ast.ext[2].type.args.params[0]),
            [
                "Typename",
                [
                    "FuncDecl",
                    [
                        [
                            "Typename",
                            [
                                "FuncDecl",
                                [
                                    [
                                        "Typename",
                                        ["TypeDecl", ["IdentifierType", ["char"]]],
                                    ]
                                ],
                                ["TypeDecl", ["IdentifierType", ["TT"]]],
                            ],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

        # foo takes an int array named aa
        # bar takes a function taking a TT array
        s3 = r"""
        typedef char TT;
        int foo(int (aa[]));
        int bar(int (TT[]));
        """
        s3_ast = self.parse(s3)
        self.assertEqual(
            expand_decl(s3_ast.ext[1].type.args.params[0]),
            [
                "Decl",
                "aa",
                ["ArrayDecl", "", [], ["TypeDecl", ["IdentifierType", ["int"]]]],
            ],
        )
        self.assertEqual(
            expand_decl(s3_ast.ext[2].type.args.params[0]),
            [
                "Typename",
                [
                    "FuncDecl",
                    [
                        [
                            "Typename",
                            [
                                "ArrayDecl",
                                "",
                                [],
                                ["TypeDecl", ["IdentifierType", ["TT"]]],
                            ],
                        ]
                    ],
                    ["TypeDecl", ["IdentifierType", ["int"]]],
                ],
            ],
        )

    def test_innerscope_reuse_typedef_name(self):
        # identifiers can be reused in inner scopes; the original should be
        # restored at the end of the block
        s1 = r"""
            typedef char TT;
            void foo(void) {
              unsigned TT;
              TT = 10;
            }
            TT x = 5;
            """
        s1_ast = self.parse(s1)
        self.assertEqual(
            expand_decl(s1_ast.ext[1].body.block_items[0]),
            ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]],
        )
        self.assertEqual(
            expand_decl(s1_ast.ext[2]),
            ["Decl", "x", ["TypeDecl", ["IdentifierType", ["TT"]]]],
        )

        # this should be recognized even with an initializer
        s2 = r"""
            typedef char TT;
            void foo(void) {
              unsigned TT = 10;
            }
            """
        s2_ast = self.parse(s2)
        self.assertEqual(
            expand_decl(s2_ast.ext[1].body.block_items[0]),
            ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]],
        )

        # before the second local variable, TT is a type; after, it's a
        # variable
        s3 = r"""
            typedef char TT;
            void foo(void) {
              TT tt = sizeof(TT);
              unsigned TT = 10;
            }
            """
        s3_ast = self.parse(s3)
        self.assertEqual(
            expand_decl(s3_ast.ext[1].body.block_items[0]),
            ["Decl", "tt", ["TypeDecl", ["IdentifierType", ["TT"]]]],
        )
        self.assertEqual(
            expand_decl(s3_ast.ext[1].body.block_items[1]),
            ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]],
        )

        # a variable and its type can even share the same name
        s4 = r"""
            typedef char TT;
            void foo(void) {
              TT TT = sizeof(TT);
              unsigned uu = TT * 2;
            }
            """
        s4_ast = self.parse(s4)
        self.assertEqual(
            expand_decl(s4_ast.ext[1].body.block_items[0]),
            ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["TT"]]]],
        )
        self.assertEqual(
            expand_decl(s4_ast.ext[1].body.block_items[1]),
            ["Decl", "uu", ["TypeDecl", ["IdentifierType", ["unsigned"]]]],
        )

        # ensure an error is raised if a type, redeclared as a variable, is
        # used as a type
        s5 = r"""
            typedef char TT;
            void foo(void) {
              unsigned TT = 10;
              TT erroneous = 20;
            }
            """
        self.assertRaises(ParseError, self.parse, s5)

        # reusing a type name should work with multiple declarators
        s6 = r"""
            typedef char TT;
            void foo(void) {
              unsigned TT, uu;
            }
            """
        s6_ast = self.parse(s6)
        items = s6_ast.ext[1].body.block_items
        self.assertEqual(
            expand_decl(items[0]),
            ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]],
        )
        self.assertEqual(
            expand_decl(items[1]),
            ["Decl", "uu", ["TypeDecl", ["IdentifierType", ["unsigned"]]]],
        )

        # reusing a type name should work after a pointer
        s7 = r"""
            typedef char TT;
            void foo(void) {
              unsigned * TT;
            }
            """
        s7_ast = self.parse(s7)
        items = s7_ast.ext[1].body.block_items
        self.assertEqual(
            expand_decl(items[0]),
            ["Decl", "TT", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["unsigned"]]]]],
        )

        # redefine a name in the middle of a multi-declarator declaration
        s8 = r"""
            typedef char TT;
            void foo(void) {
                int tt = sizeof(TT), TT, uu = sizeof(TT);
                int uu = sizeof(tt);
            }
            """
        s8_ast = self.parse(s8)
        items = s8_ast.ext[1].body.block_items
        self.assertEqual(
            expand_decl(items[0]),
            ["Decl", "tt", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )
        self.assertEqual(
            expand_decl(items[1]),
            ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )
        self.assertEqual(
            expand_decl(items[2]),
            ["Decl", "uu", ["TypeDecl", ["IdentifierType", ["int"]]]],
        )

        # Don't test this until we have support for it
        # self.assertEqual(expand_init(items[0].init),
        #     ['UnaryOp', 'sizeof', ['Typename', ['TypeDecl', ['IdentifierType', ['TT']]]]])
        # self.assertEqual(expand_init(items[2].init),
        #     ['UnaryOp', 'sizeof', ['ID', 'TT']])

    def test_parameter_reuse_typedef_name(self):
        # identifiers can be reused as parameter names; parameter name scope
        # begins and ends with the function body; it's important that TT is
        # used immediately before the LBRACE or after the RBRACE, to test
        # a corner case
        s1 = r"""
            typedef char TT;
            void foo(unsigned TT, TT bar) {
              TT = 10;
            }
            TT x = 5;
            """
        s1_ast = self.parse(s1)
        self.assertEqual(
            expand_decl(s1_ast.ext[1].decl),
            [
                "Decl",
                "foo",
                [
                    "FuncDecl",
                    [
                        ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]],
                        ["Decl", "bar", ["TypeDecl", ["IdentifierType", ["TT"]]]],
                    ],
                    ["TypeDecl", ["IdentifierType", ["void"]]],
                ],
            ],
        )

        # the scope of a parameter name in a function declaration ends at the
        # end of the declaration...so it is effectively never used; it's
        # important that TT is used immediately after the declaration, to
        # test a corner case
        s2 = r"""
            typedef char TT;
            void foo(unsigned TT, TT bar);
            TT x = 5;
            """
        s2_ast = self.parse(s2)
        self.assertEqual(
            expand_decl(s2_ast.ext[1]),
            [
                "Decl",
                "foo",
                [
                    "FuncDecl",
                    [
                        ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]],
                        ["Decl", "bar", ["TypeDecl", ["IdentifierType", ["TT"]]]],
                    ],
                    ["TypeDecl", ["IdentifierType", ["void"]]],
                ],
            ],
        )

        # ensure an error is raised if a type, redeclared as a parameter, is
        # used as a type
        s3 = r"""
            typedef char TT;
            void foo(unsigned TT, TT bar) {
              TT erroneous = 20;
            }
            """
        self.assertRaises(ParseError, self.parse, s3)

    def test_nested_function_decls(self):
        # parameter names of nested function declarations must not escape into
        # the top-level function _definition's_ scope; the following must
        # succeed because TT is still a typedef inside foo's body
        s1 = r"""
            typedef char TT;
            void foo(unsigned bar(int TT)) {
              TT x = 10;
            }
            """
        self.assertIsInstance(self.parse(s1), FileAST)

    def test_samescope_reuse_name(self):
        # a typedef name cannot be reused as an object name in the same scope
        s1 = r"""
            typedef char TT;
            char TT = 5;
            """
        self.assertRaises(ParseError, self.parse, s1)

        # ...and vice-versa
        s2 = r"""
            char TT = 5;
            typedef char TT;
            """
        self.assertRaises(ParseError, self.parse, s2)

    def test_label_empty_statement(self):
        # Labels with empty statements and no semicolon should be parsed correctly
        s1 = r"""
            int main() {
                int i = 0;
                label0: i++;
                label1:
            }
            """
        s1_ast: FileAST = self.parse(s1)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[1], Label)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[1].stmt, UnaryOp)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[2], Label)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[2].stmt, EmptyStatement)

    def test_case_empty_statement(self):
        # Labels with empty statements and no semicolon should be parsed correctly
        s1 = r"""
            int main() {
                int i = 0;
                switch (i) {
                    case 0:
                        i = 1;
                    case 1:
                }
                return i;
            }
            """
        s2 = r"""
            int main() {
                int i = 0;
                switch (i) {
                    case 0:
                        i = 1;
                    default:
                }
                return i;
            }
            """
        s1_ast: FileAST = self.parse(s1)
        s2_ast: FileAST = self.parse(s2)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[1], Switch)
        self.assertIsInstance(s1_ast.ext[0].body.block_items[1].stmt, Compound)
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[1].stmt.block_items[0], Case
        )
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[1].stmt.block_items[0].stmts[0], Assignment
        )
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[1].stmt.block_items[1], Case
        )
        self.assertIsInstance(
            s1_ast.ext[0].body.block_items[1].stmt.block_items[1].stmts[0],
            EmptyStatement,
        )
        self.assertIsInstance(
            s2_ast.ext[0].body.block_items[1].stmt.block_items[1].stmts[0],
            EmptyStatement,
        )


if __name__ == "__main__":
    # ~ suite = unittest.TestLoader().loadTestsFromNames(
    # ~ ['test_c_parser.TestCParser_fundamentals.test_typedef'])

    # ~ unittest.TextTestRunner(verbosity=2).run(suite)
    unittest.main()
