@@ -139,6 +139,9 @@ def trace_print(*args):
139139#: Symbols to ignore, usually special macros
140140ignoreSymbols = ["Q_OBJECT" ]
141141
142+ _BRACE_REASON_OTHER = 0
143+ _BRACE_REASON_NS = 1
144+ _BRACE_REASON_EXTERN = 2
142145
143146# Track what was added in what order and at what depth
144147parseHistory = []
@@ -1477,7 +1480,6 @@ class Resolver(object):
14771480 C_KEYWORDS = "extern virtual static explicit inline friend constexpr" .split ()
14781481 C_KEYWORDS = set (C_KEYWORDS )
14791482
1480- SubTypedefs = {} # TODO deprecate?
14811483 NAMESPACES = []
14821484 CLASSES = {}
14831485
@@ -1506,6 +1508,11 @@ def cur_namespace(self, add_double_colon=False):
15061508 i += 1
15071509 return rtn
15081510
1511+ def cur_linkage (self ):
1512+ if len (self .linkage_stack ):
1513+ return self .linkage_stack [- 1 ]
1514+ return ""
1515+
15091516 def guess_ctypes_type (self , string ):
15101517 pointers = string .count ("*" )
15111518 string = string .replace ("*" , "" )
@@ -1870,21 +1877,6 @@ def finalize_vars(self):
18701877 var ["ctypes_type" ] = "ctypes.c_void_p"
18711878 var ["unresolved" ] = True
18721879
1873- elif tag in self .SubTypedefs : # TODO remove SubTypedefs
1874- if (
1875- "property_of_class" in var
1876- or "property_of_struct" in var
1877- ):
1878- trace_print (
1879- "class:" , self .SubTypedefs [tag ], "tag:" , tag
1880- )
1881- var ["typedef" ] = self .SubTypedefs [tag ] # class name
1882- var ["ctypes_type" ] = "ctypes.c_void_p"
1883- else :
1884- trace_print ("WARN-this should almost never happen!" )
1885- trace_print (var )
1886- var ["unresolved" ] = True
1887-
18881880 elif tag in self ._template_typenames :
18891881 var ["typename" ] = tag
18901882 var ["ctypes_type" ] = "ctypes.c_void_p"
@@ -2061,10 +2053,6 @@ def finalize(self):
20612053 trace_print ("meth returns class:" , meth ["returns" ])
20622054 meth ["returns_class" ] = True
20632055
2064- elif meth ["returns" ] in self .SubTypedefs :
2065- meth ["returns_class" ] = True
2066- meth ["returns_nested" ] = self .SubTypedefs [meth ["returns" ]]
2067-
20682056 elif meth ["returns" ] in cls ._public_enums :
20692057 enum = cls ._public_enums [meth ["returns" ]]
20702058 meth ["returns_enum" ] = enum .get ("type" )
@@ -2372,6 +2360,7 @@ def _evaluate_method_stack(self):
23722360 self ._get_location (self .nameStack ),
23732361 )
23742362 newMethod ["parent" ] = None
2363+ newMethod ["linkage" ] = self .cur_linkage ()
23752364 self .functions .append (newMethod )
23762365
23772366 # Reset template once it has been used
@@ -2472,7 +2461,6 @@ def _evaluate_property_stack(self, clearStack=True, addToVar=None):
24722461 klass ["typedefs" ][self .curAccessSpecifier ].append (name )
24732462 if self .curAccessSpecifier == "public" :
24742463 klass ._public_typedefs [name ] = typedef ["type" ]
2475- Resolver .SubTypedefs [name ] = self .curClass
24762464 else :
24772465 assert 0
24782466 elif self .curClass :
@@ -2524,6 +2512,7 @@ def _evaluate_property_stack(self, clearStack=True, addToVar=None):
25242512 self ._get_location (self .nameStack ),
25252513 )
25262514 newVar ["namespace" ] = self .current_namespace ()
2515+ newVar ["linkage" ] = self .cur_linkage ()
25272516 if self .curClass :
25282517 klass = self .classes [self .curClass ]
25292518 klass ["properties" ][self .curAccessSpecifier ].append (newVar )
@@ -2542,6 +2531,7 @@ def _evaluate_property_stack(self, clearStack=True, addToVar=None):
25422531 self ._get_location (self .nameStack ),
25432532 )
25442533 newVar ["namespace" ] = self .cur_namespace (False )
2534+ newVar ["linkage" ] = self .cur_linkage ()
25452535 if addToVar :
25462536 newVar .update (addToVar )
25472537 self .variables .append (newVar )
@@ -2600,6 +2590,7 @@ def _evaluate_class_stack(self):
26002590 )
26012591 self .curTemplate = None
26022592 newClass ["declaration_method" ] = self .nameStack [0 ]
2593+ newClass ["linkage" ] = self .cur_linkage ()
26032594 self .classes_order .append (newClass ) # good idea to save ordering
26042595 self .stack = [] # fixes if class declared with ';' in closing brace
26052596 self .stmtTokens = []
@@ -2702,7 +2693,14 @@ def show(self):
27022693 for className in list (self .classes .keys ()):
27032694 self .classes [className ].show ()
27042695
2705- def __init__ (self , headerFileName , argType = "file" , encoding = None , ** kwargs ):
2696+ def __init__ (
2697+ self ,
2698+ headerFileName ,
2699+ argType = "file" ,
2700+ encoding = None ,
2701+ preprocessed = False ,
2702+ ** kwargs
2703+ ):
27062704 """Create the parsed C++ header file parse tree
27072705
27082706 headerFileName - Name of the file to parse OR actual file contents (depends on argType)
@@ -2775,6 +2773,7 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
27752773 self .curAccessSpecifier = "private" # private is default
27762774 self .curTemplate = None
27772775 self .accessSpecifierStack = []
2776+ self .linkage_stack = []
27782777 debug_print (
27792778 "curAccessSpecifier changed/defaulted to %s" , self .curAccessSpecifier
27802779 )
@@ -2802,31 +2801,24 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
28022801 "[ ]+" , " " , supportedAccessSpecifier [i ]
28032802 ).strip ()
28042803
2805- # Change multi line #defines and expressions to single lines maintaining line nubmers
2806- # Based from http://stackoverflow.com/questions/2424458/regular-expression-to-match-cs-multiline-preprocessor-statements
2807- matches = re .findall (r"(?m)^(?:.*\\\r?\n)+.*$" , headerFileStr )
2808- is_define = re .compile (r"[ \t\v]*#[Dd][Ee][Ff][Ii][Nn][Ee]" )
2809- for m in matches :
2810- # Keep the newlines so that linecount doesnt break
2811- num_newlines = len ([a for a in m if a == "\n " ])
2812- if is_define .match (m ):
2813- new_m = m .replace ("\n " , "<CppHeaderParser_newline_temp_replacement>\\ n" )
2814- else :
2815- # Just expression taking up multiple lines, make it take 1 line for easier parsing
2816- new_m = m .replace ("\\ \n " , " " )
2817- if num_newlines > 0 :
2818- new_m += "\n " * (num_newlines )
2819- headerFileStr = headerFileStr .replace (m , new_m )
2820-
2821- # Filter out Extern "C" statements. These are order dependent
2822- matches = re .findall (
2823- re .compile (r'extern[\t ]+"[Cc]"[\t \n\r]*{' , re .DOTALL ), headerFileStr
2824- )
2825- for m in matches :
2826- # Keep the newlines so that linecount doesnt break
2827- num_newlines = len ([a for a in m if a == "\n " ])
2828- headerFileStr = headerFileStr .replace (m , "\n " * num_newlines )
2829- headerFileStr = re .sub (r'extern[ ]+"[Cc]"[ ]*' , "" , headerFileStr )
2804+ if not preprocessed :
2805+ # Change multi line #defines and expressions to single lines maintaining line nubmers
2806+ # Based from http://stackoverflow.com/questions/2424458/regular-expression-to-match-cs-multiline-preprocessor-statements
2807+ matches = re .findall (r"(?m)^(?:.*\\\r?\n)+.*$" , headerFileStr )
2808+ is_define = re .compile (r"[ \t\v]*#[Dd][Ee][Ff][Ii][Nn][Ee]" )
2809+ for m in matches :
2810+ # Keep the newlines so that linecount doesnt break
2811+ num_newlines = len ([a for a in m if a == "\n " ])
2812+ if is_define .match (m ):
2813+ new_m = m .replace (
2814+ "\n " , "<CppHeaderParser_newline_temp_replacement>\\ n"
2815+ )
2816+ else :
2817+ # Just expression taking up multiple lines, make it take 1 line for easier parsing
2818+ new_m = m .replace ("\\ \n " , " " )
2819+ if num_newlines > 0 :
2820+ new_m += "\n " * (num_newlines )
2821+ headerFileStr = headerFileStr .replace (m , new_m )
28302822
28312823 # Filter out any ignore symbols that end with "()" to account for #define magic functions
28322824 for ignore in ignoreSymbols :
@@ -2866,6 +2858,8 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
28662858 )
28672859
28682860 self .braceDepth = 0
2861+ self .braceReason = []
2862+ self .lastBraceReason = _BRACE_REASON_OTHER
28692863
28702864 lex = Lexer (self .headerFileName )
28712865 lex .input (headerFileStr )
@@ -2938,23 +2932,20 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
29382932 continue
29392933
29402934 if parenDepth == 0 and tok .type == "{" :
2935+ self .lastBraceReason = _BRACE_REASON_OTHER
29412936 if len (self .nameStack ) >= 2 and is_namespace (
29422937 self .nameStack
29432938 ): # namespace {} with no name used in boost, this sets default?
2944- if (
2945- self .nameStack [1 ]
2946- == "__IGNORED_NAMESPACE__CppHeaderParser__"
2947- ): # Used in filtering extern "C"
2948- self .nameStack [1 ] = ""
29492939 self .nameSpaces .append ("" .join (self .nameStack [1 :]))
29502940 ns = self .cur_namespace ()
29512941 self .stack = []
29522942 self .stmtTokens = []
29532943 if ns not in self .namespaces :
29542944 self .namespaces .append (ns )
2945+ self .lastBraceReason = _BRACE_REASON_NS
29552946 # Detect special condition of macro magic before class declaration so we
29562947 # can filter it out
2957- if "class" in self .nameStack and self .nameStack [0 ] != "class" :
2948+ elif "class" in self .nameStack and self .nameStack [0 ] != "class" :
29582949 classLocationNS = self .nameStack .index ("class" )
29592950 classLocationS = self .stack .index ("class" )
29602951 if (
@@ -2987,14 +2978,20 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
29872978 self .stmtTokens = []
29882979 if not self .braceHandled :
29892980 self .braceDepth += 1
2981+ self .braceReason .append (self .lastBraceReason )
29902982
29912983 elif parenDepth == 0 and tok .type == "}" :
29922984 if self .braceDepth == 0 :
29932985 continue
2994- if self .braceDepth == len (self .nameSpaces ):
2995- tmp = self .nameSpaces .pop ()
2986+ reason = self .braceReason .pop ()
2987+ if reason == _BRACE_REASON_NS :
2988+ self .nameSpaces .pop ()
29962989 self .stack = [] # clear stack when namespace ends?
29972990 self .stmtTokens = []
2991+ elif reason == _BRACE_REASON_EXTERN :
2992+ self .linkage_stack .pop ()
2993+ self .stack = [] # clear stack when linkage ends?
2994+ self .stmtTokens = []
29982995 else :
29992996 self ._evaluate_stack ()
30002997 self .braceDepth -= 1
@@ -3358,8 +3355,10 @@ def _evaluate_stack(self, token=None):
33583355 pass
33593356 elif len (self .nameStack ) == 2 and self .nameStack [0 ] == "extern" :
33603357 debug_print ("trace extern" )
3358+ self .linkage_stack .append (self .nameStack [1 ].strip ('"' ))
33613359 self .stack = []
33623360 self .stmtTokens = []
3361+ self .lastBraceReason = _BRACE_REASON_EXTERN
33633362 elif (
33643363 len (self .nameStack ) == 2 and self .nameStack [0 ] == "friend"
33653364 ): # friend class declaration
@@ -3667,12 +3666,14 @@ def _parse_enum(self):
36673666 def _install_enum (self , newEnum , instancesData ):
36683667 if len (self .curClass ):
36693668 newEnum ["namespace" ] = self .cur_namespace (False )
3669+ newEnum ["linkage" ] = self .cur_linkage ()
36703670 klass = self .classes [self .curClass ]
36713671 klass ["enums" ][self .curAccessSpecifier ].append (newEnum )
36723672 if self .curAccessSpecifier == "public" and "name" in newEnum :
36733673 klass ._public_enums [newEnum ["name" ]] = newEnum
36743674 else :
36753675 newEnum ["namespace" ] = self .cur_namespace (True )
3676+ newEnum ["linkage" ] = self .cur_linkage ()
36763677 self .enums .append (newEnum )
36773678 if "name" in newEnum and newEnum ["name" ]:
36783679 self .global_enums [newEnum ["name" ]] = newEnum
0 commit comments