@@ -139,6 +139,9 @@ def trace_print(*args):
139
139
#: Symbols to ignore, usually special macros
140
140
ignoreSymbols = ["Q_OBJECT" ]
141
141
142
+ _BRACE_REASON_OTHER = 0
143
+ _BRACE_REASON_NS = 1
144
+ _BRACE_REASON_EXTERN = 2
142
145
143
146
# Track what was added in what order and at what depth
144
147
parseHistory = []
@@ -1477,7 +1480,6 @@ class Resolver(object):
1477
1480
C_KEYWORDS = "extern virtual static explicit inline friend constexpr" .split ()
1478
1481
C_KEYWORDS = set (C_KEYWORDS )
1479
1482
1480
- SubTypedefs = {} # TODO deprecate?
1481
1483
NAMESPACES = []
1482
1484
CLASSES = {}
1483
1485
@@ -1506,6 +1508,11 @@ def cur_namespace(self, add_double_colon=False):
1506
1508
i += 1
1507
1509
return rtn
1508
1510
1511
+ def cur_linkage (self ):
1512
+ if len (self .linkage_stack ):
1513
+ return self .linkage_stack [- 1 ]
1514
+ return ""
1515
+
1509
1516
def guess_ctypes_type (self , string ):
1510
1517
pointers = string .count ("*" )
1511
1518
string = string .replace ("*" , "" )
@@ -1870,21 +1877,6 @@ def finalize_vars(self):
1870
1877
var ["ctypes_type" ] = "ctypes.c_void_p"
1871
1878
var ["unresolved" ] = True
1872
1879
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
-
1888
1880
elif tag in self ._template_typenames :
1889
1881
var ["typename" ] = tag
1890
1882
var ["ctypes_type" ] = "ctypes.c_void_p"
@@ -2061,10 +2053,6 @@ def finalize(self):
2061
2053
trace_print ("meth returns class:" , meth ["returns" ])
2062
2054
meth ["returns_class" ] = True
2063
2055
2064
- elif meth ["returns" ] in self .SubTypedefs :
2065
- meth ["returns_class" ] = True
2066
- meth ["returns_nested" ] = self .SubTypedefs [meth ["returns" ]]
2067
-
2068
2056
elif meth ["returns" ] in cls ._public_enums :
2069
2057
enum = cls ._public_enums [meth ["returns" ]]
2070
2058
meth ["returns_enum" ] = enum .get ("type" )
@@ -2372,6 +2360,7 @@ def _evaluate_method_stack(self):
2372
2360
self ._get_location (self .nameStack ),
2373
2361
)
2374
2362
newMethod ["parent" ] = None
2363
+ newMethod ["linkage" ] = self .cur_linkage ()
2375
2364
self .functions .append (newMethod )
2376
2365
2377
2366
# Reset template once it has been used
@@ -2472,7 +2461,6 @@ def _evaluate_property_stack(self, clearStack=True, addToVar=None):
2472
2461
klass ["typedefs" ][self .curAccessSpecifier ].append (name )
2473
2462
if self .curAccessSpecifier == "public" :
2474
2463
klass ._public_typedefs [name ] = typedef ["type" ]
2475
- Resolver .SubTypedefs [name ] = self .curClass
2476
2464
else :
2477
2465
assert 0
2478
2466
elif self .curClass :
@@ -2524,6 +2512,7 @@ def _evaluate_property_stack(self, clearStack=True, addToVar=None):
2524
2512
self ._get_location (self .nameStack ),
2525
2513
)
2526
2514
newVar ["namespace" ] = self .current_namespace ()
2515
+ newVar ["linkage" ] = self .cur_linkage ()
2527
2516
if self .curClass :
2528
2517
klass = self .classes [self .curClass ]
2529
2518
klass ["properties" ][self .curAccessSpecifier ].append (newVar )
@@ -2542,6 +2531,7 @@ def _evaluate_property_stack(self, clearStack=True, addToVar=None):
2542
2531
self ._get_location (self .nameStack ),
2543
2532
)
2544
2533
newVar ["namespace" ] = self .cur_namespace (False )
2534
+ newVar ["linkage" ] = self .cur_linkage ()
2545
2535
if addToVar :
2546
2536
newVar .update (addToVar )
2547
2537
self .variables .append (newVar )
@@ -2600,6 +2590,7 @@ def _evaluate_class_stack(self):
2600
2590
)
2601
2591
self .curTemplate = None
2602
2592
newClass ["declaration_method" ] = self .nameStack [0 ]
2593
+ newClass ["linkage" ] = self .cur_linkage ()
2603
2594
self .classes_order .append (newClass ) # good idea to save ordering
2604
2595
self .stack = [] # fixes if class declared with ';' in closing brace
2605
2596
self .stmtTokens = []
@@ -2702,7 +2693,14 @@ def show(self):
2702
2693
for className in list (self .classes .keys ()):
2703
2694
self .classes [className ].show ()
2704
2695
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
+ ):
2706
2704
"""Create the parsed C++ header file parse tree
2707
2705
2708
2706
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):
2775
2773
self .curAccessSpecifier = "private" # private is default
2776
2774
self .curTemplate = None
2777
2775
self .accessSpecifierStack = []
2776
+ self .linkage_stack = []
2778
2777
debug_print (
2779
2778
"curAccessSpecifier changed/defaulted to %s" , self .curAccessSpecifier
2780
2779
)
@@ -2802,31 +2801,24 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
2802
2801
"[ ]+" , " " , supportedAccessSpecifier [i ]
2803
2802
).strip ()
2804
2803
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 )
2830
2822
2831
2823
# Filter out any ignore symbols that end with "()" to account for #define magic functions
2832
2824
for ignore in ignoreSymbols :
@@ -2866,6 +2858,8 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
2866
2858
)
2867
2859
2868
2860
self .braceDepth = 0
2861
+ self .braceReason = []
2862
+ self .lastBraceReason = _BRACE_REASON_OTHER
2869
2863
2870
2864
lex = Lexer (self .headerFileName )
2871
2865
lex .input (headerFileStr )
@@ -2938,23 +2932,20 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
2938
2932
continue
2939
2933
2940
2934
if parenDepth == 0 and tok .type == "{" :
2935
+ self .lastBraceReason = _BRACE_REASON_OTHER
2941
2936
if len (self .nameStack ) >= 2 and is_namespace (
2942
2937
self .nameStack
2943
2938
): # 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 ] = ""
2949
2939
self .nameSpaces .append ("" .join (self .nameStack [1 :]))
2950
2940
ns = self .cur_namespace ()
2951
2941
self .stack = []
2952
2942
self .stmtTokens = []
2953
2943
if ns not in self .namespaces :
2954
2944
self .namespaces .append (ns )
2945
+ self .lastBraceReason = _BRACE_REASON_NS
2955
2946
# Detect special condition of macro magic before class declaration so we
2956
2947
# 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" :
2958
2949
classLocationNS = self .nameStack .index ("class" )
2959
2950
classLocationS = self .stack .index ("class" )
2960
2951
if (
@@ -2987,14 +2978,20 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
2987
2978
self .stmtTokens = []
2988
2979
if not self .braceHandled :
2989
2980
self .braceDepth += 1
2981
+ self .braceReason .append (self .lastBraceReason )
2990
2982
2991
2983
elif parenDepth == 0 and tok .type == "}" :
2992
2984
if self .braceDepth == 0 :
2993
2985
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 ()
2996
2989
self .stack = [] # clear stack when namespace ends?
2997
2990
self .stmtTokens = []
2991
+ elif reason == _BRACE_REASON_EXTERN :
2992
+ self .linkage_stack .pop ()
2993
+ self .stack = [] # clear stack when linkage ends?
2994
+ self .stmtTokens = []
2998
2995
else :
2999
2996
self ._evaluate_stack ()
3000
2997
self .braceDepth -= 1
@@ -3358,8 +3355,10 @@ def _evaluate_stack(self, token=None):
3358
3355
pass
3359
3356
elif len (self .nameStack ) == 2 and self .nameStack [0 ] == "extern" :
3360
3357
debug_print ("trace extern" )
3358
+ self .linkage_stack .append (self .nameStack [1 ].strip ('"' ))
3361
3359
self .stack = []
3362
3360
self .stmtTokens = []
3361
+ self .lastBraceReason = _BRACE_REASON_EXTERN
3363
3362
elif (
3364
3363
len (self .nameStack ) == 2 and self .nameStack [0 ] == "friend"
3365
3364
): # friend class declaration
@@ -3667,12 +3666,14 @@ def _parse_enum(self):
3667
3666
def _install_enum (self , newEnum , instancesData ):
3668
3667
if len (self .curClass ):
3669
3668
newEnum ["namespace" ] = self .cur_namespace (False )
3669
+ newEnum ["linkage" ] = self .cur_linkage ()
3670
3670
klass = self .classes [self .curClass ]
3671
3671
klass ["enums" ][self .curAccessSpecifier ].append (newEnum )
3672
3672
if self .curAccessSpecifier == "public" and "name" in newEnum :
3673
3673
klass ._public_enums [newEnum ["name" ]] = newEnum
3674
3674
else :
3675
3675
newEnum ["namespace" ] = self .cur_namespace (True )
3676
+ newEnum ["linkage" ] = self .cur_linkage ()
3676
3677
self .enums .append (newEnum )
3677
3678
if "name" in newEnum and newEnum ["name" ]:
3678
3679
self .global_enums [newEnum ["name" ]] = newEnum
0 commit comments