Răsfoiți Sursa

Update CppHeaderParser to newest version, fixed bugs caused by that. Fixed bug in lua doc generation

Ivan Safrin 13 ani în urmă
părinte
comite
8468cd225f

Fișier diff suprimat deoarece este prea mare
+ 1500 - 61
Bindings/Scripts/create_lua_library/CppHeaderParser.py


+ 2281 - 0
Bindings/Scripts/create_lua_library/CppHeaderParser3.py

@@ -0,0 +1,2281 @@
+#!/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.3"
+
+tokens = [
+    'NUMBER',
+    '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_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 
+
+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):
+        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 )
+        if (len(nameStack) < 2):
+            nameStack.insert(1, "")#anonymous struct
+        global doxygenCommentCache
+        if len(doxygenCommentCache):
+            self["doxygen"] = doxygenCommentCache
+            doxygenCommentCache = ""
+        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
+
+        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['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 __repr__(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'
+
+        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)
+        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 __repr__(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):
+        debug_print( "Method:   %s"%nameStack )
+        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(" ,",",")
+        
+        self["const"] = False
+        for i in reversed(nameStack):
+            if i == "const":
+                self["const"] = 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 )
+        
+
+        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 __repr__(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['defaltValue'] - Default value of the variable, this key will only
+        exist if there is a default value
+    """
+    Vars = []
+    def __init__(self, nameStack,  **kwargs):
+        _stack_ = nameStack
+        if "[" in nameStack: #strip off array informatin
+            arrayStack = nameStack[nameStack.index("["):]
+            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["defaltValue"] = " ".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 __repr__(self):
+        keys_white_list = ['constant','name','reference','type','static','pointer','desc', 'line_number']
+        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:]
+        if (len(preBraceStack) == 2 and "typedef" not in nameStack):
+            self["name"] = preBraceStack[1]           
+        elif len(postBraceStack) and "typedef" in nameStack:
+                self["name"] = " ".join(postBraceStack)
+        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(macro.split(" ", 1)[1].strip())
+                elif macro.lower().startswith("#pragma"):
+                    trace_print("Adding #pragma %s"%macro)
+                    self.pragmas.append(macro.split(" ", 1)[1].strip())
+                elif macro.lower().startswith("#include"):
+                    trace_print("Adding #include %s"%macro)
+                    self.includes.append(macro.split(" ", 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
+
+        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 ':;': 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)
+                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)
+                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.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')
+        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] == ';'
+        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]))
+            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})
+
+        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
+        
+        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)
+            self.anon_union_counter = [self.braceDepth, 2]
+            trace_print( 'NEW UNION', newClass['name'] )
+        else:
+            newClass = CppClass(self.nameStack)
+            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.global_enums = {}
+        self.nameStack = []
+        self.nameSpaces = []
+        self.curAccessSpecifier = 'private'    # private is default
+        self.accessSpecifierStack = []
+        self.accessSpecifierScratch = []
+        debug_print("curAccessSpecifier changed/defaulted to %s"%self.curAccessSpecifier)
+        self.initextra()
+    
+        self.anon_union_counter = [-1, 0]
+    
+        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
+        headerFileStr = re.sub("template[\t ]*<[^>]*>", "", headerFileStr)
+
+        # 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 > 1):
+                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)
+                
+        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
+                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)
+                    continue
+                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 )
+                    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 == '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'):
+                    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 )
+                    if not self.stack: continue
+                    if self.stack[0]=='typedef' and ( '{' not in self.stack or '}' in self.stack ): self.stack = []; trace_print( "REAL CLEAR")
+                    elif self.stack[0] != 'typedef': self.stack = []; trace_print('CLEAR STACK')
+
+        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 = []
+
+    def evaluate_stack(self, token=None):
+        """Evaluates the current name stack"""
+        global doxygenCommentCache
+        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))
+
+        #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:
+            trace_print('STACK', self.stack)
+            if token == 'SEMI_COLON' and ('{' not in self.stack or '}' in self.stack): self.evaluate_typedef()
+            else: 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 self.nameStack[0] == "friend":
+            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 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"):
+            #Parsing a union can reuse much of the class parsing
+            debug_print( "trace" )
+            self.evaluate_class_stack()
+        #elif (self.nameStack[0] == "struct"):
+        #    debug_print( "trace" )
+            ##this causes a bug when structs are nested in protected or private##self.curAccessSpecifier = "public"
+        #    self.evaluate_struct_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 = ""
+            return
+        elif (self.braceDepth < 1):
+            debug_print( "trace" )
+            #Ignore global stuff for now
+            debug_print( "Global stuff: %s"%self.nameStack )
+            self.nameStack = []
+            doxygenCommentCache = ""
+            return
+        elif (self.braceDepth > len(self.nameSpaces) + 1):
+            debug_print( "trace" )
+            self.nameStack = []
+            doxygenCommentCache = ""
+            return
+
+        self.nameStack = []        # its a little confusing to have some if/else above return and others not, and then clearning the nameStack down here
+        doxygenCommentCache = ""
+    
+
+    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 __repr__(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.enums:
+            rtn += "// enums\n"
+            for f in self.enums:
+                rtn += "%s\n"%f
+        return rtn

+ 19 - 8
Bindings/Scripts/create_lua_library/create_lua_library.py

@@ -226,11 +226,17 @@ def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, api
 
 				luaDocOut += "\t\t<members>\n"
 
+				numGetVars = 0
 				if len(classProperties) > 0: # If there are properties, add index lookup to the metatable
 					luaClassBindingOut += "function %s:__getvar(name)\n" % ckey
 					# Iterate over property structures, creating if/else clauses for each.
 					# TODO: Could a table be more appropriate for 
 					for pp in classProperties:
+						if pp["name"] == "" or pp["array"] == 1:
+							continue
+
+						numGetVars = numGetVars + 1
+
 						pp["type"] = typeFilter(pp["type"])
 						if pidx == 0:
 							luaClassBindingOut += "\tif name == \"%s\" then\n" % (pp["name"])
@@ -290,8 +296,8 @@ def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, api
 						
 						# Success
 						pidx = pidx + 1
-
-					luaClassBindingOut += "\tend\n"
+					if numGetVars != 0:
+						luaClassBindingOut += "\tend\n"
 					if inherits:
 						luaClassBindingOut += "\tif %s[\"__getvar\"] ~= nil then\n" % (parentClass)
 						luaClassBindingOut += "\t\treturn %s.__getvar(self, name)\n" % (parentClass)
@@ -307,6 +313,8 @@ def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, api
 				if len(classProperties) > 0: # If there are properties, add index setter to the metatable
 					luaClassBindingOut += "function %s:__setvar(name,value)\n" % ckey
 					for pp in classProperties:
+						if pp["name"] == "" or pp["array"] == 1:
+							continue
 						pp["type"] = typeFilter(pp["type"])
 						
 						# If type is a primitive: Create lua and C++ sides at the same time.
@@ -367,18 +375,21 @@ def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, api
 
 					# Skip destructors and methods which return templates.
 					# TODO: Special-case certain kind of vector<>s?
-					if pm["name"] == "~"+ckey:
+					if pm["name"] == "~"+ckey or pm["name"] == "CoreServices":
 						continue
 					
-					if pm["rtnType"].find("std : : vector") > -1:
-						vectorReturnClass = pm["rtnType"].replace("std : : vector <", "").replace(">","").replace(" ", "")
+					if pm["rtnType"].find("std::vector") > -1:
+						vectorReturnClass = pm["rtnType"].replace("std::vector<", "").replace(">","").replace(" ", "")
 						luaDocOut += "\t\t\t<method name=\"%s\" return_array=\"true\" return_type=\"%s\">\n" % (pm["name"],  toLuaType(typeFilter(vectorReturnClass).replace("*", "")))
 					else:
 						luaDocOut += "\t\t\t<method name=\"%s\" return_type=\"%s\">\n" % (pm["name"],  toLuaType(typeFilter(pm["rtnType"].replace("*", ""))))
 
 					docs = None
 					if 'doxygen' in pm:
-						docs = cleanDocs(pm['doxygen']).split("@return")[0].split("@param")
+						if pm['doxygen'].find("@return") > -1:
+							docs = cleanDocs(pm['doxygen']).split("@return")[0].split("@param")
+						else:
+							docs = cleanDocs(pm['doxygen']).split("@param")
 						luaDocOut += "\t\t\t\t<desc><![CDATA[%s]]></desc>\n" % (docs[0])
 						
 					if len(pm["parameters"]) > 0:
@@ -538,8 +549,8 @@ def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, api
 							#check if returning a template
 							if pm["rtnType"].find("<") > -1:
 								#if returning a vector, convert to lua table
-								if pm["rtnType"].find("std : : vector") > -1:
-									vectorReturnClass = pm["rtnType"].replace("std : : vector <", "").replace(">","").replace(" ", "")
+								if pm["rtnType"].find("std::vector") > -1:
+									vectorReturnClass = pm["rtnType"].replace("std::vector<", "").replace(">","").replace(" ", "")
 									if vectorReturnClass.find("&") == -1 and vectorReturnClass.find("*") > -1: #FIXME: return references to std::vectors and basic types
 										vectorReturn = True
 										wrappersHeaderOut += "\tstd::vector<%s> retVector = %s;\n" % (vectorReturnClass,call)

+ 1 - 1
Core/Contents/Include/PolyQuaternion.h

@@ -95,7 +95,7 @@ namespace Polycode {
 	Quaternion Log () const;
     Quaternion Exp () const;	
     Number Norm () const;
-    Number normalize(void);	
+    Number normalize();	
     Quaternion operator+ (const Quaternion& rkQ) const;
     Quaternion operator* (const Quaternion& rkQ) const;
     Quaternion operator* (Number fScalar) const;

+ 1 - 1
Core/Contents/Include/PolyQuaternionCurve.h

@@ -45,7 +45,7 @@ namespace Polycode {
 			Quaternion interpolate(unsigned int fromIndex, Number t, bool useShortestPath);
 						
 			void generatePointsFromCurves(BezierCurve *wCurve, BezierCurve *xCurve, BezierCurve *yCurve, BezierCurve *zCurve);
-			void recalcTangents(void);
+			void recalcTangents();
 		
 		protected:
 		

+ 1 - 1
Core/Contents/Source/PolyQuaternion.cpp

@@ -178,7 +178,7 @@ Matrix4 Quaternion::createMatrix() const
         return w*w+x*x+y*y+z*z;
     }
 
-    Number Quaternion::normalize(void)
+    Number Quaternion::normalize()
     {
         Number len = Norm();
         Number factor = 1.0f / sqrtf(len);

+ 1 - 1
Core/Contents/Source/PolyQuaternionCurve.cpp

@@ -121,7 +121,7 @@ void QuaternionCurve::generatePointsFromCurves(BezierCurve *wCurve, BezierCurve
 
     }
 
-void QuaternionCurve::recalcTangents(void)
+void QuaternionCurve::recalcTangents()
 {
         unsigned int i, numPoints;
         bool isClosed;

+ 3 - 2
Documentation/Lua/scripts/make_html.py

@@ -89,10 +89,11 @@ def makePage(item, classList):
 				html += "\t\t\t\t\t\t\t\t<div class=\"class_method_param\">\n"
 				html += "\t\t\t\t\t\t\t\t\t<div class=\"class_method_param_name\">%s</div>\n" % (param.attributes["name"].value)
 				html += "\t\t\t\t\t\t\t\t\t<div class=\"class_method_param_type\">%s</div>\n" % (param.attributes["type"].value)
-				desc = subitem.getElementsByTagName('desc')
+				desc = param.getElementsByTagName('desc')
 				descText = "No description."
 				if len(desc) > 0:
-					descText = desc[0].childNodes[0].data
+					if len(desc[0].childNodes) > 0:
+						descText = desc[0].childNodes[0].data
 				html += "\t\t\t\t\t\t\t\t\t<div class=\"class_method_param_desc\">%s</div>\n" % (descText)
 				html += "\t\t\t\t\t\t\t\t</div>\n"
 

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff