21
21
]
22
22
23
23
"""
24
- Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>],
24
+ Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>, original_return_type, docstring ],
25
25
where each element of <list_of_arguments> is 4-element list itself:
26
26
[argtype, argname, default_value /* or "" if none */, <list_of_modifiers>]
27
27
where the list of modifiers is yet another nested list of strings
28
28
(currently recognized are "/O" for output argument, "/S" for static (i.e. class) methods
29
29
and "/A value" for the plain C arrays with counters)
30
+ original_return_type is None if the original_return_type is the same as return_value_type
30
31
"""
31
32
32
33
class CppHeaderParser (object ):
@@ -226,7 +227,7 @@ def parse_enum(self, decl_str):
226
227
else :
227
228
prev_val_delta = 0
228
229
prev_val = val = pv [1 ].strip ()
229
- decl .append (["const " + self .get_dotted_name (pv [0 ].strip ()), val , [], []])
230
+ decl .append (["const " + self .get_dotted_name (pv [0 ].strip ()), val , [], [], None , "" ])
230
231
return decl
231
232
232
233
def parse_class_decl (self , decl_str ):
@@ -256,7 +257,7 @@ def parse_class_decl(self, decl_str):
256
257
bases = ll [2 :]
257
258
return classname , bases , modlist
258
259
259
- def parse_func_decl_no_wrap (self , decl_str , static_method = False ):
260
+ def parse_func_decl_no_wrap (self , decl_str , static_method = False , docstring = "" ):
260
261
decl_str = (decl_str or "" ).strip ()
261
262
virtual_method = False
262
263
explicit_method = False
@@ -299,7 +300,7 @@ def parse_func_decl_no_wrap(self, decl_str, static_method = False):
299
300
apos = fdecl .find ("(" , apos + 1 )
300
301
301
302
fname = "cv." + fname .replace ("::" , "." )
302
- decl = [fname , rettype , [], []]
303
+ decl = [fname , rettype , [], [], None , docstring ]
303
304
304
305
# inline constructor implementation
305
306
implmatch = re .match (r"(\(.*?\))\s*:\s*(\w+\(.*?\),?\s*)+" , fdecl [apos :])
@@ -370,7 +371,7 @@ def parse_func_decl_no_wrap(self, decl_str, static_method = False):
370
371
print (decl_str )
371
372
return decl
372
373
373
- def parse_func_decl (self , decl_str , use_umat = False ):
374
+ def parse_func_decl (self , decl_str , use_umat = False , docstring = "" ):
374
375
"""
375
376
Parses the function or method declaration in the form:
376
377
[([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
@@ -379,7 +380,7 @@ def parse_func_decl(self, decl_str, use_umat=False):
379
380
[const] {; | <function_body>}
380
381
381
382
Returns the function declaration entry:
382
- [<func name>, <return value C-type>, <list of modifiers>, <list of arguments>] (see above)
383
+ [<func name>, <return value C-type>, <list of modifiers>, <list of arguments>, <original return type>, <docstring> ] (see above)
383
384
"""
384
385
385
386
if self .wrap_mode :
@@ -484,7 +485,7 @@ def parse_func_decl(self, decl_str, use_umat=False):
484
485
funcname = self .get_dotted_name (funcname )
485
486
486
487
if not self .wrap_mode :
487
- decl = self .parse_func_decl_no_wrap (decl_str , static_method )
488
+ decl = self .parse_func_decl_no_wrap (decl_str , static_method , docstring )
488
489
decl [0 ] = funcname
489
490
return decl
490
491
@@ -574,10 +575,7 @@ def parse_func_decl(self, decl_str, use_umat=False):
574
575
if static_method :
575
576
func_modlist .append ("/S" )
576
577
577
- if original_type is None :
578
- return [funcname , rettype , func_modlist , args ]
579
- else :
580
- return [funcname , rettype , func_modlist , args , original_type ]
578
+ return [funcname , rettype , func_modlist , args , original_type , docstring ]
581
579
582
580
def get_dotted_name (self , name ):
583
581
"""
@@ -612,7 +610,7 @@ class A {
612
610
n = "cv.Algorithm"
613
611
return n
614
612
615
- def parse_stmt (self , stmt , end_token , use_umat = False ):
613
+ def parse_stmt (self , stmt , end_token , use_umat = False , docstring = "" ):
616
614
"""
617
615
parses the statement (ending with ';' or '}') or a block head (ending with '{')
618
616
@@ -659,7 +657,7 @@ def parse_stmt(self, stmt, end_token, use_umat=False):
659
657
exit (1 )
660
658
if classname .startswith ("_Ipl" ):
661
659
classname = classname [1 :]
662
- decl = [stmt_type + " " + self .get_dotted_name (classname ), "" , modlist , []]
660
+ decl = [stmt_type + " " + self .get_dotted_name (classname ), "" , modlist , [], None , docstring ]
663
661
if bases :
664
662
decl [1 ] = ": " + ", " .join ([self .get_dotted_name (b ).replace ("." ,"::" ) for b in bases ])
665
663
return stmt_type , classname , True , decl
@@ -674,7 +672,7 @@ def parse_stmt(self, stmt, end_token, use_umat=False):
674
672
exit (1 )
675
673
decl = []
676
674
if ("CV_EXPORTS_W" in stmt ) or ("CV_EXPORTS_AS" in stmt ) or (not self .wrap_mode ):# and ("CV_EXPORTS" in stmt)):
677
- decl = [stmt_type + " " + self .get_dotted_name (classname ), "" , modlist , []]
675
+ decl = [stmt_type + " " + self .get_dotted_name (classname ), "" , modlist , [], None , docstring ]
678
676
if bases :
679
677
decl [1 ] = ": " + ", " .join ([self .get_dotted_name (b ).replace ("." ,"::" ) for b in bases ])
680
678
return stmt_type , classname , True , decl
@@ -704,7 +702,7 @@ def parse_stmt(self, stmt, end_token, use_umat=False):
704
702
# since we filtered off the other places where '(' can normally occur:
705
703
# - code blocks
706
704
# - function pointer typedef's
707
- decl = self .parse_func_decl (stmt , use_umat = use_umat )
705
+ decl = self .parse_func_decl (stmt , use_umat = use_umat , docstring = docstring )
708
706
# we return parse_flag == False to prevent the parser to look inside function/method bodies
709
707
# (except for tracking the nested blocks)
710
708
return stmt_type , "" , False , decl
@@ -759,11 +757,13 @@ def parse(self, hname, wmode=True):
759
757
SCAN = 0 # outside of a comment or preprocessor directive
760
758
COMMENT = 1 # inside a multi-line comment
761
759
DIRECTIVE = 2 # inside a multi-line preprocessor directive
760
+ DOCSTRING = 3 # inside a multi-line docstring
762
761
763
762
state = SCAN
764
763
765
764
self .block_stack = [["file" , hname , True , True , None ]]
766
765
block_head = ""
766
+ docstring = ""
767
767
self .lineno = 0
768
768
self .wrap_mode = wmode
769
769
@@ -789,6 +789,15 @@ def parse(self, hname, wmode=True):
789
789
l = l [pos + 2 :]
790
790
state = SCAN
791
791
792
+ if state == DOCSTRING :
793
+ pos = l .find ("*/" )
794
+ if pos < 0 :
795
+ docstring += l + "\n "
796
+ continue
797
+ docstring += l [:pos ] + "\n "
798
+ l = l [pos + 2 :]
799
+ state = SCAN
800
+
792
801
if state != SCAN :
793
802
print ("Error at %d: invlid state = %d" % (self .lineno , state ))
794
803
sys .exit (- 1 )
@@ -806,11 +815,20 @@ def parse(self, hname, wmode=True):
806
815
807
816
if token == "/*" :
808
817
block_head += " " + l [:pos ]
809
- pos = l .find ("*/" , pos + 2 )
810
- if pos < 0 :
818
+ end_pos = l .find ("*/" , pos + 2 )
819
+ if len (l ) > pos + 2 and l [pos + 2 ] == "*" :
820
+ # '/**', it's a docstring
821
+ if end_pos < 0 :
822
+ state = DOCSTRING
823
+ docstring = l [pos + 3 :] + "\n "
824
+ break
825
+ else :
826
+ docstring = l [pos + 3 :end_pos ]
827
+
828
+ elif end_pos < 0 :
811
829
state = COMMENT
812
830
break
813
- l = l [pos + 2 :]
831
+ l = l [end_pos + 2 :]
814
832
continue
815
833
816
834
if token == "\" " :
@@ -840,7 +858,8 @@ def parse(self, hname, wmode=True):
840
858
if stack_top [self .PROCESS_FLAG ]:
841
859
# even if stack_top[PUBLIC_SECTION] is False, we still try to process the statement,
842
860
# since it can start with "public:"
843
- stmt_type , name , parse_flag , decl = self .parse_stmt (stmt , token )
861
+ docstring = docstring .strip ()
862
+ stmt_type , name , parse_flag , decl = self .parse_stmt (stmt , token , docstring = docstring )
844
863
if decl :
845
864
if stmt_type == "enum" :
846
865
for d in decl :
@@ -854,8 +873,9 @@ def parse(self, hname, wmode=True):
854
873
args = decl [3 ]
855
874
has_mat = len (list (filter (lambda x : x [0 ] in {"Mat" , "vector_Mat" }, args ))) > 0
856
875
if has_mat :
857
- _ , _ , _ , umat_decl = self .parse_stmt (stmt , token , use_umat = True )
876
+ _ , _ , _ , umat_decl = self .parse_stmt (stmt , token , use_umat = True , docstring = docstring )
858
877
decls .append (umat_decl )
878
+ docstring = ""
859
879
if stmt_type == "namespace" :
860
880
chunks = [block [1 ] for block in self .block_stack if block [0 ] == 'namespace' ] + [name ]
861
881
self .namespaces .add ('.' .join (chunks ))
@@ -887,6 +907,8 @@ def print_decls(self, decls):
887
907
"""
888
908
for d in decls :
889
909
print (d [0 ], d [1 ], ";" .join (d [2 ]))
910
+ # Uncomment below line to see docstrings
911
+ # print('"""\n' + d[5] + '\n"""')
890
912
for a in d [3 ]:
891
913
print (" " , a [0 ], a [1 ], a [2 ], end = "" )
892
914
if a [3 ]:
0 commit comments