#!/usr/bin/python
#
# Author: Jashua R. Cloutier (contact via https://bitbucket.org/senex)
# Project: http://senexcanis.com/open-source/cppheaderparser/
#
# Copyright (C) 2011, Jashua R. Cloutier
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in
#   the documentation and/or other materials provided with the
#   distribution.
#
# * Neither the name of Jashua R. Cloutier nor the names of its
#   contributors may be used to endorse or promote products derived from
#   this software without specific prior written permission.  Stories,
#   blog entries etc making reference to this project may mention the
#   name Jashua R. Cloutier in terms of project originator/creator etc.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#
# The CppHeaderParser.py script is written in Python 2.4 and released to
# the open source community for continuous improvements under the BSD
# 2.0 new license, which can be found at:
#
#   http://www.opensource.org/licenses/bsd-license.php
#
"""Parse C++ header files and generate a data structure
representing the class
"""

import ply.lex as lex
import os
import sys
import re

import inspect

def lineno():
    """Returns the current line number in our program."""
    return inspect.currentframe().f_back.f_lineno

version = __version__ = "2.7.4"

tokens = [
    'NUMBER',
    'FLOAT_NUMBER',
    'TEMPLATE_NAME',
    'NAME',
    'OPEN_PAREN',
    'CLOSE_PAREN',
    'OPEN_BRACE',
    'CLOSE_BRACE',
    'OPEN_SQUARE_BRACKET',
    'CLOSE_SQUARE_BRACKET',
    'COLON',
    'SEMI_COLON',
    'COMMA',
    'TAB',
    'BACKSLASH',
    'PIPE',
    'PERCENT',
    'EXCLAMATION',
    'CARET',
    'COMMENT_SINGLELINE',
    'COMMENT_MULTILINE',
    'PRECOMP_MACRO',
    'PRECOMP_MACRO_CONT', 
    'ASTERISK',
    'AMPERSTAND',
    'EQUALS',
    'MINUS',
    'PLUS',  
    'DIVIDE', 
    'CHAR_LITERAL', 
    'STRING_LITERAL',
    'NEW_LINE',
    'SQUOTE',
]

t_ignore = " \r.?@\f"
t_NUMBER = r'[0-9][0-9XxA-Fa-f]*'
t_FLOAT_NUMBER = r'[-+]?[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?'
t_TEMPLATE_NAME = r'CppHeaderParser_template_[0-9]+'
t_NAME = r'[<>A-Za-z_~][A-Za-z0-9_]*'
t_OPEN_PAREN = r'\('
t_CLOSE_PAREN = r'\)'
t_OPEN_BRACE = r'{'
t_CLOSE_BRACE = r'}'
t_OPEN_SQUARE_BRACKET = r'\['
t_CLOSE_SQUARE_BRACKET = r'\]'
t_SEMI_COLON = r';'
t_COLON = r':'
t_COMMA = r','
t_TAB = r'\t'
t_BACKSLASH = r'\\'
t_PIPE = r'\|'
t_PERCENT = r'%'
t_CARET = r'\^'
t_EXCLAMATION = r'!'
t_PRECOMP_MACRO = r'\#.*'
t_PRECOMP_MACRO_CONT = r'.*\\\n'
def t_COMMENT_SINGLELINE(t):
    r'\/\/.*\n'
    global doxygenCommentCache
    if t.value.startswith("///") or t.value.startswith("//!"):
        if doxygenCommentCache:
            doxygenCommentCache += "\n"
        if t.value.endswith("\n"):
            doxygenCommentCache += t.value[:-1]
        else:
            doxygenCommentCache += t.value
    t.lexer.lineno += len([a for a in t.value if a=="\n"])
t_ASTERISK = r'\*'
t_MINUS = r'\-'
t_PLUS = r'\+'
t_DIVIDE = r'/(?!/)'
t_AMPERSTAND = r'&'
t_EQUALS = r'='
t_CHAR_LITERAL = "'.'"
t_SQUOTE = "'"
#found at http://wordaligned.org/articles/string-literals-and-regular-expressions
#TODO: This does not work with the string "bla \" bla"
t_STRING_LITERAL = r'"([^"\\]|\\.)*"'
#Found at http://ostermiller.org/findcomment.html
def t_COMMENT_MULTILINE(t):
    r'/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/'
    global doxygenCommentCache
    if t.value.startswith("/**") or t.value.startswith("/*!"):
        #not sure why, but get double new lines
        v = t.value.replace("\n\n", "\n")
        #strip prefixing whitespace
        v = re.sub("\n[\s]+\*", "\n*", v)
        doxygenCommentCache += v
    t.lexer.lineno += len([a for a in t.value if a=="\n"])
def t_NEWLINE(t):
    r'\n+'
    t.lexer.lineno += len(t.value)

def t_error(v):
    print(( "Lex error: ", v ))

lex.lex()
# Controls error_print
print_errors = 1
# Controls warning_print
print_warnings = 1
# Controls debug_print
debug = 0
# Controls trace_print
debug_trace = 0

def error_print(arg):
    if print_errors: print(("[%4d] %s"%(inspect.currentframe().f_back.f_lineno, arg)))

def warning_print(arg):
    if print_warnings: print(("[%4d] %s"%(inspect.currentframe().f_back.f_lineno, arg)))

def debug_print(arg):
    global debug
    if debug: print(("[%4d] %s"%(inspect.currentframe().f_back.f_lineno, arg)))

def trace_print(*arg):
    global debug_trace
    if debug_trace:
        sys.stdout.write("[%s] "%(inspect.currentframe().f_back.f_lineno))
        for a in arg: sys.stdout.write("%s "%a)
        sys.stdout.write("\n")

supportedAccessSpecifier = [
    'public',
    'protected', 
    'private'
]

#Symbols to ignore, usually special macros
ignoreSymbols = [
    'Q_OBJECT',
]

doxygenCommentCache = ""

#Track what was added in what order and at what depth
parseHistory = []

def is_namespace(nameStack):
    """Determines if a namespace is being specified"""
    if len(nameStack) == 0:
        return False
    if nameStack[0] == "namespace":
        return True
    return False

def is_enum_namestack(nameStack):
    """Determines if a namestack is an enum namestack"""
    if len(nameStack) == 0:
        return False
    if nameStack[0] == "enum":
        return True
    if len(nameStack) > 1 and nameStack[0] == "typedef" and nameStack[1] == "enum":
        return True
    return False

def is_fundamental(s):
    for a in s.split():
        if a not in ["size_t", "struct", "union", "unsigned", "signed", "bool", "char", "short", "int", "float", "double", "long", "void", "*"]: return False
    return True

def is_function_pointer_stack(stack):
    """Count how many non-nested paranthesis are in the stack.  Useful for determining if a stack is a function pointer"""
    paren_depth = 0
    paren_count = 0
    star_after_first_paren = False
    last_e = None
    for e in stack:
        if e == "(":
            paren_depth += 1
        elif e == ")" and paren_depth > 0:
            paren_depth -= 1
            if paren_depth == 0:
                paren_count += 1
        elif e == "*" and last_e == "(" and paren_count == 0 and paren_depth == 1:
            star_after_first_paren = True
        last_e = e
        
    if star_after_first_paren and paren_count == 2:
        return True
    else:
        return False

def is_method_namestack(stack):
    r = False
    if '(' not in stack: r = False
    elif stack[0] == 'typedef': r = False    # TODO deal with typedef function prototypes
    #elif '=' in stack and stack.index('=') < stack.index('(') and stack[stack.index('=')-1] != 'operator': r = False    #disabled July6th - allow all operators
    elif 'operator' in stack: r = True    # allow all operators
    elif '{' in stack and stack.index('{') < stack.index('('): r = False    # struct that looks like a method/class
    elif '(' in stack and ')' in stack:
        if '{' in stack and '}' in stack: r = True
        elif stack[-1] == ';':
            if is_function_pointer_stack(stack):
                r = False
            else:
                r = True
        elif '{' in stack: r = True    # ideally we catch both braces... TODO
    else: r = False
    #Test for case of property set to something with parens such as "static const int CONST_A = (1 << 7) - 1;"
    if r and "(" in stack and "=" in stack and 'operator' not in stack:
        if stack.index("=") < stack.index("("): r = False
    return r

def is_property_namestack(nameStack):
    r = False
    if '(' not in nameStack and ')' not in nameStack: r = True
    elif "(" in nameStack and "=" in nameStack and nameStack.index("=") < nameStack.index("("): r = True
    #See if we are a function pointer
    if not r and is_function_pointer_stack(nameStack): r = True
    return r

def detect_lineno(s):
    """Detect the line number for a given token string"""
    try:
        rtn = s.lineno()
        if rtn != -1:
            return rtn
    except: pass
    global curLine
    return curLine 

def filter_out_attribute_keyword(stack):
    """Strips __attribute__ and its parenthetical expression from the stack"""
    if "__attribute__" not in stack: return stack
    try:
        debug_print("Stripping __attribute__ from %s"% stack)
        attr_index = stack.index("__attribute__")
        attr_end = attr_index + 1 #Assuming not followed by parenthetical expression which wont happen
        #Find final paren
        if stack[attr_index + 1] == '(':
            paren_count = 1
            for i in range(attr_index + 2, len(stack)):
                elm = stack[i]
                if elm == '(':
                    paren_count += 1
                elif elm == ')':
                    paren_count -= 1
                    if paren_count == 0:
                        attr_end = i + 1
                        break
        new_stack = stack[0:attr_index] + stack[attr_end:]
        debug_print("stripped stack is %s"% new_stack)
        return new_stack
    except:
        return stack
    

class TagStr(str):
    """Wrapper for a string that allows us to store the line number associated with it"""
    lineno_reg = {}
    def __new__(cls,*args,**kw):
        new_obj =  str.__new__(cls,*args)
        if "lineno" in kw:
            TagStr.lineno_reg[id(new_obj)] = kw["lineno"]
        return new_obj
    
    def __del__(self):
        try:
            del TagStr.lineno_reg[id(self)]
        except: pass
    
    def lineno(self):
        return TagStr.lineno_reg.get(id(self), -1)

class CppParseError(Exception): pass
    
class CppClass(dict):
    """Takes a name stack and turns it into a class
    
    Contains the following Keys:
    self['name'] - Name of the class
    self['doxygen'] - Doxygen comments associated with the class if they exist
    self['inherits'] - List of Classes that this one inherits where the values
        are of the form {"access": Anything in supportedAccessSpecifier
                                  "class": Name of the class
    self['methods'] - Dictionary where keys are from supportedAccessSpecifier
        and values are a lists of CppMethod's
    self['properties'] - Dictionary where keys are from supportedAccessSpecifier
        and values are lists of CppVariable's 
    self['enums'] - Dictionary where keys are from supportedAccessSpecifier and
        values are lists of CppEnum's
    self['structs'] - Dictionary where keys are from supportedAccessSpecifier and
        values are lists of nested Struct's
    
    An example of how this could look is as follows:
    #self =
    {
        'name': ""
        'inherits':[]
        'methods':
        {
            'public':[],
            'protected':[], 
            'private':[]
        }, 
        'properties':
        {
            'public':[],
            'protected':[], 
            'private':[]
        },
        'enums':
        {
            'public':[],
            'protected':[], 
            'private':[]
        }
    }
    """

    def get_all_methods(self):
        r = []
        for typ in supportedAccessSpecifier: r += self['methods'][typ]
        return r

    def get_all_method_names( self ):
        r = []
        for typ in supportedAccessSpecifier: r += self.get_method_names(typ)        # returns list
        return r

    def get_all_pure_virtual_methods( self ):
        r = {}
        for typ in supportedAccessSpecifier: r.update(self.get_pure_virtual_methods(typ))        # returns dict
        return r


    def get_method_names( self, type='public' ): return [ meth['name'] for meth in self['methods'][ type ] ]

    def get_pure_virtual_methods( self, type='public' ):
        r = {}
        for meth in self['methods'][ type ]:
            if meth['pure_virtual']: r[ meth['name'] ] = meth
        return r

    def __init__(self, nameStack, curTemplate):
        self['nested_classes'] = []
        self['parent'] = None
        self['abstract'] = False
        self._public_enums = {}
        self._public_structs = {}
        self._public_typedefs = {}
        self._public_forward_declares = []
        self['namespace'] = ""

        debug_print( "Class:    %s"%nameStack )
        debug_print( "Template: %s"%curTemplate)
        
        if (len(nameStack) < 2):
            nameStack.insert(1, "")#anonymous struct
        global doxygenCommentCache
        if len(doxygenCommentCache):
            self["doxygen"] = doxygenCommentCache
            doxygenCommentCache = ""
        
        if "::" in "".join(nameStack):
            #Re-Join class paths (ex  ['class', 'Bar', ':', ':', 'Foo'] -> ['class', 'Bar::Foo'] 
            try:
                new_nameStack = []
                for name in nameStack:
                    if len(new_nameStack) == 0: 
                        new_nameStack.append(name)
                    elif name == ":" and new_nameStack[-1].endswith(":"):
                        new_nameStack[-1] += name
                    elif new_nameStack[-1].endswith("::"):
                        new_nameStack[-2] += new_nameStack[-1] + name
                        del new_nameStack[-1]
                    else:
                        new_nameStack.append(name)
                trace_print("Convert from namestack\n %s\nto\n%s"%(nameStack, new_nameStack))
                nameStack = new_nameStack
            except: pass
        
        # Handle final specifier
        self["final"] = False
        try:
            final_index = nameStack.index("final")
            # Dont trip up the rest of the logic
            del nameStack[final_index]
            self["final"] = True
            trace_print("final")
        except: pass
        
        self["name"] = nameStack[1]
        self["line_number"] = detect_lineno(nameStack[0])
        
        #Handle template classes
        if len(nameStack) > 3 and nameStack[2].startswith("<"):
            open_template_count = 0
            param_separator = 0
            found_first = False
            i = 0
            for elm in nameStack:
                if '<' in elm :
                    open_template_count += 1
                    found_first = True
                elif '>' in elm:
                    open_template_count -= 1
                if found_first and open_template_count == 0:
                    self["name"] = "".join(nameStack[1:i + 1])
                    break;
                i += 1
        elif ":" in nameStack:
            self['name'] = nameStack[ nameStack.index(':') - 1 ]

        inheritList = []

        if nameStack.count(':') == 1:
            nameStack = nameStack[nameStack.index(":") + 1:]
            while len(nameStack):
                tmpStack = []
                tmpInheritClass = {"access":"private", "virtual": False}
                if "," in nameStack:
                    tmpStack = nameStack[:nameStack.index(",")]
                    nameStack = nameStack[nameStack.index(",") + 1:]
                else:
                    tmpStack = nameStack
                    nameStack = []
                
                # Convert template classes to one name in the last index
                for i in range(0, len(tmpStack)):
                    if '<' in tmpStack[i]:
                        tmpStack2 = tmpStack[:i-1]
                        tmpStack2.append("".join(tmpStack[i-1:]))
                        tmpStack = tmpStack2
                        break
                if len(tmpStack) == 0:
                    break;
                elif len(tmpStack) == 1:
                    tmpInheritClass["class"] = tmpStack[0]
                elif len(tmpStack) == 2:
                    tmpInheritClass["access"] = tmpStack[0]
                    tmpInheritClass["class"] = tmpStack[1]
                elif len(tmpStack) == 3 and "virtual" in tmpStack:
                    tmpInheritClass["access"] = tmpStack[1] if tmpStack[1] != "virtual" else tmpStack[0]
                    tmpInheritClass["class"] = tmpStack[2]
                    tmpInheritClass["virtual"] = True
                else:
                    warning_print( "Warning: can not parse inheriting class %s"%(" ".join(tmpStack)))
                    if '>' in tmpStack: pass    # allow skip templates for now
                    else: raise NotImplemented

                if 'class' in tmpInheritClass: inheritList.append(tmpInheritClass)

        elif nameStack.count(':') == 2: self['parent'] = self['name']; self['name'] = nameStack[-1]

        elif nameStack.count(':') > 2 and nameStack[0] in ("class", "struct"):
            tmpStack = nameStack[nameStack.index(":") + 1:]
            
            superTmpStack = [[]]
            for tok in tmpStack:
                if tok == ',':
                    superTmpStack.append([])
                else:
                    superTmpStack[-1].append(tok)
            
            for tmpStack in superTmpStack:
                tmpInheritClass = {"access":"private"}
                
                if len(tmpStack) and tmpStack[0] in supportedAccessSpecifier:
                    tmpInheritClass["access"] = tmpStack[0]
                    tmpStack = tmpStack[1:]
                
                inheritNSStack = []
                while len(tmpStack) > 3:
                    if tmpStack[0] == ':': break;
                    if tmpStack[1] != ':': break;
                    if tmpStack[2] != ':': break;
                    inheritNSStack.append(tmpStack[0])
                    tmpStack = tmpStack[3:]
                if len(tmpStack) == 1 and tmpStack[0] != ':':
                     inheritNSStack.append(tmpStack[0])
                tmpInheritClass["class"] = "::".join(inheritNSStack)
                inheritList.append(tmpInheritClass)

        self['inherits'] = inheritList

        if curTemplate:
            self["template"] = curTemplate
            trace_print("Setting template to '%s'"%self["template"])

        methodAccessSpecificList = {}
        propertyAccessSpecificList = {}
        enumAccessSpecificList = {}
        structAccessSpecificList = {}
        typedefAccessSpecificList = {}
        forwardAccessSpecificList = {}
        
        for accessSpecifier in supportedAccessSpecifier:
            methodAccessSpecificList[accessSpecifier] = []
            propertyAccessSpecificList[accessSpecifier] = []
            enumAccessSpecificList[accessSpecifier] = []
            structAccessSpecificList[accessSpecifier] = []
            typedefAccessSpecificList[accessSpecifier] = []
            forwardAccessSpecificList[accessSpecifier] = []

        self['methods'] = methodAccessSpecificList
        self['properties'] = propertyAccessSpecificList
        self['enums'] = enumAccessSpecificList
        self['structs'] = structAccessSpecificList
        self['typedefs'] = typedefAccessSpecificList
        self['forward_declares'] = forwardAccessSpecificList

 
    def show(self):
        """Convert class to a string"""
        namespace_prefix = ""
        if self["namespace"]: namespace_prefix = self["namespace"] + "::"
        rtn = "%s %s"%(self["declaration_method"], namespace_prefix + self["name"])
        if self["final"]: rtn += " final"
        if self['abstract']: rtn += '    (abstract)\n'
        else: rtn += '\n'

        if 'doxygen' in list(self.keys()): rtn += self["doxygen"] + '\n'
        if 'parent' in list(self.keys()) and self['parent']: rtn += 'parent class: ' + self['parent'] + '\n'

        if "inherits" in list(self.keys()):
            rtn += "  Inherits: "
            for inheritClass in self["inherits"]:
                if inheritClass["virtual"]: rtn += "virtual "
                rtn += "%s %s, "%(inheritClass["access"], inheritClass["class"])
            rtn += "\n"
        rtn += "  {\n"
        for accessSpecifier in supportedAccessSpecifier:
            rtn += "    %s\n"%(accessSpecifier)
            #Enums
            if (len(self["enums"][accessSpecifier])):
                rtn += "        <Enums>\n"
            for enum in self["enums"][accessSpecifier]:
                rtn += "            %s\n"%(repr(enum))
            #Properties
            if (len(self["properties"][accessSpecifier])):
                rtn += "        <Properties>\n"
            for property in self["properties"][accessSpecifier]:
                rtn += "            %s\n"%(repr(property))
            #Methods
            if (len(self["methods"][accessSpecifier])):
                rtn += "        <Methods>\n"
            for method in self["methods"][accessSpecifier]:
                rtn += "\t\t" + method.show() + '\n'
        rtn += "  }\n"
        print(rtn)
    
    def __str__(self):
        """Convert class to a string"""
        namespace_prefix = ""
        if self["namespace"]: namespace_prefix = self["namespace"] + "::"
        rtn = "%s %s"%(self["declaration_method"], namespace_prefix + self["name"])
        if self["final"]: rtn += " final"
        if self['abstract']: rtn += '    (abstract)\n'
        else: rtn += '\n'

        if 'doxygen' in list(self.keys()): rtn += self["doxygen"] + '\n'
        if 'parent' in list(self.keys()) and self['parent']: rtn += 'parent class: ' + self['parent'] + '\n'

        if "inherits" in list(self.keys()) and len(self["inherits"]):
            rtn += "Inherits: "
            for inheritClass in self["inherits"]:
                if inheritClass.get("virtual", False): rtn += "virtual "
                rtn += "%s %s, "%(inheritClass["access"], inheritClass["class"])
            rtn += "\n"
        rtn += "{\n"
        for accessSpecifier in supportedAccessSpecifier:
            rtn += "%s\n"%(accessSpecifier)
            #Enums
            if (len(self["enums"][accessSpecifier])):
                rtn += "    // Enums\n"
            for enum in self["enums"][accessSpecifier]:
                rtn += "    %s\n"%(repr(enum))
            #Properties
            if (len(self["properties"][accessSpecifier])):
                rtn += "    // Properties\n"
            for property in self["properties"][accessSpecifier]:
                rtn += "    %s\n"%(repr(property))
            #Methods
            if (len(self["methods"][accessSpecifier])):
                rtn += "    // Methods\n"
            for method in self["methods"][accessSpecifier]:
                rtn += "   %s\n"%(repr(method))
        rtn += "}\n"
        return rtn


class CppUnion( CppClass ):
    """Takes a name stack and turns it into a union
    
    Contains the following Keys:
    self['name'] - Name of the union
    self['doxygen'] - Doxygen comments associated with the union if they exist
    self['members'] - List of members the union has 
    
    An example of how this could look is as follows:
    #self =
    {
        'name': ""
        'members': []
    }
    """
    
    def __init__(self, nameStack):
        CppClass.__init__(self, nameStack, None)
        self["name"] = "union " + self["name"]
        self["members"] = self["properties"]["public"]
    
    def transform_to_union_keys(self):
        print("union keys: %s"%list(self.keys()))
        for key in ['inherits', 'parent', 'abstract', 'namespace', 'typedefs', 'methods']:
            del self[key] 
        
    def show(self):
        """Convert class to a string"""
        print(self)
    
    
    def __str__(self):
        """Convert class to a string"""
        namespace_prefix = ""
        if self["namespace"]: namespace_prefix = self["namespace"] + "::"
        rtn = "%s %s"%(self["declaration_method"], namespace_prefix + self["name"])
        if self['abstract']: rtn += '    (abstract)\n'
        else: rtn += '\n'

        if 'doxygen' in list(self.keys()): rtn += self["doxygen"] + '\n'
        if 'parent' in list(self.keys()) and self['parent']: rtn += 'parent class: ' + self['parent'] + '\n'

        rtn += "{\n"
        for member in self["members"]:
            rtn += "    %s\n"%(repr(member))
        rtn += "}\n"
        return rtn

       

class _CppMethod( dict ):
    def _params_helper1( self, stack ):
        # deal with "throw" keyword
        if 'throw' in stack: stack = stack[ : stack.index('throw') ]

        ## remove GCC keyword __attribute__(...) and preserve returns ##
        cleaned = []
        hit = False; hitOpen = 0; hitClose = 0
        for a in stack:
            if a == '__attribute__': hit = True
            if hit:
                if a == '(': hitOpen += 1
                elif a == ')': hitClose += 1
                if a==')' and hitOpen == hitClose:
                    hit = False
            else:
                cleaned.append( a )
        stack = cleaned

        # also deal with attribute((const)) function prefix #
        # TODO this needs to be better #
        if len(stack) > 5:
            a = ''.join(stack)
            if a.startswith('((__const__))'): stack = stack[ 5 : ]
            elif a.startswith('__attribute__((__const__))'): stack = stack[ 6 : ]

        stack = stack[stack.index('(') + 1: ]
        if not stack: return []
        if len(stack)>=3 and stack[0]==')' and stack[1]==':':    # is this always a constructor?
            self['constructor'] = True
            return []

        stack.reverse(); _end_ = stack.index(')'); stack.reverse()
        stack = stack[ : len(stack)-(_end_+1) ]
        if '(' not in stack: return stack    # safe to return, no defaults that init a class

        # transforms ['someclass', '(', '0', '0', '0', ')'] into "someclass(0,0,0)'"
        r = []; hit=False
        for a in stack:
            if a == '(': hit=True
            elif a == ')': hit=False
            if hit or a == ')': r[-1] = r[-1] + a
            else: r.append( a )
        return r

    def _params_helper2( self, params ):
        for p in params:
            p['method'] = self        # save reference in variable to parent method
            if '::' in p['type']:
                ns = p['type'].split('::')[0]
                if ns not in Resolver.NAMESPACES and ns in Resolver.CLASSES:
                    p['type'] = self['namespace'] + p['type']
            else: p['namespace'] = self[ 'namespace' ]

class CppMethod( _CppMethod ):
    """Takes a name stack and turns it into a method
    
    Contains the following Keys:
    self['rtnType'] - Return type of the method (ex. "int")
    self['name'] - Name of the method (ex. "getSize")
    self['doxygen'] - Doxygen comments associated with the method if they exist
    self['parameters'] - List of CppVariables
    """
    def show(self):
        r = ['method name: %s (%s)' %(self['name'],self['debug']) ]
        if self['returns']: r.append( 'returns: %s'%self['returns'] )
        if self['parameters']: r.append( 'number arguments: %s' %len(self['parameters']))
        if self['pure_virtual']: r.append( 'pure virtual: %s'%self['pure_virtual'] )
        if self['constructor']: r.append( 'constructor' )
        if self['destructor']: r.append( 'destructor' )
        return '\n\t\t  '.join( r )

    def __init__(self, nameStack, curClass, methinfo, curTemplate):
        debug_print( "Method:   %s"%nameStack )
        debug_print( "Template: %s"%curTemplate )
        global doxygenCommentCache
        if len(doxygenCommentCache):
            self["doxygen"] = doxygenCommentCache
            doxygenCommentCache = ""
        if "operator" in nameStack:
            self["rtnType"] = " ".join(nameStack[:nameStack.index('operator')])
            self["name"] = "".join(nameStack[nameStack.index('operator'):nameStack.index('(')])
        else:
            self["rtnType"] = " ".join(nameStack[:nameStack.index('(') - 1])
            self["name"] = " ".join(nameStack[nameStack.index('(') - 1:nameStack.index('(')])
        if self["rtnType"].startswith("virtual"):
           self["rtnType"] = self["rtnType"][len("virtual"):].strip()
        if len(self["rtnType"]) == 0 or self["name"] == curClass:
            self["rtnType"] = "void"
        
        self["rtnType"] = self["rtnType"].replace(' : : ', '::' )
        self["rtnType"] = self["rtnType"].replace(" <","<")
        self["rtnType"] = self["rtnType"].replace(" >",">").replace(">>", "> >").replace(">>", "> >")
        self["rtnType"] = self["rtnType"].replace(" ,",",")
        
        for spec in ["const", "final", "override"]:
            self[spec] = False
            for i in reversed(nameStack):
                if i == spec:
                    self[spec] = True
                    break
                elif i == ")":
                    break

        self.update( methinfo )
        self["line_number"] = detect_lineno(nameStack[0])

        #Filter out initializer lists used in constructors
        try:
            paren_depth_counter = 0
            for i in range(0, len(nameStack)):
                elm = nameStack[i]
                if elm == "(":
                    paren_depth_counter += 1
                if elm == ")":
                    paren_depth_counter -=1
                    if paren_depth_counter == 0 and nameStack[i+1] == ':':
                        debug_print("Stripping out initializer list")
                        nameStack = nameStack[:i+1]
                        break
        except: pass
        
        paramsStack = self._params_helper1( nameStack )
        
        debug_print( "curTemplate: %s"%curTemplate)
        if curTemplate:
            self["template"] = curTemplate
            debug_print( "SET self['template'] to `%s`"%self["template"]) 

        params = []
        #See if there is a doxygen comment for the variable
        doxyVarDesc = {}
        
        if "doxygen" in self:
            doxyLines = self["doxygen"].split("\n")
            lastParamDesc = ""
            for doxyLine in doxyLines:
                if " @param " in doxyLine or " \param " in doxyLine:
                    try:
                        #Strip out the param
                        doxyLine = doxyLine[doxyLine.find("param ") + 6:]
                        (var, desc) = doxyLine.split(" ", 1)
                        doxyVarDesc[var] = desc.strip()
                        lastParamDesc = var
                    except: pass
                elif " @return " in doxyLine or " \return " in doxyLine:
                    lastParamDesc = ""
                    # not handled for now
                elif lastParamDesc:
                    try:
                        doxyLine = doxyLine.strip()
                        if " " not in doxyLine:
                            lastParamDesc = ""
                            continue
                        doxyLine = doxyLine[doxyLine.find(" ") + 1:]
                        doxyVarDesc[lastParamDesc] += " " + doxyLine
                    except: pass
        
        #Create the variable now
        while (len(paramsStack)):
            # Find commas that are not nexted in <>'s like template types
            open_template_count = 0
            param_separator = 0
            i = 0
            for elm in paramsStack:
                if '<' in elm :
                    open_template_count += 1
                elif '>' in elm:
                    open_template_count -= 1
                elif elm == ',' and open_template_count == 0:
                    param_separator = i
                    break
                i += 1
            
            if param_separator:
                param = CppVariable(paramsStack[0:param_separator],  doxyVarDesc=doxyVarDesc)
                if len(list(param.keys())): params.append(param)
                paramsStack = paramsStack[param_separator + 1:]
            else:
                param = CppVariable(paramsStack,  doxyVarDesc=doxyVarDesc)
                if len(list(param.keys())): params.append(param)
                break


        self["parameters"] = params
        self._params_helper2( params )    # mods params inplace

    def __str__(self):
        filter_keys = ("parent", "defined", "operator", "returns_reference")
        cpy = dict((k,v) for (k,v) in list(self.items()) if k not in filter_keys)
        return "%s"%cpy


class _CppVariable(dict):
    def _name_stack_helper( self, stack ):
        stack = list(stack)
        if '=' not in stack:        # TODO refactor me
            # check for array[n] and deal with funny array syntax: "int myvar:99"
            array = []
            while stack and stack[-1].isdigit(): array.append( stack.pop() )
            if array: array.reverse(); self['array'] = int(''.join(array))
            if stack and stack[-1].endswith(':'): stack[-1] = stack[-1][:-1]

        while stack and not stack[-1]: stack.pop()            # can be empty
        return stack

    def init(self):
        #assert self['name']    # allow unnamed variables, methods like this: "void func(void);"
        a = []
        self['aliases'] = []; self['parent'] = None; self['typedef'] = None
        for key in 'constant reference pointer static typedefs class fundamental unresolved'.split():
            self[ key ] = 0
        for b in self['type'].split():
            if b == '__const__': b = 'const'
            a.append( b )
        self['type'] = ' '.join( a )


class CppVariable( _CppVariable ):
    """Takes a name stack and turns it into a method
    
    Contains the following Keys:
    self['type'] - Type for the variable (ex. "const string &")
    self['name'] - Name of the variable (ex. "numItems")
    self['namespace'] - Namespace containing the enum
    self['desc'] - Description of the variable if part of a method (optional)
    self['doxygen'] - Doxygen comments associated with the method if they exist
    self['defaultValue'] - Default value of the variable, this key will only
        exist if there is a default value
    self['extern'] - True if its an extern, false if not
    """
    Vars = []
    def __init__(self, nameStack,  **kwargs):
        debug_print("trace %s"%nameStack)
        if len(nameStack) and nameStack[0] == "extern":
            self['extern'] = True
            del nameStack[0]
        else:
            self['extern'] = False
        
        _stack_ = nameStack
        if "[" in nameStack: #strip off array informatin
            arrayStack = nameStack[nameStack.index("["):]
            if nameStack.count("[") > 1:
                debug_print("Multi dimensional array")
                debug_print("arrayStack=%s"%arrayStack)
                nums = filter(lambda x: x.isdigit(), arrayStack)
                # Calculate size by multiplying all dimensions
                p = 1
                for n in nums:
                    p *= int(n)
                #Multi dimensional array
                self["array_size"] = p
                self["multi_dimensional_array"] = 1
                self["multi_dimensional_array_size"] = "x".join(nums)
            else:
                debug_print("Array")
                if len(arrayStack) == 3:
                    self["array_size"] = arrayStack[1] 
            nameStack = nameStack[:nameStack.index("[")]
            self["array"] = 1
        else:
            self["array"] = 0
        nameStack = self._name_stack_helper( nameStack )
        global doxygenCommentCache
        if len(doxygenCommentCache):
            self["doxygen"] = doxygenCommentCache
            doxygenCommentCache = ""

        debug_print( "Variable: %s"%nameStack )

        self["line_number"] = detect_lineno(nameStack[0])
        self["function_pointer"] = 0

        if (len(nameStack) < 2):    # +++
            if len(nameStack) == 1: self['type'] = nameStack[0]; self['name'] = ''
            else: error_print(_stack_); assert 0

        elif is_function_pointer_stack(nameStack): #function pointer
            self["type"] = " ".join(nameStack[:nameStack.index("(") + 2] + nameStack[nameStack.index(")")  :])
            self["name"] = " ".join(nameStack[nameStack.index("(") + 2 : nameStack.index(")")])
            self["function_pointer"] = 1

        elif ("=" in nameStack):
            self["type"] = " ".join(nameStack[:nameStack.index("=") - 1])
            self["name"] = nameStack[nameStack.index("=") - 1]
            self["defaultValue"] = " ".join(nameStack[nameStack.index("=") + 1:])    # deprecate camelCase in dicts
            self['default'] = " ".join(nameStack[nameStack.index("=") + 1:])

        elif is_fundamental(nameStack[-1]) or nameStack[-1] in ['>', '<' , ':', '.']:
            #Un named parameter
            self["type"] = " ".join(nameStack)
            self["name"] = ""

        else:    # common case
            self["type"] = " ".join(nameStack[:-1])
            self["name"] = nameStack[-1]

        self["type"] = self["type"].replace(" :",":")
        self["type"] = self["type"].replace(": ",":")
        self["type"] = self["type"].replace(" <","<")
        self["type"] = self["type"].replace(" >",">").replace(">>", "> >").replace(">>", "> >")
        self["type"] = self["type"].replace(" ,",",")
        #Optional doxygen description
        try:
            self["desc"] = kwargs["doxyVarDesc"][self["name"]]
        except: pass

        self.init()
        CppVariable.Vars.append( self )        # save and resolve later
    
    def __str__(self):
        keys_white_list = ['constant','name','reference','type','static','pointer','desc', 'line_number', 'extern']
        cpy = dict((k,v) for (k,v) in list(self.items()) if k in keys_white_list)
        if "array_size" in self: cpy["array_size"] = self["array_size"]
        return "%s"%cpy

class _CppEnum(dict):
    def resolve_enum_values( self, values ):
        """Evaluates the values list of dictionaries passed in and figures out what the enum value
        for each enum is editing in place:
        
        Example:
        From: [{'name': 'ORANGE'},
               {'name': 'RED'},
               {'name': 'GREEN', 'value': '8'}]
        To:   [{'name': 'ORANGE', 'value': 0},
               {'name': 'RED', 'value': 1},
               {'name': 'GREEN', 'value': 8}]
        """
        t = int; i = 0
        names = [ v['name'] for v in values ]
        for v in values:
            if 'value' in v:
                a = v['value'].strip()
                # Remove single quotes from single quoted chars (unless part of some expression
                if len(a) == 3 and a[0] == "'" and a[2] == "'":
                    a = v['value'] = a[1]
                if a.lower().startswith("0x"):
                    try:
                        i = a = int(a , 16)
                    except:pass
                elif a.isdigit():
                    i = a = int( a )
                elif a in names:
                    for other in values:
                        if other['name'] == a:
                            v['value'] = other['value']
                            break

                elif '"' in a or "'" in a: t = str # only if there are quotes it this a string enum
                else:
                    try:
                        a = i = ord(a)
                    except: pass
                #Allow access of what is in the file pre-convert if converted
                if v['value'] != str(a):
                    v['raw_value'] = v['value']
                v['value'] = a
            else: v['value'] = i
            try:
                v['value'] = v['value'].replace(" < < ", " << ").replace(" >> ", " >> ")
            except: pass
            i += 1
        return t

class CppEnum(_CppEnum):
    """Takes a name stack and turns it into an Enum
    
    Contains the following Keys:
    self['name'] - Name of the enum (ex. "ItemState")
    self['namespace'] - Namespace containing the enum
    self['values'] - List of values where the values are a dictionary of the
        form {"name": name of the key (ex. "PARSING_HEADER"),
                  "value": Specified value of the enum, this key will only exist
                    if a value for a given enum value was defined
                }
    """
    def __init__(self, nameStack):
        global doxygenCommentCache
        if len(doxygenCommentCache):
            self["doxygen"] = doxygenCommentCache
            doxygenCommentCache = ""
        if len(nameStack) == 3 and nameStack[0] == "enum":
            debug_print("Created enum as just name/value")
            self["name"] = nameStack[1]
            self["instances"]=[nameStack[2]]
        if len(nameStack) < 4 or "{" not in nameStack or "}" not in nameStack:
            #Not enough stuff for an enum
            debug_print("Bad enum")
            return
        valueList = []
        self["line_number"] = detect_lineno(nameStack[0])
        #Figure out what values it has
        valueStack = nameStack[nameStack.index('{') + 1: nameStack.index('}')]
        while len(valueStack):
            tmpStack = []
            if "," in valueStack:
                tmpStack = valueStack[:valueStack.index(",")]
                valueStack = valueStack[valueStack.index(",") + 1:]
            else:
                tmpStack = valueStack
                valueStack = []
            d = {}
            if len(tmpStack) == 1: d["name"] = tmpStack[0]
            elif len(tmpStack) >= 3 and tmpStack[1] == "=":
                d["name"] = tmpStack[0]; d["value"] = " ".join(tmpStack[2:])
            elif len(tmpStack) == 2 and tmpStack[1] == "=":
                debug_print( "WARN-enum: parser missed value for %s"%tmpStack[0] )
                d["name"] = tmpStack[0]

            if d: valueList.append( d )

        if len(valueList):
            self['type'] = self.resolve_enum_values( valueList )    # returns int for standard enum
            self["values"] = valueList
        else:
            warning_print( 'WARN-enum: empty enum %s'%nameStack )
            return
        #Figure out if it has a name
        preBraceStack = nameStack[:nameStack.index("{")]
        postBraceStack = nameStack[nameStack.index("}") + 1:]
        self["typedef"] = False
        if (len(preBraceStack) == 4 and ":" in nameStack and "typedef" not in nameStack):
            # C++11 specify enum type with "enum <enum_name> : <type> ..." syntax
            self["name"] = preBraceStack[1]
            self["type"] = preBraceStack[3]
        elif (len(preBraceStack) == 2 and "typedef" not in nameStack):
            # enum "enum <enum_name> ..." syntax
            self["name"] = preBraceStack[1]           
        elif len(postBraceStack) and "typedef" in nameStack:
            self["name"] = " ".join(postBraceStack)
            self["typedef"] = True
        else: warning_print( 'WARN-enum: nameless enum %s'%nameStack )
        #See if there are instances of this
        if "typedef" not in nameStack and len(postBraceStack):
            self["instances"] = []
            for var in postBraceStack:
                if "," in var:
                    continue
                self["instances"].append(var)
        self["namespace"] = ""


class CppStruct(dict):
    Structs = []
    def __init__(self, nameStack):
        if len(nameStack) >= 2: self['type'] = nameStack[1]
        else: self['type'] = None
        self['fields'] = []
        self.Structs.append( self )
        global curLine
        self["line_number"] = curLine

C99_NONSTANDARD = {
    'int8' : 'signed char',
    'int16' : 'short int',
    'int32' : 'int',
    'int64' : 'int64_t',        # this can be: long int (64bit), or long long int (32bit)
    'uint' : 'unsigned int',
    'uint8' : 'unsigned char',
    'uint16' : 'unsigned short int',
    'uint32' : 'unsigned int',
    'uint64' : 'uint64_t',    # depends on host bits
}


def standardize_fundamental( s ):
    if s in C99_NONSTANDARD: return C99_NONSTANDARD[ s ]
    else: return s


class Resolver(object):
    C_FUNDAMENTAL = 'size_t unsigned signed bool char wchar short int float double long void'.split()
    C_FUNDAMENTAL += 'struct union enum'.split()


    SubTypedefs = {}        # TODO deprecate?
    NAMESPACES = []
    CLASSES = {}
    STRUCTS = {}

    def initextra(self):
        self.typedefs = {}
        self.typedefs_order = []
        self.classes_order = []
        self.structs = Resolver.STRUCTS
        self.structs_order = []
        self.namespaces = Resolver.NAMESPACES        # save all namespaces
        self.curStruct = None
        self.stack = []    # full name stack, good idea to keep both stacks? (simple stack and full stack)
        self._classes_brace_level = {}    # class name : level
        self._structs_brace_level = {}        # struct type : level
        self._method_body = None
        self._forward_decls = []
        self._template_typenames = []    # template<typename XXX>

    def current_namespace(self): return self.cur_namespace(True)

    def cur_namespace(self, add_double_colon=False):
        rtn = ""
        i = 0
        while i < len(self.nameSpaces):
            rtn += self.nameSpaces[i]
            if add_double_colon or i < len(self.nameSpaces) - 1: rtn += "::"
            i+=1
        return rtn


    def guess_ctypes_type( self, string ):
        pointers = string.count('*')
        string = string.replace('*','')

        a = string.split()
        if 'unsigned' in a: u = 'u'
        else: u = ''
        if 'long' in a and 'double' in a: b = 'longdouble'    # there is no ctypes.c_ulongdouble (this is a 64bit float?)
        elif a.count('long') == 2 and 'int' in a: b = '%sint64' %u
        elif a.count('long') == 2: b = '%slonglong' %u
        elif 'long' in a: b = '%slong' %u
        elif 'double' in a: b = 'double'    # no udouble in ctypes
        elif 'short' in a: b = '%sshort' %u
        elif 'char' in a: b = '%schar' %u
        elif 'wchar' in a: b = 'wchar'
        elif 'bool' in a: b = 'bool'
        elif 'float' in a: b = 'float'

        elif 'int' in a: b = '%sint' %u
        elif 'int8' in a: b = 'int8'
        elif 'int16' in a: b = 'int16'
        elif 'int32' in a: b = 'int32'
        elif 'int64' in a: b = 'int64'

        elif 'uint' in a: b = 'uint'
        elif 'uint8' in a: b = 'uint8'
        elif 'uint16' in a: b = 'uint16'
        elif 'uint32' in a: b = 'uint32'
        elif 'uint64' in a: b = 'uint64'

        elif 'size_t' in a: b = 'size_t'
        elif 'void' in a: b = 'void_p'

        elif string in 'struct union'.split(): b = 'void_p'    # what should be done here? don't trust struct, it could be a class, no need to expose via ctypes
        else: b = 'void_p'

        if not pointers: return 'ctypes.c_%s' %b
        else:
            x = ''
            for i in range(pointers): x += 'ctypes.POINTER('
            x += 'ctypes.c_%s' %b
            x += ')' * pointers
            return x

    def resolve_type( self, string, result ):    # recursive
        '''
        keeps track of useful things like: how many pointers, number of typedefs, is fundamental or a class, etc...
        '''
        ## be careful with templates, what is inside <something*> can be a pointer but the overall type is not a pointer
        ## these come before a template
        s = string.split('<')[0]
        result[ 'constant' ] += s.split().count('const')
        result[ 'static' ] += s.split().count('static')
        result[ 'mutable' ] = 'mutable' in s.split()

        ## these come after a template
        s = string.split('>')[-1]
        result[ 'pointer' ] += s.count('*')
        result[ 'reference' ] += s.count('&')


        x = string; alias = False
        for a in '* & const static mutable'.split(): x = x.replace(a,'')
        for y in x.split():
            if y not in self.C_FUNDAMENTAL: alias = y; break

        #if alias == 'class':
        #    result['class'] = result['name']    # forward decl of class
        #    result['forward_decl'] = True
        if alias == '__extension__': result['fundamental_extension'] = True
        elif alias:
            result['aliases'].append( alias )
            if alias in C99_NONSTANDARD:
                result['type'] = C99_NONSTANDARD[ alias ]
                result['typedef'] = alias
                result['typedefs'] += 1
            elif alias in self.typedefs:
                result['typedefs'] += 1
                result['typedef'] = alias
                self.resolve_type( self.typedefs[alias], result )
            elif alias in self.classes:
                klass = self.classes[alias]; result['fundamental'] = False
                result['class'] = klass
                result['unresolved'] = False
            else: result['unresolved'] = True
        else:
            result['fundamental'] = True
            result['unresolved'] = False


    def finalize_vars(self):
        for s in CppStruct.Structs:    # vars within structs can be ignored if they do not resolve
            for var in s['fields']: var['parent'] = s['type']
        #for c in self.classes.values():
        #    for var in c.get_all_properties(): var['parent'] = c['name']

        ## RESOLVE ##
        for var in CppVariable.Vars:
            self.resolve_type( var['type'], var )
            #if 'method' in var and var['method']['name'] ==  '_notifyCurrentCamera': print(var); assert 0

        # then find concrete type and best guess ctypes type #
        for var in CppVariable.Vars:    
            if not var['aliases']:    #var['fundamental']:
                var['ctypes_type'] = self.guess_ctypes_type( var['type'] )
            else:
                var['unresolved'] = False    # below may test to True
                if var['class']:
                    var['ctypes_type'] = 'ctypes.c_void_p'
                else:
                    assert var['aliases']
                    tag = var['aliases'][0]

                    klass = None
                    nestedEnum = None
                    nestedStruct = None
                    nestedTypedef = None
                    if 'method' in var and 'parent' in list(var['method'].keys()):
                        klass = var['method']['parent']
                        if tag in var['method']['parent']._public_enums:
                            nestedEnum = var['method']['parent']._public_enums[ tag ]
                        elif tag in var['method']['parent']._public_structs:
                            nestedStruct = var['method']['parent']._public_structs[ tag ]
                        elif tag in var['method']['parent']._public_typedefs:
                            nestedTypedef = var['method']['parent']._public_typedefs[ tag ]


                    if '<' in tag:    # should also contain '>'
                        var['template'] = tag        # do not resolve templates
                        var['ctypes_type'] = 'ctypes.c_void_p'
                        var['unresolved'] = True

                    elif nestedEnum:
                        enum = nestedEnum
                        if enum['type'] is int:
                            var['ctypes_type'] = 'ctypes.c_int'
                            var['raw_type'] = 'int'

                        elif enum['type'] is str:
                            var['ctypes_type'] = 'ctypes.c_char_p'
                            var['raw_type'] = 'char*'

                        var['enum'] = var['method']['path'] + '::' + enum['name']
                        var['fundamental'] = True

                    elif nestedStruct:
                        var['ctypes_type'] = 'ctypes.c_void_p'
                        var['raw_type'] = var['method']['path'] + '::' + nestedStruct['type']
                        var['fundamental'] = False

                    elif nestedTypedef:
                        var['fundamental'] = is_fundamental( nestedTypedef )
                        if not var['fundamental']:
                            var['raw_type'] = var['method']['path'] + '::' + tag

                    else:
                        _tag = tag
                        if '::' in tag and tag.split('::')[0] in self.namespaces: tag = tag.split('::')[-1]
                        con = self.concrete_typedef( _tag )
                        if con:
                            var['concrete_type'] = con
                            var['ctypes_type'] = self.guess_ctypes_type( var['concrete_type'] )

                        elif tag in self.structs:
                            trace_print( 'STRUCT', var )
                            var['struct'] = tag
                            var['ctypes_type'] = 'ctypes.c_void_p'
                            var['raw_type'] = self.structs[tag]['namespace'] + '::' + tag

                        elif tag in self._forward_decls:
                            var['forward_declared'] = tag
                            var['ctypes_type'] = 'ctypes.c_void_p'

                        elif tag in self.global_enums:
                            enum = self.global_enums[ tag ]
                            if enum['type'] is int:
                                var['ctypes_type'] = 'ctypes.c_int'
                                var['raw_type'] = 'int'
                            elif enum['type'] is str:
                                var['ctypes_type'] = 'ctypes.c_char_p'
                                var['raw_type'] = 'char*'
                            var['enum'] = enum['namespace'] + enum['name']
                            var['fundamental'] = True


                        elif var['parent']:
                            warning_print( 'WARN unresolved %s'%_tag)
                            var['ctypes_type'] = 'ctypes.c_void_p'
                            var['unresolved'] = True


                        elif tag.count('::')==1:
                            trace_print( 'trying to find nested something in', tag )
                            a = tag.split('::')[0]
                            b = tag.split('::')[-1]
                            if a in self.classes:    # a::b is most likely something nested in a class
                                klass = self.classes[ a ]
                                if b in klass._public_enums:
                                    trace_print( '...found nested enum', b )
                                    enum = klass._public_enums[ b ]
                                    if enum['type'] is int:
                                        var['ctypes_type'] = 'ctypes.c_int'
                                        var['raw_type'] = 'int'
                                    elif enum['type'] is str:
                                        var['ctypes_type'] = 'ctypes.c_char_p'
                                        var['raw_type'] = 'char*'
                                    try:
                                        if 'method' in var: var['enum'] = var['method']['path'] + '::' + enum['name']
                                        else:    # class property
                                            var['unresolved'] = True
                                    except:
                                        var['unresolved'] = True
                                        
                                    var['fundamental'] = True

                                else: var['unresolved'] = True    # TODO klass._public_xxx

                            elif a in self.namespaces:    # a::b can also be a nested namespace
                                if b in self.global_enums:
                                    enum = self.global_enums[ b ]
                                    trace_print(enum)
                                trace_print(var)
                                assert 0

                            elif b in self.global_enums:        # falling back, this is a big ugly
                                enum = self.global_enums[ b ]
                                assert a in enum['namespace'].split('::')
                                if enum['type'] is int:
                                    var['ctypes_type'] = 'ctypes.c_int'
                                    var['raw_type'] = 'int'
                                elif enum['type'] is str:
                                    var['ctypes_type'] = 'ctypes.c_char_p'
                                    var['raw_type'] = 'char*'
                                var['fundamental'] = True

                            else:    # boost::gets::crazy
                                trace_print('NAMESPACES', self.namespaces)
                                trace_print( a, b )
                                trace_print( '---- boost gets crazy ----' )
                                var['ctypes_type'] = 'ctypes.c_void_p'
                                var['unresolved'] = True


                        elif 'namespace' in var and self.concrete_typedef(var['namespace']+tag):
                            #print( 'TRYING WITH NS', var['namespace'] )
                            con = self.concrete_typedef( var['namespace']+tag )
                            if con:
                                var['typedef'] = var['namespace']+tag
                                var['type'] = con
                                if 'struct' in con.split():
                                    var['raw_type'] = var['typedef']
                                    var['ctypes_type'] = 'ctypes.c_void_p'
                                else:
                                    self.resolve_type( var['type'], var )
                                    var['ctypes_type'] = self.guess_ctypes_type( var['type'] )

                        elif '::' in var:
                            var['ctypes_type'] = 'ctypes.c_void_p'
                            var['unresolved'] = True

                        elif tag in self.SubTypedefs:    # TODO remove SubTypedefs
                            if 'property_of_class' in var or 'property_of_struct' in var:
                                trace_print( 'class:', self.SubTypedefs[ tag ], 'tag:', tag )
                                var['typedef'] = self.SubTypedefs[ tag ]    # class name
                                var['ctypes_type'] = 'ctypes.c_void_p'
                            else:
                                trace_print( "WARN-this should almost never happen!" )
                                trace_print( var ); trace_print('-'*80)
                                var['unresolved'] = True

                        elif tag in self._template_typenames:
                            var['typename'] = tag
                            var['ctypes_type'] = 'ctypes.c_void_p'
                            var['unresolved'] = True    # TODO, how to deal with templates?

                        elif tag.startswith('_'):    # assume starting with underscore is not important for wrapping
                            warning_print( 'WARN unresolved %s'%_tag)
                            var['ctypes_type'] = 'ctypes.c_void_p'
                            var['unresolved'] = True

                        else:
                            trace_print( 'WARN: unknown type', var )
                            assert 'property_of_class' in var or 'property_of_struct'    # only allow this case
                            var['unresolved'] = True


                    ## if not resolved and is a method param, not going to wrap these methods  ##
                    if var['unresolved'] and 'method' in var: var['method']['unresolved_parameters'] = True


        # create stripped raw_type #
        p = '* & const static mutable'.split()        # +++ new July7: "mutable"
        for var in CppVariable.Vars:
            if 'raw_type' not in var:
                raw = []
                for x in var['type'].split():
                    if x not in p: raw.append( x )
                var['raw_type'] = ' '.join( raw )

                #if 'AutoConstantEntry' in var['raw_type']: print(var); assert 0
                if var['class']:
                    if '::' not in var['raw_type']:
                        if not var['class']['parent']:
                            var['raw_type'] = var['class']['namespace'] + '::' + var['raw_type']
                        elif var['class']['parent'] in self.classes:
                            parent = self.classes[ var['class']['parent'] ]
                            var['raw_type'] = parent['namespace'] + '::' + var['class']['name'] + '::' + var['raw_type']
                        else:
                            var['unresolved'] = True

                    elif '::' in var['raw_type'] and var['raw_type'].split('::')[0] not in self.namespaces:
                        var['raw_type'] = var['class']['namespace'] + '::' + var['raw_type']
                    else:
                        var['unresolved'] = True

                elif 'forward_declared' in var and 'namespace' in var:
                    if '::' not in var['raw_type']:
                        var['raw_type'] = var['namespace'] + var['raw_type']
                    elif '::' in var['raw_type'] and var['raw_type'].split('::')[0] in self.namespaces:
                        pass
                    else: trace_print('-'*80); trace_print(var); raise NotImplemented


            ## need full name space for classes in raw type ##
            if var['raw_type'].startswith( '::' ):
                #print(var)
                #print('NAMESPACE', var['class']['namespace'])
                #print( 'PARENT NS', var['class']['parent']['namespace'] )
                #assert 0
                var['unresolved'] = True
                if 'method' in var: var['method']['unresolved_parameters'] = True
                #var['raw_type'] = var['raw_type'][2:]
        
        # Take care of #defines and #pragmas etc
        trace_print("Processing precomp_macro_buf: %s"%self._precomp_macro_buf)
        for m in self._precomp_macro_buf:
            macro = m.replace("<CppHeaderParser_newline_temp_replacement>\\n", "\n")
            try:
                if macro.lower().startswith("#define"):
                    trace_print("Adding #define %s"%macro)
                    self.defines.append(re.split("[\t ]+", macro, 1)[1].strip())
                elif macro.lower().startswith("#pragma"):
                    trace_print("Adding #pragma %s"%macro)
                    self.pragmas.append(re.split("[\t ]+", macro, 1)[1].strip())
                elif macro.lower().startswith("#include"):
                    trace_print("Adding #include %s"%macro)
                    self.includes.append(re.split("[\t ]+", macro, 1)[1].strip())
                else:
                    debug_print("Cant detect what to do with precomp macro '%s'"%macro)
            except: pass
        self._precomp_macro_buf = None
        

    def concrete_typedef( self, key ):
        if key not in self.typedefs:
            #print( 'FAILED typedef', key )
            return None
        while key in self.typedefs:
            prev = key
            key = self.typedefs[ key ]
            if '<' in key or '>' in key: return prev        # stop at template
            if key.startswith('std::'): return key        # stop at std lib
        return key


class _CppHeader( Resolver ):
    def finalize(self):
        self.finalize_vars()
        # finalize classes and method returns types
        for cls in list(self.classes.values()):
            for meth in cls.get_all_methods():
                if meth['pure_virtual']: cls['abstract'] = True

                if not meth['returns_fundamental'] and meth['returns'] in C99_NONSTANDARD:
                    meth['returns'] = C99_NONSTANDARD[meth['returns']]
                    meth['returns_fundamental'] = True

                elif not meth['returns_fundamental']:    # describe the return type
                    con = None
                    if cls['namespace'] and '::' not in meth['returns']:
                        con = self.concrete_typedef( cls['namespace'] + '::' + meth['returns'] )
                    else: con = self.concrete_typedef( meth['returns'] )


                    if con:
                        meth['returns_concrete'] = con
                        meth['returns_fundamental'] = is_fundamental( con )

                    elif meth['returns'] in self.classes:
                        trace_print( 'meth returns class:', meth['returns'] )
                        meth['returns_class'] = True

                    elif meth['returns'] in self.SubTypedefs:
                        meth['returns_class'] = True
                        meth['returns_nested'] = self.SubTypedefs[ meth['returns'] ]

                    elif meth['returns'] in cls._public_enums:
                        enum = cls._public_enums[ meth['returns'] ]
                        meth['returns_enum'] = enum['type']
                        meth['returns_fundamental'] = True
                        if enum['type'] == int: meth['returns'] = 'int'
                        else: meth['returns'] = 'char*'

                    elif meth['returns'] in self.global_enums:
                        enum = self.global_enums[ meth['returns'] ]
                        meth['returns_enum'] = enum['type']
                        meth['returns_fundamental'] = True
                        if enum['type'] == int: meth['returns'] = 'int'
                        else: meth['returns'] = 'char*'

                    elif meth['returns'].count('::')==1:
                        trace_print( meth )
                        a,b = meth['returns'].split('::')
                        if a in self.namespaces:
                            if b in self.classes:
                                klass = self.classes[ b ]
                                meth['returns_class'] = a + '::' + b
                            elif '<' in b and '>' in b:
                                warning_print( 'WARN-can not return template: %s'%b )
                                meth['returns_unknown'] = True
                            elif b in self.global_enums:
                                enum = self.global_enums[ b ]
                                meth['returns_enum'] = enum['type']
                                meth['returns_fundamental'] = True
                                if enum['type'] == int: meth['returns'] = 'int'
                                else: meth['returns'] = 'char*'

                            else: trace_print( a, b); trace_print( meth); meth['returns_unknown'] = True    # +++

                        elif a in self.classes:
                            klass = self.classes[ a ]
                            if b in klass._public_enums:
                                trace_print( '...found nested enum', b )
                                enum = klass._public_enums[ b ]
                                meth['returns_enum'] = enum['type']
                                meth['returns_fundamental'] = True
                                if enum['type'] == int: meth['returns'] = 'int'
                                else: meth['returns'] = 'char*'

                            elif b in klass._public_forward_declares:
                                meth['returns_class'] = True

                            elif b in klass._public_typedefs:
                                typedef = klass._public_typedefs[ b ]
                                meth['returns_fundamental'] = is_fundamental( typedef )

                            else:
                                trace_print( meth )    # should be a nested class, TODO fix me.
                                meth['returns_unknown'] = True

                    elif '::' in meth['returns']:
                        trace_print('TODO namespace or extra nested return:', meth)
                        meth['returns_unknown'] = True
                    else:
                        trace_print( 'WARN: UNKNOWN RETURN', meth['name'], meth['returns'])
                        meth['returns_unknown'] = True
        
                if meth["returns"].startswith(": : "):
                    meth["returns"] = meth["returns"].replace(": : ", "::")
        
        for cls in list(self.classes.values()):
            methnames = cls.get_all_method_names()
            pvm = cls.get_all_pure_virtual_methods()

            for d in cls['inherits']:
                c = d['class']
                a = d['access']    # do not depend on this to be 'public'
                trace_print( 'PARENT CLASS:', c )
                if c not in self.classes: trace_print('WARN: parent class not found')
                if c in self.classes and self.classes[c]['abstract']:
                    p = self.classes[ c ]
                    for meth in p.get_all_methods():    #p["methods"]["public"]:
                        trace_print( '\t\tmeth', meth['name'], 'pure virtual', meth['pure_virtual'] )
                        if meth['pure_virtual'] and meth['name'] not in methnames: cls['abstract'] = True; break





    def evaluate_struct_stack(self):
        """Create a Struct out of the name stack (but not its parts)"""
        #print( 'eval struct stack', self.nameStack )
        #if self.braceDepth != len(self.nameSpaces): return
        struct = CppStruct(self.nameStack)
        struct["namespace"] = self.cur_namespace()
        self.structs[ struct['type'] ] = struct
        self.structs_order.append( struct )
        if self.curClass:
            struct['parent'] = self.curClass
            klass = self.classes[ self.curClass ]
            klass['structs'][self.curAccessSpecifier].append( struct )
            if self.curAccessSpecifier == 'public': klass._public_structs[ struct['type'] ] = struct
        self.curStruct = struct
        self._structs_brace_level[ struct['type'] ] = self.braceDepth

    
    def parse_method_type( self, stack ):
        trace_print( 'meth type info', stack )
        if stack[0] in ':;' and stack[1] != ':': stack = stack[1:]
        info = { 
            'debug': ' '.join(stack).replace(' : : ', '::' ).replace(' < ', '<' ).replace(' > ', '> ' ).replace(" >",">").replace(">>", "> >").replace(">>", "> >"), 
            'class':None, 
            'namespace':self.cur_namespace(add_double_colon=True),
        }

        for tag in 'defined pure_virtual operator constructor destructor extern template virtual static explicit inline friend returns returns_pointer returns_fundamental returns_class'.split(): info[tag]=False
        header = stack[ : stack.index('(') ]
        header = ' '.join( header )
        header = header.replace(' : : ', '::' )
        header = header.replace(' < ', '<' )
        header = header.replace(' > ', '> ' )
        header = header.strip()

        if '{' in stack:
            info['defined'] = True
            self._method_body = self.braceDepth + 1
            trace_print( 'NEW METHOD WITH BODY', self.braceDepth )
        elif stack[-1] == ';':
            info['defined'] = False
            self._method_body = None    # not a great idea to be clearing here
        else: assert 0

        if len(stack) > 3 and stack[-1] == ';' and stack[-2] == '0' and stack[-3] == '=':
            info['pure_virtual'] = True

        r = header.split()
        name = None
        if 'operator' in stack:    # rare case op overload defined outside of class
            op = stack[ stack.index('operator')+1 : stack.index('(') ]
            op = ''.join(op)
            if not op:
                if " ".join(['operator', '(', ')', '(']) in " ".join(stack):
                    op = "()"
                else:
                    trace_print( 'Error parsing operator')
                    return None
            
            info['operator'] = op
            name = 'operator' + op
            a = stack[ : stack.index('operator') ]

        elif r:
            name = r[-1]
            a = r[ : -1 ]    # strip name

        if name is None: return None
        #if name.startswith('~'): name = name[1:]

        while a and a[0] == '}':    # strip - can have multiple } }
            a = a[1:]


        if '::' in name:
            #klass,name = name.split('::')    # methods can be defined outside of class
            klass = name[ : name.rindex('::') ]
            name = name.split('::')[-1]
            info['class'] = klass
            if klass in self.classes and not self.curClass:
                 #Class function defined outside the class
                return None
        #    info['name'] = name
        #else: info['name'] = name

        if name.startswith('~'):
            info['destructor'] = True
            name = name[1:]
        elif not a or (name == self.curClass and len(self.curClass)):
            info['constructor'] = True

        info['name'] = name

        for tag in 'extern virtual static explicit inline friend'.split():
            if tag in a: info[ tag ] = True; a.remove( tag )    # inplace
        if 'template' in a:
            a.remove('template')
            b = ' '.join( a )
            if '>' in b:
                info['template'] = b[ : b.index('>')+1 ]
                info['returns'] = b[ b.index('>')+1 : ]    # find return type, could be incorrect... TODO
                if '<typename' in info['template'].split():
                    typname = info['template'].split()[-1]
                    typname = typname[ : -1 ]    # strip '>'
                    if typname not in self._template_typenames: self._template_typenames.append( typname )
            else: info['returns'] = ' '.join( a )
        else: info['returns'] = ' '.join( a )
        info['returns'] = info['returns'].replace(' <', '<').strip()

        ## be careful with templates, do not count pointers inside template
        info['returns_pointer'] = info['returns'].split('>')[-1].count('*')
        if info['returns_pointer']: info['returns'] = info['returns'].replace('*','').strip()

        info['returns_reference'] = '&' in info['returns']
        if info['returns']: info['returns'] = info['returns'].replace('&','').strip()

        a = []
        for b in info['returns'].split():
            if b == '__const__': info['returns_const'] = True
            elif b == 'const': info['returns_const'] = True
            else: a.append( b )
        info['returns'] = ' '.join( a )

        info['returns_fundamental'] = is_fundamental( info['returns'] )
        return info

    def evaluate_method_stack(self):
        """Create a method out of the name stack"""

        if self.curStruct:
            trace_print( 'WARN - struct contains methods - skipping' )
            trace_print( self.stack )
            assert 0
        
        info = self.parse_method_type( self.stack )
        if info:
            if info[ 'class' ] and info['class'] in self.classes:     # case where methods are defined outside of class
                newMethod = CppMethod(self.nameStack, info['name'], info, self.curTemplate)
                klass = self.classes[ info['class'] ]
                klass[ 'methods' ][ 'public' ].append( newMethod )
                newMethod['parent'] = klass
                if klass['namespace']: newMethod['path'] = klass['namespace'] + '::' + klass['name']
                else: newMethod['path'] = klass['name']
                
            elif self.curClass:    # normal case
                newMethod = CppMethod(self.nameStack, self.curClass, info, self.curTemplate)
                klass = self.classes[self.curClass]
                klass['methods'][self.curAccessSpecifier].append(newMethod)
                newMethod['parent'] = klass
                if klass['namespace']: newMethod['path'] = klass['namespace'] + '::' + klass['name']
                else: newMethod['path'] = klass['name']
            else: #non class functions
                debug_print("FREE FUNCTION")
                newMethod = CppMethod(self.nameStack, None, info, self.curTemplate)
                self.functions.append(newMethod)
            global parseHistory
            parseHistory.append({"braceDepth": self.braceDepth, "item_type": "method", "item": newMethod})
        else:
            trace_print( 'free function?', self.nameStack )

        self.stack = []

    def _parse_typedef( self, stack, namespace='' ):
        if not stack or 'typedef' not in stack: return
        stack = list( stack )    # copy just to be safe
        if stack[-1] == ';': stack.pop()

        while stack and stack[-1].isdigit(): stack.pop()    # throw away array size for now

        idx = stack.index('typedef')
        if stack[-1] == "]":
            try:
                name = namespace + "".join(stack[-4:])
                # Strip off the array part so the rest of the parsing is better
                stack = stack[:-3]
            except:
                name = namespace + stack[-1]
        else:
            name = namespace + stack[-1]
        s = ''
        for a in stack[idx+1:-1]:
            if a == '{': break
            if not s or s[-1] in ':<>' or a in ':<>': s += a    # keep compact
            else: s += ' ' + a    # spacing

        r = {'name':name, 'raw':s, 'type':s}
        if not is_fundamental(s):
            if 'struct' in s.split(): pass        # TODO is this right? "struct ns::something"
            elif '::' not in s: s = namespace + s         # only add the current name space if no namespace given
            r['type'] = s
        if s: return r


    def evaluate_typedef(self):
        ns = self.cur_namespace(add_double_colon=True)
        res = self._parse_typedef( self.stack, ns )
        if res:
            name = res['name']
            self.typedefs[ name ] = res['type']
            if name not in self.typedefs_order: self.typedefs_order.append( name )


    def evaluate_property_stack(self):
        """Create a Property out of the name stack"""
        global parseHistory
        assert self.stack[-1] == ';'
        debug_print( "trace" )
        if self.nameStack[0] == 'typedef':
            if self.curClass:
                typedef = self._parse_typedef( self.stack )
                name = typedef['name']
                klass = self.classes[ self.curClass ]
                klass[ 'typedefs' ][ self.curAccessSpecifier ].append( name )
                if self.curAccessSpecifier == 'public': klass._public_typedefs[ name ] = typedef['type']
                Resolver.SubTypedefs[ name ] = self.curClass
            else: assert 0
        elif self.curStruct or self.curClass:
            if len(self.nameStack) == 1:
                #See if we can de anonymize the type
                filteredParseHistory = [h for h in parseHistory if h["braceDepth"] == self.braceDepth]
                if len(filteredParseHistory) and filteredParseHistory[-1]["item_type"] == "class":
                    self.nameStack.insert(0, filteredParseHistory[-1]["item"]["name"])
                    debug_print("DEANONYMOIZING %s to type '%s'"%(self.nameStack[1], self.nameStack[0]))
            if "," in self.nameStack: #Maybe we have a variable list
                #Figure out what part is the variable separator but remember templates of function pointer
                #First find left most comma outside of a > and )
                leftMostComma = 0;
                for i in range(0, len(self.nameStack)):
                    name = self.nameStack[i]
                    if name in (">", ")"): leftMostComma = 0
                    if leftMostComma == 0 and name == ",": leftMostComma = i
                # Is it really a list of variables?
                if leftMostComma != 0:
                    trace_print("Multiple variables for namestack in %s.  Separating processing"%self.nameStack)
                    orig_nameStack = self.nameStack[:]
                    orig_stack = self.stack[:]
                    
                    type_nameStack = orig_nameStack[:leftMostComma-1]
                    for name in orig_nameStack[leftMostComma - 1::2]:
                        self.nameStack = type_nameStack + [name]
                        self.stack = orig_stack[:] # Not maintained for mucking, but this path it doesnt matter
                        self.evaluate_property_stack()
                    return
            
            newVar = CppVariable(self.nameStack)
            newVar['namespace'] = self.current_namespace()
            if self.curStruct:
                self.curStruct[ 'fields' ].append( newVar )
                newVar['property_of_struct'] = self.curStruct
            elif self.curClass:
                klass = self.classes[self.curClass]
                klass["properties"][self.curAccessSpecifier].append(newVar)
                newVar['property_of_class'] = klass['name']
            parseHistory.append({"braceDepth": self.braceDepth, "item_type": "variable", "item": newVar})
        else:
            debug_print( "Found Global variable" )
            newVar = CppVariable(self.nameStack)
            self.variables.append(newVar)

        self.stack = []        # CLEAR STACK

    def evaluate_class_stack(self):
        """Create a Class out of the name stack (but not its parts)"""
        #dont support sub classes today
        #print( 'eval class stack', self.nameStack )
        parent = self.curClass
        if self.braceDepth > len( self.nameSpaces) and parent:
            trace_print( 'HIT NESTED SUBCLASS' )
            self.accessSpecifierStack.append(self.curAccessSpecifier)
        elif self.braceDepth != len(self.nameSpaces):
            error_print( 'ERROR: WRONG BRACE DEPTH' )
            return
        
        # When dealing with typedefed structs, get rid of typedef keyword to handle later on
        if self.nameStack[0] == "typedef":
            del self.nameStack[0]
            if len(self.nameStack) == 1:
                self.anon_struct_counter += 1
                # We cant handle more than 1 anonymous struct, so name them uniquely
                self.nameStack.append("<anon-struct-%d>"%self.anon_struct_counter)
        
        if self.nameStack[0] == "class":
            self.curAccessSpecifier = 'private'
        else:#struct
            self.curAccessSpecifier = 'public'
        debug_print("curAccessSpecifier changed/defaulted to %s"%self.curAccessSpecifier)
        if self.nameStack[0] == "union":
            newClass = CppUnion(self.nameStack)
            if newClass['name'] == 'union ':
                self.anon_union_counter = [self.braceDepth, 2]
            else:
                self.anon_union_counter = [self.braceDepth, 1]
            trace_print( 'NEW UNION', newClass['name'] )
        else:
            newClass = CppClass(self.nameStack, self.curTemplate)
            trace_print( 'NEW CLASS', newClass['name'] )
        newClass["declaration_method"] = self.nameStack[0]
        self.classes_order.append( newClass )    # good idea to save ordering
        self.stack = []        # fixes if class declared with ';' in closing brace
        if parent:
            newClass["namespace"] = self.classes[ parent ]['namespace'] + '::' + parent
            newClass['parent'] = parent
            self.classes[ parent ]['nested_classes'].append( newClass )
            ## supports nested classes with the same name ##
            self.curClass = key = parent+'::'+newClass['name']
            self._classes_brace_level[ key ] = self.braceDepth

        elif newClass['parent']:        # nested class defined outside of parent.  A::B {...}
            parent = newClass['parent']
            newClass["namespace"] = self.classes[ parent ]['namespace'] + '::' + parent
            self.classes[ parent ]['nested_classes'].append( newClass )
            ## supports nested classes with the same name ##
            self.curClass = key = parent+'::'+newClass['name']
            self._classes_brace_level[ key ] = self.braceDepth

        else:
            newClass["namespace"] = self.cur_namespace()
            key = newClass['name']
            self.curClass = newClass["name"]
            self._classes_brace_level[ newClass['name'] ] = self.braceDepth

        if not key.endswith("::") and not key.endswith(" ") and len(key) != 0:
            if key in self.classes:
                trace_print( 'ERROR name collision:', key )
                self.classes[key].show()
                trace_print('-'*80)
                newClass.show()            
                assert key not in self.classes    # namespace collision
        self.classes[ key ] = newClass
        global parseHistory
        parseHistory.append({"braceDepth": self.braceDepth, "item_type": "class", "item": newClass})
    

    def evalute_forward_decl(self):
        trace_print( 'FORWARD DECL', self.nameStack )
        assert self.nameStack[0] in ('class', 'struct')
        name = self.nameStack[-1]
        if self.curClass:
            klass = self.classes[ self.curClass ]
            klass['forward_declares'][self.curAccessSpecifier].append( name )
            if self.curAccessSpecifier == 'public': klass._public_forward_declares.append( name )
        else: self._forward_decls.append( name )

class CppHeader( _CppHeader ):
    """Parsed C++ class header
    
    Variables produced:
    self.classes - Dictionary of classes found in a given header file where the
        key is the name of the class
    """
    IGNORE_NAMES = '__extension__'.split()
   
    def show(self):
        for className in list(self.classes.keys()):self.classes[className].show()

    def __init__(self, headerFileName, argType="file", **kwargs):
        """Create the parsed C++ header file parse tree
        
        headerFileName - Name of the file to parse OR actual file contents (depends on argType)
        argType - Indicates how to interpret headerFileName as a file string or file name
        kwargs - Supports the following keywords
        """
        ## reset global state ##
        global doxygenCommentCache
        doxygenCommentCache = ""
        CppVariable.Vars = []
        CppStruct.Structs = []

        if (argType == "file"):
            self.headerFileName = os.path.expandvars(headerFileName)
            self.mainClass = os.path.split(self.headerFileName)[1][:-2]
            headerFileStr = ""
        elif argType == "string":
            self.headerFileName = ""
            self.mainClass = "???"
            headerFileStr = headerFileName
        else:
            raise Exception("Arg type must be either file or string")
        self.curClass = ""
       
        # nested classes have parent::nested, but no extra namespace,
        # this keeps the API compatible, TODO proper namespace for everything. 
        Resolver.CLASSES = {}
        self.classes = Resolver.CLASSES
        #Functions that are not part of a class
        self.functions = []
        
        self.pragmas = []
        self.defines = []
        self.includes = []
        self._precomp_macro_buf = [] #for internal purposes, will end up filling out pragmras and defines at the end

        self.enums = []
        self.variables = []
        self.global_enums = {}
        self.nameStack = []
        self.nameSpaces = []
        self.curAccessSpecifier = 'private'    # private is default
        self.curTemplate = None
        self.accessSpecifierStack = []
        self.accessSpecifierScratch = []
        debug_print("curAccessSpecifier changed/defaulted to %s"%self.curAccessSpecifier)
        self.initextra()
        # Old namestacks for a given level
        self.nameStackHistory = []
        self.anon_struct_counter = 0    
        self.anon_union_counter = [-1, 0]
        self.templateRegistry = []
    
        if (len(self.headerFileName)):
            fd = open(self.headerFileName)
            headerFileStr = "".join(fd.readlines())
            fd.close()     
        
        # Make sure supportedAccessSpecifier are sane
        for i in range(0, len(supportedAccessSpecifier)):
            if " " not in supportedAccessSpecifier[i]: continue
            supportedAccessSpecifier[i] = re.sub("[ ]+", " ", supportedAccessSpecifier[i]).strip()
        
        # Strip out template declarations
        templateSectionsToSliceOut = []
        try:
            for m in re.finditer("template[\t ]*<[^>]*>", headerFileStr):
                start = m.start()
                # Search for the final '>' which may or may not be caught in the case of nexted <>'s
                for i in range(start, len(headerFileStr)):
                    if headerFileStr[i] == '<':
                        firstBracket = i
                        break
                ltgtStackCount = 1
                #Now look for fianl '>'
                for i in range(firstBracket + 1, len(headerFileStr)):
                    if headerFileStr[i] == '<':
                        ltgtStackCount += 1
                    elif headerFileStr[i] == '>':
                        ltgtStackCount -= 1
                    if ltgtStackCount == 0:
                        end = i
                        break
                templateSectionsToSliceOut.append((start, end))
            
            # Now strip out all instances of the template
            templateSectionsToSliceOut.reverse()
            for tslice in templateSectionsToSliceOut:
                # Replace the template symbol with a single symbol
                template_symbol="CppHeaderParser_template_%d"%len(self.templateRegistry)
                self.templateRegistry.append(headerFileStr[tslice[0]: tslice[1]+1])
                newlines = headerFileStr[tslice[0]: tslice[1]].count("\n") * "\n" #Keep line numbers the same
                headerFileStr = headerFileStr[:tslice[0]] + newlines + " " + template_symbol + " " + headerFileStr[tslice[1] + 1:]
        except:
            pass

        # Change multi line #defines and expressions to single lines maintaining line nubmers
        # Based from http://stackoverflow.com/questions/2424458/regular-expression-to-match-cs-multiline-preprocessor-statements
        matches = re.findall(r'(?m)^(?:.*\\\r?\n)+.*$', headerFileStr)
        is_define = re.compile(r'[ \t\v]*#[Dd][Ee][Ff][Ii][Nn][Ee]')
        for m in matches:
            #Keep the newlines so that linecount doesnt break
            num_newlines = len([a for a in m if a=="\n"])
            if is_define.match(m):
                new_m = m.replace("\n", "<CppHeaderParser_newline_temp_replacement>\\n")
            else:
                # Just expression taking up multiple lines, make it take 1 line for easier parsing
                new_m = m.replace("\\\n", " ")
            if (num_newlines > 0):
                new_m += "\n"*(num_newlines)
            headerFileStr = headerFileStr.replace(m, new_m)
        
        #Filter out Extern "C" statements.  These are order dependent
        matches = re.findall(re.compile(r'extern[\t ]+"[Cc]"[\t \n\r]*{', re.DOTALL), headerFileStr)
        for m in matches:
            #Keep the newlines so that linecount doesnt break
            num_newlines = len([a for a in m if a=="\n"])
            headerFileStr = headerFileStr.replace(m, "\n" * num_newlines)        
        headerFileStr = re.sub(r'extern[ ]+"[Cc]"[ ]*', "", headerFileStr)
                
        #Filter out any ignore symbols that end with "()" to account for #define magic functions
        for ignore in ignoreSymbols:
            if not ignore.endswith("()"): continue
            while True:
                locStart = headerFileStr.find(ignore[:-1])
                if locStart == -1:
                    break;
                locEnd = None
                #Now walk till we find the last paren and account for sub parens
                parenCount = 1
                inQuotes = False
                for i in range(locStart + len(ignore) - 1, len(headerFileStr)):
                    c = headerFileStr[i]
                    if not inQuotes:
                        if c == "(":
                            parenCount += 1
                        elif c == ")":
                            parenCount -= 1
                        elif c == '"':
                            inQuotes = True
                        if parenCount == 0:
                            locEnd = i + 1
                            break;
                    else:
                        if c == '"' and headerFileStr[i-1] != '\\':
                            inQuotes = False
                        
                if locEnd:
                    #Strip it out but keep the linecount the same so line numbers are right
                    match_str = headerFileStr[locStart:locEnd]
                    debug_print("Striping out '%s'"%match_str)
                    num_newlines = len([a for a in match_str if a=="\n"])
                    headerFileStr = headerFileStr.replace(headerFileStr[locStart:locEnd], "\n"*num_newlines)
        
        self.braceDepth = 0
        lex.lex()
        lex.input(headerFileStr)
        global curLine
        global curChar
        curLine = 0
        curChar = 0
        try:
            while True:
                tok = lex.token()
                if not tok: break
                if self.anon_union_counter[0] == self.braceDepth and self.anon_union_counter[1]:
                    self.anon_union_counter[1] -= 1
                tok.value = TagStr(tok.value, lineno=tok.lineno)
                #debug_print("TOK: %s"%tok)
                if tok.type == 'NAME' and tok.value in self.IGNORE_NAMES: continue
                if tok.type != 'TEMPLATE_NAME':
                    self.stack.append( tok.value )
                curLine = tok.lineno
                curChar = tok.lexpos
                if (tok.type in ('PRECOMP_MACRO', 'PRECOMP_MACRO_CONT')):
                    debug_print("PRECOMP: %s"%tok)
                    self._precomp_macro_buf.append(tok.value)
                    self.stack = []
                    self.nameStack = []
                    continue
                if tok.type == 'TEMPLATE_NAME':
                    try:
                        templateId = int(tok.value.replace("CppHeaderParser_template_",""))
                        self.curTemplate = self.templateRegistry[templateId]
                    except: pass 
                if (tok.type == 'OPEN_BRACE'):
                    if len(self.nameStack) >= 2 and is_namespace(self.nameStack):    # namespace {} with no name used in boost, this sets default?
                        if self.nameStack[1] == "__IGNORED_NAMESPACE__CppHeaderParser__":#Used in filtering extern "C"
                            self.nameStack[1] = ""
                        self.nameSpaces.append(self.nameStack[1])
                        ns = self.cur_namespace(); self.stack = []
                        if ns not in self.namespaces: self.namespaces.append( ns )
                    # Detect special condition of macro magic before class declaration so we
                    # can filter it out
                    if 'class' in self.nameStack and self.nameStack[0] != 'class':
                        classLocationNS = self.nameStack.index("class")
                        classLocationS = self.stack.index("class")
                        if "(" not in self.nameStack[classLocationNS:]:
                            debug_print("keyword 'class' found in unexpected location in nameStack, must be following #define magic.  Process that before moving on")
                            origNameStack = self.nameStack
                            origStack = self.stack
                            #Process first part of stack which is probably #define macro magic and may cause issues
                            self.nameStack = self.nameStack[:classLocationNS]
                            self.stack = self.stack[:classLocationS]
                            try:
                                self.evaluate_stack()
                            except:
                                debug_print("Error processing #define magic... Oh well")
                            #Process rest of stack
                            self.nameStack = origNameStack[classLocationNS:]
                            self.stack = origStack[classLocationS:]
                        
                    
                    if len(self.nameStack) and not is_enum_namestack(self.nameStack):
                        self.evaluate_stack()
                    else:
                        self.nameStack.append(tok.value)
                    if self.stack and self.stack[0] == 'class': self.stack = []
                    self.braceDepth += 1
                    
                elif (tok.type == 'CLOSE_BRACE'):
                    if self.braceDepth == 0:
                        continue
                    if (self.braceDepth == len(self.nameSpaces)):
                        tmp = self.nameSpaces.pop()
                        self.stack = []    # clear stack when namespace ends?
                    if len(self.nameStack) and is_enum_namestack(self.nameStack):
                        self.nameStack.append(tok.value)
                    elif self.braceDepth < 10:
                        self.evaluate_stack()
                    else:
                        self.nameStack = []
                    self.braceDepth -= 1
                    #self.stack = []; print 'BRACE DEPTH', self.braceDepth, 'NS', len(self.nameSpaces)
                    if self.curClass: debug_print( 'CURBD %s'%self._classes_brace_level[ self.curClass ] )

                    if (self.braceDepth == 0) or (self.curClass and self._classes_brace_level[self.curClass]==self.braceDepth):
                        trace_print( 'END OF CLASS DEF' )
                        if self.accessSpecifierStack:
                            self.curAccessSpecifier = self.accessSpecifierStack[-1]
                            self.accessSpecifierStack = self.accessSpecifierStack[:-1] 
                        if self.curClass and self.classes[ self.curClass ]['parent']: self.curClass = self.classes[ self.curClass ]['parent']
                        else: self.curClass = ""; #self.curStruct = None
                        self.stack = []

                    #if self.curStruct: self.curStruct = None
                    if self.braceDepth == 0 or (self.curStruct and self._structs_brace_level[self.curStruct['type']]==self.braceDepth):
                        trace_print( 'END OF STRUCT DEF' )
                        self.curStruct = None

                    if self._method_body and (self.braceDepth + 1) <= self._method_body:
                        self._method_body = None; self.stack = []; self.nameStack = []; trace_print( 'FORCE CLEAR METHBODY' )
                
                if (tok.type == 'OPEN_PAREN'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'CLOSE_PAREN'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'OPEN_SQUARE_BRACKET'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'CLOSE_SQUARE_BRACKET'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'TAB'): pass
                elif (tok.type == 'EQUALS'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'COMMA'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'BACKSLASH'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'DIVIDE'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'PIPE'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'PERCENT'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'CARET'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'EXCLAMATION'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'SQUOTE'): pass
                elif (tok.type == 'NUMBER' or tok.type == 'FLOAT_NUMBER'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'MINUS'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'PLUS'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'STRING_LITERAL'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'NAME' or tok.type == 'AMPERSTAND' or tok.type == 'ASTERISK' or tok.type == 'CHAR_LITERAL'):
                    if tok.value in ignoreSymbols:
                        debug_print("Ignore symbol %s"%tok.value)
                    elif (tok.value == 'class'):
                        self.nameStack.append(tok.value)
                    elif tok.value in supportedAccessSpecifier:
                        if len(self.nameStack) and self.nameStack[0] in ("class", "struct", "union"):
                            self.nameStack.append(tok.value)
                        elif self.braceDepth == len(self.nameSpaces) + 1 or self.braceDepth == (len(self.nameSpaces) + len(self.curClass.split("::"))):
                            self.curAccessSpecifier = tok.value;
                            self.accessSpecifierScratch.append(tok.value)
                            debug_print("curAccessSpecifier updated to %s"%self.curAccessSpecifier)
                        self.stack = []
                    else:
                        self.nameStack.append(tok.value)
                        if self.anon_union_counter[0] == self.braceDepth:
                            self.anon_union_counter = [-1, 0]
                elif (tok.type == 'COLON'):
                    #Dont want colon to be first in stack
                    if len(self.nameStack) == 0:
                        self.accessSpecifierScratch = []
                        continue
                    
                    # Handle situation where access specifiers can be multi words such as "public slots"
                    jns = " ".join(self.accessSpecifierScratch + self.nameStack)
                    if jns in supportedAccessSpecifier:
                        self.curAccessSpecifier = jns;
                        debug_print("curAccessSpecifier updated to %s"%self.curAccessSpecifier)
                        self.stack = []
                        self.nameStack = []
                    else:
                        self.nameStack.append(tok.value)
                    self.accessSpecifierScratch = []

                elif (tok.type == 'SEMI_COLON'):
                    if self.anon_union_counter[0] == self.braceDepth and self.anon_union_counter[1]:
                        debug_print("Creating anonymous union")
                        #Force the processing of an anonymous union
                        saved_namestack = self.nameStack[:] 
                        saved_stack = self.stack[:]
                        self.nameStack = [""]
                        self.stack = self.nameStack + [";"]
                        self.nameStack = self.nameStack[0:1]
                        debug_print("pre eval anon stack")
                        self.evaluate_stack( tok.type )
                        debug_print("post eval anon stack")
                        self.nameStack = saved_namestack
                        self.stack = saved_stack
                        self.anon_union_counter = [-1, 0];
                    
                    
                    if (self.braceDepth < 10): self.evaluate_stack( tok.type )
                    self.stack = []
                    self.nameStack = []

        except:
            if (debug): raise
            raise CppParseError("Not able to parse %s on line %d evaluating \"%s\"\nError around: %s"
                                % (self.headerFileName, tok.lineno, tok.value, " ".join(self.nameStack)))

        self.finalize()
        global parseHistory
        parseHistory = []
        # Delete some temporary variables
        for key in ["_precomp_macro_buf", "nameStack", "nameSpaces", "curAccessSpecifier", "accessSpecifierStack",
            "accessSpecifierScratch", "nameStackHistory", "anon_struct_counter", "anon_union_counter",
            "_classes_brace_level", "_forward_decls", "stack", "mainClass", "curStruct", "_template_typenames",
            "_method_body", "braceDepth", "_structs_brace_level", "typedefs_order", "curTemplate", "templateRegistry"]:
            del self.__dict__[key]
        

    def evaluate_stack(self, token=None):
        """Evaluates the current name stack"""
        global doxygenCommentCache
        
        self.nameStack = filter_out_attribute_keyword(self.nameStack)
        self.stack = filter_out_attribute_keyword(self.stack)
        nameStackCopy = self.nameStack[:]
        
        debug_print( "Evaluating stack %s\n       BraceDepth: %s (called from %d)" %(self.nameStack,self.braceDepth, inspect.currentframe().f_back.f_lineno))
        
        #Handle special case of overloading operator ()
        if "operator()(" in "".join(self.nameStack):
            operator_index = self.nameStack.index("operator")
            self.nameStack.pop(operator_index + 2)
            self.nameStack.pop(operator_index + 1)
            self.nameStack[operator_index] = "operator()"
        
        if (len(self.curClass)):
            debug_print( "%s (%s) "%(self.curClass, self.curAccessSpecifier))
        else:
            debug_print( "<anonymous> (%s) "%self.curAccessSpecifier)

        #Filter special case of array with casting in it
        try:
            bracePos = self.nameStack.index("[")
            parenPos = self.nameStack.index("(")
            if bracePos == parenPos - 1:
                endParen = self.nameStack.index(")")
                self.nameStack = self.nameStack[:bracePos + 1] + self.nameStack[endParen + 1:]
                debug_print("Filtered namestack to=%s"%self.nameStack)
        except: pass

        #if 'typedef' in self.nameStack: self.evaluate_typedef()        # allows nested typedefs, probably a bad idea
        if (not self.curClass and 'typedef' in self.nameStack and 
            (('struct' not in self.nameStack and 'union' not in self.nameStack) or self.stack[-1] == ";") and
            not is_enum_namestack(self.nameStack)):
            trace_print('STACK', self.stack)
            self.evaluate_typedef()
            return
        
        elif (len(self.nameStack) == 0):
            debug_print( "trace" )
            debug_print( "(Empty Stack)" )
            return
        elif (self.nameStack[0] == "namespace"):
            #Taken care of outside of here
            pass
        elif len(self.nameStack) == 2 and self.nameStack[0] == "friend":#friend class declaration
            pass
        elif len(self.nameStack) >= 2 and self.nameStack[0] == 'using' and self.nameStack[1] == 'namespace': pass    # TODO

        elif is_enum_namestack(self.nameStack):
            debug_print( "trace" )
            self.evaluate_enum_stack()

        elif self._method_body and (self.braceDepth + 1) > self._method_body: trace_print( 'INSIDE METHOD DEF' )
        elif is_method_namestack(self.stack) and not self.curStruct and '(' in self.nameStack:
            debug_print( "trace" )
            if self.braceDepth > 0:
                if "{" in self.stack and self.stack[0] != '{' and self.stack[-1] == ';' and self.braceDepth == 1:
                    #Special case of a method defined outside a class that has a body
                    pass
                else: 
                    self.evaluate_method_stack()
            else:
                #Free function
                self.evaluate_method_stack()
        elif (len(self.nameStack) == 1 and len(self.nameStackHistory) > self.braceDepth
              and (self.nameStackHistory[self.braceDepth][0][0:2] == ["typedef", "struct"] or
                   self.nameStackHistory[self.braceDepth][0][0:2] == ["typedef", "union"])):
            # Look for the name of a typedef struct: struct typedef {...] StructName; or unions to get renamed
            debug_print("found the naming of a union")
            type_name_to_rename = self.nameStackHistory[self.braceDepth][1]
            new_name = self.nameStack[0]
            type_to_rename = self.classes[type_name_to_rename]
            type_to_rename["name"] = self.nameStack[0]
            #Now re install it in its new location
            self.classes[new_name] = type_to_rename
            if new_name != type_name_to_rename:
                del self.classes[type_name_to_rename] 
        elif is_property_namestack(self.nameStack) and self.stack[-1] == ';':
            debug_print( "trace" )
            if self.nameStack[0] in ('class', 'struct') and len(self.stack) == 3: self.evalute_forward_decl()
            elif len(self.nameStack) >= 2 and (self.nameStack[0]=='friend' and self.nameStack[1]=='class'): pass
            else: self.evaluate_property_stack()    # catches class props and structs in a namespace

        elif self.nameStack[0] in ("class", "struct", "union") or self.nameStack[0] == 'typedef' and self.nameStack[1] in ('struct', 'union'):
            #Parsing a union can reuse much of the class parsing
            debug_print( "trace" )
            self.evaluate_class_stack()

        elif not self.curClass:
            debug_print( "trace" )
            if is_enum_namestack(self.nameStack): self.evaluate_enum_stack()
            elif self.curStruct and self.stack[-1] == ';': self.evaluate_property_stack()    # this catches fields of global structs
            self.nameStack = []
            doxygenCommentCache = ""
        elif (self.braceDepth < 1):
            debug_print( "trace" )
            #Ignore global stuff for now
            debug_print( "Global stuff: %s"%self.nameStack )
            self.nameStack = []
            doxygenCommentCache = ""
        elif (self.braceDepth > len(self.nameSpaces) + 1):
            debug_print( "trace" )
            self.nameStack = []
            doxygenCommentCache = ""

        try:
            self.nameStackHistory[self.braceDepth] = (nameStackCopy, self.curClass)
        except:
            self.nameStackHistory.append((nameStackCopy, self.curClass))
        self.nameStack = []        # its a little confusing to have some if/else above return and others not, and then clearning the nameStack down here
        doxygenCommentCache = ""
        self.curTemplate = None
    

    def evaluate_enum_stack(self):
        """Create an Enum out of the name stack"""
        debug_print( "evaluating enum" )
        newEnum = CppEnum(self.nameStack)
        if len(list(newEnum.keys())):
            if len(self.curClass):
                newEnum["namespace"] = self.cur_namespace(False)
                klass = self.classes[self.curClass]
                klass["enums"][self.curAccessSpecifier].append(newEnum)
                if self.curAccessSpecifier == 'public' and 'name' in newEnum: klass._public_enums[ newEnum['name'] ] = newEnum
            else:
                newEnum["namespace"] = self.cur_namespace(True)
                self.enums.append(newEnum)
                if 'name' in newEnum and newEnum['name']: self.global_enums[ newEnum['name'] ] = newEnum

            #This enum has instances, turn them into properties
            if "instances" in newEnum:
                instanceType = "enum"
                if "name" in newEnum:
                    instanceType = newEnum["name"]
                for instance in newEnum["instances"]:
                    self.nameStack = [instanceType,  instance]
                    self.evaluate_property_stack()
                del newEnum["instances"]

    def strip_parent_keys(self):
        """Strip all parent (and method) keys to prevent loops"""
        obj_queue = [self]
        while len(obj_queue):
            obj = obj_queue.pop()
            trace_print("pop %s type %s"%(obj, type(obj)))
            try:
                if "parent" in obj.keys():
                    del obj["parent"]
                    trace_print("Stripped parent from %s"%obj.keys())
            except: pass
            try:
                if "method" in obj.keys():
                    del obj["method"]
                    trace_print("Stripped method from %s"%obj.keys())
            except: pass
            # Figure out what sub types are one of ours
            try:
                if not hasattr(obj, 'keys'):
                    obj = obj.__dict__
                for k in obj.keys():
                    trace_print("-Try key %s"%(k))
                    trace_print("-type  %s"%(type(obj[k])))
                    if k in ["nameStackHistory", "parent", "_public_typedefs"]: continue
                    if type(obj[k]) == list:
                        for i in obj[k]:
                            trace_print("push l %s"%i)
                            obj_queue.append(i)
                    elif type(obj[k]) == dict: 
                        if len(obj):
                            trace_print("push d %s"%obj[k])
                            obj_queue.append(obj[k])
                    elif type(obj[k]) == type(type(0)):
                        if type(obj[k]) == int:
                            obj[k] = "int"
                        elif type(obj[k]) == str:
                            obj[k] = "string"
                        else:
                            obj[k] = "???"
                    trace_print("next key\n")
            except:
                trace_print("Exception")

    def toJSON(self, indent=4):
        """Converts a parsed structure to JSON"""
        import json
        self.strip_parent_keys()
        try:
            del self.__dict__["classes_order"]
        except: pass
        return json.dumps(self.__dict__, indent=indent)


    def __repr__(self):
        rtn = {
          "classes": self.classes,
          "functions": self.functions,
          "enums": self.enums,
          "variables": self.variables,
        }
        return repr(rtn)

    def __str__(self):
        rtn = ""
        for className in list(self.classes.keys()):
            rtn += "%s\n"%self.classes[className]
        if self.functions:
            rtn += "// functions\n"
            for f in self.functions:
                rtn += "%s\n"%f
        if self.variables:
            rtn += "// variables\n"
            for f in self.variables:
                rtn += "%s\n"%f
        if self.enums:
            rtn += "// enums\n"
            for f in self.enums:
                rtn += "%s\n"%f
        return rtn
