2017-03-17 10:47:01 +01:00
#!/usr/bin/perl
use strict ;
use warnings ;
use File::Basename ;
2017-05-23 09:34:27 +02:00
use File::Spec ;
2017-04-27 10:38:12 +02:00
use Getopt::Long ;
2017-05-23 09:34:27 +02:00
use YAML::Tiny ;
2017-05-22 09:01:45 +02:00
no if $] >= 5.018000 , warnings = > 'experimental::smartmatch' ;
2017-03-17 10:47:01 +01:00
2017-04-07 08:50:57 +02:00
use constant PRIVATE = > 0 ;
use constant PROTECTED = > 1 ;
use constant PUBLIC = > 2 ;
2017-05-18 07:50:23 +02:00
use constant STRICT = > 10 ;
use constant UNSTRICT = > 11 ;
2017-04-27 10:38:12 +02:00
# read arguments
my $ debug = 0 ;
2017-05-12 09:47:03 +02:00
die ( "usage: $0 [-debug] headerfile\n" ) unless GetOptions ( "debug" = > \ $ debug ) && @ ARGV == 1 ;
2017-04-27 10:38:12 +02:00
my $ headerfile = $ ARGV [ 0 ] ;
2017-03-27 09:27:12 +02:00
2017-04-27 10:38:12 +02:00
# read file
2017-04-20 11:18:29 +02:00
open ( my $ handle , "<" , $ headerfile ) || die "Couldn't open '" . $ headerfile . "' for reading because: " . $! ;
2017-05-29 11:26:44 +02:00
chomp ( my @ INPUT_LINES = <$handle> ) ;
2017-04-20 11:18:29 +02:00
close $ handle ;
2017-03-17 10:47:01 +01:00
2017-05-23 09:34:27 +02:00
# config
my $ cfg_file = File::Spec - > catfile ( dirname ( __FILE__ ) , 'sipify.yaml' ) ;
my $ yaml = YAML::Tiny - > read ( $ cfg_file ) ;
my $ SIP_CONFIG = $ yaml - > [ 0 ] ;
2017-03-27 09:27:12 +02:00
# contexts
my $ SIP_RUN = 0 ;
my $ HEADER_CODE = 0 ;
2017-04-29 16:16:58 +02:00
my @ ACCESS = ( PUBLIC ) ;
2017-05-22 09:01:45 +02:00
my @ CLASSNAME = ( ) ;
2017-05-19 21:56:31 +02:00
my @ EXPORTED = ( 0 ) ;
2017-03-28 09:06:45 +02:00
my $ MULTILINE_DEFINITION = 0 ;
2017-05-29 11:26:44 +02:00
my $ ACTUAL_CLASS = '' ;
my $ COMMENT = '' ;
my $ GLOB_IFDEF_NESTING_IDX = 0 ;
my @ GLOB_BRACKET_NESTING_IDX = ( 0 ) ;
my $ PRIVATE_SECTION_LINE = '' ;
my $ RETURN_TYPE = '' ;
my $ IS_OVERRIDE = 0 ;
my % QFLAG_HASH ;
my $ LINE_COUNT = @ INPUT_LINES ;
my $ LINE_IDX = 0 ;
my $ LINE ;
my @ OUTPUT = ( ) ;
sub read_line {
my $ new_line = $ INPUT_LINES [ $ LINE_IDX ] ;
$ LINE_IDX + + ;
$ debug == 0 or print sprintf ( 'LIN:%d DEPTH:%d ACC:%d BRCK:%d SIP:%d MLT:%d CLSS: %s/%d' ,
$ LINE_IDX ,
$# ACCESS ,
$ ACCESS [ $# ACCESS ] ,
$ GLOB_BRACKET_NESTING_IDX [ $# GLOB_BRACKET_NESTING_IDX ] ,
$ SIP_RUN ,
$ MULTILINE_DEFINITION ,
$ ACTUAL_CLASS ,
$# CLASSNAME ) . " :: " . $ new_line . "\n" ;
return $ new_line ;
}
2017-03-17 10:47:01 +01:00
2017-05-29 11:26:44 +02:00
sub write_output {
my ( $ dbg_code , $ out ) = @ _ ;
if ( $ debug == 1 ) {
$ dbg_code = sprintf ( "%d %-4s :: " , $ LINE_IDX , $ dbg_code ) ;
}
else {
$ dbg_code = '' ;
}
push @ OUTPUT , $ dbg_code . $ out ;
}
2017-03-17 10:47:01 +01:00
2017-05-29 11:26:44 +02:00
sub dbg_info {
if ( $ debug == 1 ) {
push @ OUTPUT , $ _ [ 0 ] . "\n" ;
print $ LINE_IDX . " " . @ ACCESS . " " . $ SIP_RUN . " " . $ MULTILINE_DEFINITION . " " . $ _ [ 0 ] . "\n" ;
}
2017-04-27 10:38:12 +02:00
}
2017-05-29 11:26:44 +02:00
2017-06-06 08:02:31 +02:00
sub exit_with_error {
die "! Sipify error in $headerfile at line :: $LINE_IDX\n! $_[0]\n" ;
}
2017-05-29 11:26:44 +02:00
sub write_header_footer {
push @ OUTPUT , "/************************************************************************\n" ;
push @ OUTPUT , " * This file has been generated automatically from *\n" ;
push @ OUTPUT , " * *\n" ;
push @ OUTPUT , sprintf " * %-*s *\n" , 68 , $ headerfile ;
push @ OUTPUT , " * *\n" ;
push @ OUTPUT , " * Do not edit manually ! Edit header and run scripts/sipify.pl again *\n" ;
push @ OUTPUT , " ************************************************************************/\n" ;
2017-04-27 10:38:12 +02:00
}
2017-05-29 11:26:44 +02:00
sub processDoxygenLine {
2017-05-23 09:34:27 +02:00
my $ line = $ _ [ 0 ] ;
# remove \a formatting
$ line =~ s/\\a (.+?)\b/``$1``/g ;
# replace :: with . (changes c++ style namespace/class directives to Python style)
$ line =~ s/::/./g ;
# replace nullptr with None (nullptr means nothing to Python devs)
$ line =~ s/\bnullptr\b/None/g ;
# replace \returns with :return:
$ line =~ s/\\return(s)?/:return:/g ;
if ( $ line =~ m/[\\@](ingroup|class)/ ) {
return ""
}
if ( $ line =~ m/\\since .*?([\d\.]+)/i ) {
return ".. versionadded:: $1\n" ;
}
if ( $ line =~ m/\\see (.*)/ ) {
return ".. seealso:: $1\n" ;
}
if ( $ line =~ m/[\\@]note (.*)/ ) {
return ".. note::\n\n $1\n" ;
}
if ( $ line =~ m/[\\@]brief (.*)/ ) {
return " $1\n" ;
}
return "$line\n" ;
}
2017-05-18 14:16:42 +02:00
sub detect_and_remove_following_body_or_initializerlist {
2017-06-02 23:35:10 +02:00
# https://regex101.com/r/ZaP3tC/7
2017-04-30 13:26:45 +02:00
do { no warnings 'uninitialized' ;
2017-06-02 23:35:10 +02:00
if ( $ LINE =~ m/^(\s*)?((?:(?:explicit|static|const|unsigned|virtual)\s+)*)(([\w:]+(<.*?>)?\s+[*&]?)?(~?\w+|(\w+::)?operator.{1,2})\s*\(([\w=()\/ ,&*<>."-]|::)*\)( +(?:const|SIP_[A-Z_]*?))*)\s*((\s*[:,]\s+\w+\(.*\))*\s*\{.*\};?|(?!;))(\s*\/\/.*)?$/
2017-05-29 11:26:44 +02:00
|| $ LINE =~ m/SIP_SKIP\s*(?!;)\s*(\/\/.*)?$/
|| $ LINE =~ m/^\s*class.*SIP_SKIP/ ) {
2017-04-30 13:26:45 +02:00
dbg_info ( "remove constructor definition, function bodies, member initializing list" ) ;
2017-05-18 16:39:21 +02:00
my $ newline = "$1$2$3;" ;
2017-05-29 11:26:44 +02:00
remove_following_body_or_initializerlist ( ) unless $ LINE =~ m/{.*}(\s*SIP_\w+)*\s*(\/\/.*)?$/ ;
$ LINE = $ newline ;
2017-05-16 08:39:03 +02:00
}
} ;
}
2017-05-18 14:16:42 +02:00
sub remove_following_body_or_initializerlist {
2017-05-16 08:39:03 +02:00
do { no warnings 'uninitialized' ;
dbg_info ( "remove constructor definition, function bodies, member initializing list" ) ;
2017-05-29 11:26:44 +02:00
$ LINE = read_line ( ) ;
while ( $ LINE =~ m/^\s*[:,]\s+([\w<>]|::)+\(.*?\)/ ) {
2017-05-16 08:39:03 +02:00
dbg_info ( " member initializing list" ) ;
2017-05-29 11:26:44 +02:00
$ LINE = read_line ( ) ;
2017-05-16 08:39:03 +02:00
}
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*\{/ ) {
2017-05-16 08:39:03 +02:00
my $ nesting_index = 0 ;
2017-05-29 11:26:44 +02:00
while ( $ LINE_IDX < $ LINE_COUNT ) {
2017-05-16 08:39:03 +02:00
dbg_info ( " remove body" ) ;
2017-05-29 11:26:44 +02:00
$ nesting_index += $ LINE =~ tr /\{/ / ;
$ nesting_index -= $ LINE =~ tr /\}/ / ;
2017-05-16 08:39:03 +02:00
if ( $ nesting_index == 0 ) {
last ;
}
2017-05-29 11:26:44 +02:00
$ LINE = read_line ( ) ;
2017-04-30 13:26:45 +02:00
}
}
} ;
}
2017-06-02 12:03:19 +02:00
sub fix_annotations {
my $ line = $ _ [ 0 ] ;
# printed annotations
$ line =~ s/\bSIP_ABSTRACT\b/\/Abstract\// ;
$ line =~ s/\bSIP_ALLOWNONE\b/\/AllowNone\// ;
$ line =~ s/\bSIP_ARRAY\b/\/Array\//g ;
$ line =~ s/\bSIP_ARRAYSIZE\b/\/ArraySize\//g ;
$ line =~ s/\bSIP_DEPRECATED\b/\/Deprecated\//g ;
$ line =~ s/\bSIP_CONSTRAINED\b/\/Constrained\//g ;
$ line =~ s/\bSIP_EXTERNAL\b/\/External\//g ;
$ line =~ s/\bSIP_FACTORY\b/\/Factory\// ;
$ line =~ s/\bSIP_IN\b/\/In\//g ;
$ line =~ s/\bSIP_INOUT\b/\/In,Out\//g ;
$ line =~ s/\bSIP_KEEPREFERENCE\b/\/KeepReference\// ;
$ line =~ s/\bSIP_NODEFAULTCTORS\b/\/NoDefaultCtors\// ;
$ line =~ s/\bSIP_OUT\b/\/Out\//g ;
$ line =~ s/\bSIP_RELEASEGIL\b/\/ReleaseGIL\// ;
$ line =~ s/\bSIP_TRANSFER\b/\/Transfer\//g ;
$ line =~ s/\bSIP_TRANSFERBACK\b/\/TransferBack\// ;
$ line =~ s/\bSIP_TRANSFERTHIS\b/\/TransferThis\// ;
$ line =~ s/SIP_PYNAME\(\s*(\w+)\s*\)/\/PyName=$1\// ;
# combine multiple annotations
# https://regex101.com/r/uvCt4M/3
do { no warnings 'uninitialized' ;
$ line =~ s/\/(\w+(=\w+)?)\/\s*\/(\w+(=\w+)?)\//\/$1,$3\// ;
( ! $ 3 ) or dbg_info ( "combine multiple annotations -- works only for 2" ) ;
} ;
# unprinted annotations
$ line =~ s/(\w+)(\<(?>[^<>]|(?2))*\>)?\s+SIP_PYALTERNATIVETYPE\(\s*\'?([^()']+)(\(\s*(?:[^()]++|(?2))*\s*\))?\'?\s*\)/$3/g ;
$ line =~ s/=\s+[^=]*?\s+SIP_PYARGDEFAULT\(\s*\'?([^()']+)(\(\s*(?:[^()]++|(?2))*\s*\))?\'?\s*\)/= $1/g ;
# remove argument
if ( $ line =~ m/SIP_PYARGREMOVE/ ) {
dbg_info ( "remove arg" ) ;
if ( $ MULTILINE_DEFINITION == 1 ) {
my $ prev_line = pop ( @ OUTPUT ) =~ s/\n$// r ;
# update multi line status
my $ parenthesis_balance = 0 ;
$ parenthesis_balance += $ prev_line =~ tr /\(/ / ;
$ parenthesis_balance -= $ prev_line =~ tr /\)/ / ;
if ( $ parenthesis_balance == 1 ) {
$ MULTILINE_DEFINITION = 0 ;
}
# concat with above line to bring previous commas
$ line =~ s/^\s+// ;
$ line = "$prev_line $line\n" ;
}
# see https://regex101.com/r/5iNptO/4
$ line =~ s/(?<coma>, +)?(const )?(\w+)(\<(?>[^<>]|(?4))*\>)?\s+[\w&*]+\s+SIP_PYARGREMOVE( = [^()]*(\(\s*(?:[^()]++|(?6))*\s*\))?)?(?(<coma>)|,?)//g ;
}
$ line =~ s/SIP_FORCE// ;
return $ line ;
2017-05-08 07:34:37 +02:00
}
2017-05-10 16:09:20 +02:00
# detect a comment block, return 1 if found
2017-05-18 07:50:23 +02:00
# if STRICT comment block shall begin at beginning of line (no code in front)
sub detect_comment_block {
my % args = ( strict_mode = > STRICT , @ _ ) ;
# dbg_info("detect comment strict:" . $args{strict_mode} );
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*\/\*/ || $ args { strict_mode } == UNSTRICT && $ LINE =~ m/\/\*/ ) {
2017-05-18 07:50:23 +02:00
dbg_info ( "found comment block" ) ;
2017-05-10 16:09:20 +02:00
do { no warnings 'uninitialized' ;
2017-05-29 11:26:44 +02:00
$ COMMENT = processDoxygenLine ( $ LINE =~ s/^\s*\/\*(\*)?(.*?)\n?$/$2/ r ) ;
2017-05-10 16:09:20 +02:00
} ;
2017-05-29 11:26:44 +02:00
$ COMMENT =~ s/^\s*$// ;
while ( $ LINE !~ m/\*\/\s*(\/\/.*?)?$/ ) {
$ LINE = read_line ( ) ;
$ COMMENT . = processDoxygenLine ( $ LINE =~ s/\s*\*?(.*?)(\/)?\n?$/$1/ r ) ;
2017-05-10 16:09:20 +02:00
}
2017-05-29 11:26:44 +02:00
$ COMMENT =~ s/\n+$// ;
2017-05-10 16:09:20 +02:00
return 1 ;
}
return 0 ;
}
2017-04-30 13:26:45 +02:00
2017-05-29 11:26:44 +02:00
write_header_footer ( ) ;
# write some code in front of line to know where the output comes from
$ debug == 0 or push @ OUTPUT , "CODE SIP_RUN MultiLine\n" ;
2017-04-27 10:38:12 +02:00
# main loop
2017-05-29 11:26:44 +02:00
while ( $ LINE_IDX < $ LINE_COUNT ) {
$ ACTUAL_CLASS = $ CLASSNAME [ $# CLASSNAME ] unless $# CLASSNAME < 0 ;
$ LINE = read_line ( ) ;
if ( $ LINE =~ m/^\s*SIP_FEATURE\( (\w+) \)(.*)$/ ) {
write_output ( "SF1" , "%Feature $1$2\n" ) ;
2017-04-02 12:53:31 +02:00
next ;
}
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*SIP_IF_FEATURE\( (\!?\w+) \)(.*)$/ ) {
write_output ( "SF2" , "%If ($1)$2\n" ) ;
2017-04-02 12:53:31 +02:00
next ;
}
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*SIP_CONVERT_TO_SUBCLASS_CODE(.*)$/ ) {
write_output ( "SCS" , "%ConvertToSubClassCode$1\n" ) ;
2017-04-02 12:53:31 +02:00
next ;
}
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*SIP_END(.*)$/ ) {
write_output ( "SEN" , "%End$1\n" ) ;
2017-04-02 12:53:31 +02:00
next ;
}
2017-03-17 10:47:01 +01:00
# Skip preprocessor stuff
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*#/ ) {
2017-04-26 07:47:58 +02:00
# skip #if 0 blocks
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*#if (0|defined\(Q_OS_WIN\))/ ) {
2017-05-16 08:39:03 +02:00
dbg_info ( "skipping #if $1 block" ) ;
2017-04-26 07:47:58 +02:00
my $ nesting_index = 0 ;
2017-05-29 11:26:44 +02:00
while ( $ LINE_IDX < $ LINE_COUNT ) {
$ LINE = read_line ( ) ;
if ( $ LINE =~ m/^\s*#if(def)?\s+/ ) {
2017-04-26 07:47:58 +02:00
$ nesting_index + + ;
}
2017-05-29 11:26:44 +02:00
elsif ( $ nesting_index == 0 && $ LINE =~ m/^\s*#(endif|else)/ ) {
$ COMMENT = '' ;
2017-04-26 07:47:58 +02:00
last ;
}
2017-05-29 11:26:44 +02:00
elsif ( $ nesting_index != 0 && $ LINE =~ m/^\s*#(endif)/ ) {
2017-04-26 07:47:58 +02:00
$ nesting_index - - ;
}
}
next ;
}
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*#ifdef SIP_RUN/ ) {
2017-03-27 09:27:12 +02:00
$ SIP_RUN = 1 ;
2017-04-29 16:16:58 +02:00
if ( $ ACCESS [ $# ACCESS ] == PRIVATE ) {
dbg_info ( "writing private content" ) ;
2017-05-29 11:26:44 +02:00
write_output ( "PRV1" , $ PRIVATE_SECTION_LINE . "\n" ) ;
2017-03-27 09:27:12 +02:00
}
next ;
}
2017-03-28 09:06:45 +02:00
if ( $ SIP_RUN == 1 ) {
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*#endif/ ) {
if ( $ GLOB_IFDEF_NESTING_IDX == 0 ) {
2017-03-27 09:27:12 +02:00
$ SIP_RUN = 0 ;
next ;
}
else {
2017-05-29 11:26:44 +02:00
$ GLOB_IFDEF_NESTING_IDX - - ;
2017-03-27 09:27:12 +02:00
}
}
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*#if(def)?\s+/ ) {
$ GLOB_IFDEF_NESTING_IDX + + ;
2017-03-27 09:27:12 +02:00
}
# if there is an else at this level, code will be ignored i.e. not SIP_RUN
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*#else/ && $ GLOB_IFDEF_NESTING_IDX == 0 ) {
while ( $ LINE_IDX < $ LINE_COUNT ) {
$ LINE = read_line ( ) ;
if ( $ LINE =~ m/^\s*#if(def)?\s+/ ) {
$ GLOB_IFDEF_NESTING_IDX + + ;
2017-03-27 09:27:12 +02:00
}
2017-05-29 11:26:44 +02:00
elsif ( $ LINE =~ m/^\s*#endif/ ) {
if ( $ GLOB_IFDEF_NESTING_IDX == 0 ) {
$ COMMENT = '' ;
2017-03-27 09:27:12 +02:00
$ SIP_RUN = 0 ;
last ;
}
else {
2017-05-29 11:26:44 +02:00
$ GLOB_IFDEF_NESTING_IDX - - ;
2017-03-27 09:27:12 +02:00
}
}
}
next ;
}
}
2017-05-29 11:26:44 +02:00
elsif ( $ LINE =~ m/^\s*#ifndef SIP_RUN/ ) {
2017-03-27 09:27:12 +02:00
# code is ignored here
2017-05-29 11:26:44 +02:00
while ( $ LINE_IDX < $ LINE_COUNT ) {
$ LINE = read_line ( ) ;
if ( $ LINE =~ m/^\s*#if(def)?\s+/ ) {
$ GLOB_IFDEF_NESTING_IDX + + ;
2017-03-27 09:27:12 +02:00
}
2017-05-29 11:26:44 +02:00
elsif ( $ LINE =~ m/^\s*#else/ && $ GLOB_IFDEF_NESTING_IDX == 0 ) {
2017-03-27 09:27:12 +02:00
# code here will be printed out
2017-04-29 16:16:58 +02:00
if ( $ ACCESS [ $# ACCESS ] == PRIVATE ) {
dbg_info ( "writing private content" ) ;
2017-05-29 11:26:44 +02:00
write_output ( "PRV2" , $ PRIVATE_SECTION_LINE . "\n" ) ;
2017-03-27 09:27:12 +02:00
}
$ SIP_RUN = 1 ;
last ;
}
2017-05-29 11:26:44 +02:00
elsif ( $ LINE =~ m/^\s*#endif/ ) {
if ( $ GLOB_IFDEF_NESTING_IDX == 0 ) {
$ COMMENT = '' ;
2017-03-27 09:27:12 +02:00
$ SIP_RUN = 0 ;
last ;
}
else {
2017-05-29 11:26:44 +02:00
$ GLOB_IFDEF_NESTING_IDX - - ;
2017-03-27 09:27:12 +02:00
}
}
}
next ;
}
else {
2017-03-17 10:47:01 +01:00
next ;
}
}
2017-03-27 09:27:12 +02:00
# TYPE HEADER CODE
2017-03-28 09:06:45 +02:00
if ( $ HEADER_CODE && $ SIP_RUN == 0 ) {
2017-03-27 09:27:12 +02:00
$ HEADER_CODE = 0 ;
2017-05-29 11:26:44 +02:00
write_output ( "HCE" , "%End\n" ) ;
2017-03-27 09:27:12 +02:00
}
2017-03-17 10:47:01 +01:00
# Skip forward declarations
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*(class|struct) \w+(?<external> *SIP_EXTERNAL)?;\s*(\/\/.*)?$/ ) {
2017-05-24 14:46:43 +02:00
if ( $+ { external } ) {
dbg_info ( 'do not skip external forward declaration' ) ;
2017-05-29 11:26:44 +02:00
$ COMMENT = '' ;
2017-05-24 14:46:43 +02:00
}
else
{
dbg_info ( 'skipping forward declaration' ) ;
next ;
}
2017-03-17 10:47:01 +01:00
}
# Skip Q_OBJECT, Q_PROPERTY, Q_ENUM, Q_GADGET
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*Q_(OBJECT|ENUMS|PROPERTY|GADGET|DECLARE_METATYPE|DECLARE_TYPEINFO|DECL_DEPRECATED).*?$/ ) {
2017-03-17 10:47:01 +01:00
next ;
}
2017-03-27 09:27:12 +02:00
# SIP_SKIP
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/SIP_SKIP/ ) {
2017-04-30 13:26:45 +02:00
dbg_info ( 'SIP SKIP!' ) ;
2017-05-29 11:26:44 +02:00
$ COMMENT = '' ;
2017-04-30 13:26:45 +02:00
# if multiline definition, remove previous lines
if ( $ MULTILINE_DEFINITION == 1 ) {
dbg_info ( 'SIP_SKIP with MultiLine' ) ;
my $ opening_line = '' ;
while ( $ opening_line !~ m/^[^()]*\(([^()]*\([^()]*\)[^()]*)*[^()]*$/ ) {
2017-05-29 11:26:44 +02:00
$ opening_line = pop ( @ OUTPUT ) ;
2017-06-06 08:02:31 +02:00
$# OUTPUT >= 0 or exit_with_error ( 'could not reach opening definition' ) ;
2017-04-30 13:26:45 +02:00
}
2017-04-27 10:38:12 +02:00
dbg_info ( "removed multiline definition of SIP_SKIP method" ) ;
2017-04-20 14:37:22 +02:00
$ MULTILINE_DEFINITION = 0 ;
2017-04-24 14:52:10 +02:00
}
2017-04-30 13:26:45 +02:00
# also skip method body if there is one
2017-05-18 14:16:42 +02:00
detect_and_remove_following_body_or_initializerlist ( ) ;
2017-04-30 13:26:45 +02:00
# line skipped, go to next iteration
next ;
2017-03-27 09:27:12 +02:00
}
2017-04-29 16:16:58 +02:00
# Detect comment block
2017-05-10 16:09:20 +02:00
if ( detect_comment_block ( ) ) {
2017-04-29 16:16:58 +02:00
next ;
}
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*struct(\s+\w+_EXPORT)?\s+\w+$/ ) {
2017-05-22 09:01:45 +02:00
dbg_info ( " going to struct => public" ) ;
push @ CLASSNAME , $ CLASSNAME [ $# CLASSNAME ] ; # fake new class since struct has considered similarly
push @ ACCESS , PUBLIC ;
push @ EXPORTED , $ EXPORTED [ - 1 ] ;
2017-05-29 11:26:44 +02:00
push @ GLOB_BRACKET_NESTING_IDX , 0 ;
2017-05-22 09:01:45 +02:00
}
# class declaration started
2017-05-31 13:58:24 +02:00
# https://regex101.com/r/6FWntP/7
if ( $ LINE =~ m/^(\s*class)\s+([A-Z]+_EXPORT\s+)?(\w+)(\s*\:\s*(public|protected|private)\s+\w+(<([\w]|::)+>)?(::\w+(<\w+>)?)*(,\s*(public|protected|private)\s+\w+(<([\w]|::)+>)?(::\w+(<\w+>)?)*)*)?(?<annot>\s*SIP_\w+)?(?!;)$/ ) {
2017-05-22 09:01:45 +02:00
dbg_info ( "class definition started" ) ;
push @ ACCESS , PUBLIC ;
push @ EXPORTED , 0 ;
2017-05-29 11:26:44 +02:00
push @ GLOB_BRACKET_NESTING_IDX , 0 ;
2017-05-22 09:01:45 +02:00
my @ template_inheritance_template = ( ) ;
my @ template_inheritance_class = ( ) ;
do { no warnings 'uninitialized' ;
push @ CLASSNAME , $ 3 ;
dbg_info ( "class: " . $ CLASSNAME [ $# CLASSNAME ] ) ;
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/\b[A-Z]+_EXPORT\b/ || $# CLASSNAME != 0 || $ INPUT_LINES [ $ LINE_IDX - 2 ] =~ m/^\s*template</ ) {
2017-05-24 07:22:46 +02:00
# class should be exported except those not at top level or template classes
# if class is not exported, then its methods should be (checked whenever leaving out the class)
$ EXPORTED [ - 1 ] + + ;
}
2017-05-22 09:01:45 +02:00
} ;
2017-05-29 11:26:44 +02:00
$ LINE = "$1 $3" ;
2017-05-22 09:01:45 +02:00
# Inheritance
if ( $ 4 ) {
my $ m = $ 4 ;
$ m =~ s/public //g ;
$ m =~ s/[,:]?\s*private \w+(::\w+)?//g ;
# detect template based inheritance
while ( $ m =~ /[,:]\s+((?!QList)\w+)<((\w|::)+)>/g ) {
dbg_info ( "template class" ) ;
push @ template_inheritance_template , $ 1 ;
push @ template_inheritance_class , $ 2 ;
}
$ m =~ s/(\b(?!QList)\w+)<((?:\w|::)+)>/$1${2}Base/g ; # use the typeded as template inheritance
$ m =~ s/(\w+)<((?:\w|::)+)>//g ; # remove remaining templates
$ m =~ s/([:,])\s*,/$1/g ;
$ m =~ s/(\s*[:,])?\s*$// ;
2017-05-29 11:26:44 +02:00
$ LINE . = $ m ;
2017-05-22 09:01:45 +02:00
}
if ( defined $+ { annot } )
{
2017-05-29 11:26:44 +02:00
$ LINE . = "$+{annot}" ;
2017-06-02 12:03:19 +02:00
$ LINE = fix_annotations ( $ LINE ) ;
2017-05-22 09:01:45 +02:00
}
2017-05-29 11:26:44 +02:00
$ LINE . = "\n{\n" ;
if ( $ COMMENT !~ m/^\s*$/ ) {
$ LINE . = "%Docstring\n$COMMENT\n%End\n" ;
2017-05-22 09:01:45 +02:00
}
2017-05-29 11:26:44 +02:00
$ LINE . = "\n%TypeHeaderCode\n#include \"" . basename ( $ headerfile ) . "\"" ;
2017-05-22 09:01:45 +02:00
# for template based inheritance, add a typedef to define the base type
# add it to the class and to the TypeHeaderCode
# also include the template header
# see https://www.riverbankcomputing.com/pipermail/pyqt/2015-May/035893.html
while ( @ template_inheritance_template ) {
my $ tpl = pop @ template_inheritance_template ;
my $ cls = pop @ template_inheritance_class ;
2017-05-23 09:34:27 +02:00
my $ tpl_header = lc $ tpl . ".h" ;
if ( exists $ SIP_CONFIG - > { class_headerfile } - > { $ tpl } ) {
$ tpl_header = $ SIP_CONFIG - > { class_headerfile } - > { $ tpl } ;
}
2017-05-29 11:26:44 +02:00
$ LINE = "\ntypedef $tpl<$cls> ${tpl}${cls}Base;\n\n$LINE" ;
$ LINE . = "\n#include \"" . $ tpl_header . "\"" ;
$ LINE . = "\ntypedef $tpl<$cls> ${tpl}${cls}Base;" ;
2017-05-22 09:01:45 +02:00
}
if ( PRIVATE ~ ~ @ ACCESS && $# ACCESS != 0 ) {
# do not write anything in PRIVATE context and not top level
dbg_info ( "skipping class in private context" ) ;
next ;
}
$ ACCESS [ $# ACCESS ] = PRIVATE ; # private by default
2017-05-29 11:26:44 +02:00
write_output ( "CLS" , "$LINE\n" ) ;
2017-05-22 09:01:45 +02:00
# Skip opening curly bracket, incrementing hereunder
2017-05-29 11:26:44 +02:00
my $ skip = read_line ( ) ;
2017-06-06 08:02:31 +02:00
$ skip =~ m/^\s*{\s*$/ or exit_with_error ( "expecting { after class definition" ) ;
2017-05-29 11:26:44 +02:00
$ GLOB_BRACKET_NESTING_IDX [ $# GLOB_BRACKET_NESTING_IDX ] + + ;
2017-05-22 09:01:45 +02:00
2017-05-29 11:26:44 +02:00
$ COMMENT = '' ;
2017-05-22 09:01:45 +02:00
$ HEADER_CODE = 1 ;
$ ACCESS [ $# ACCESS ] = PRIVATE ;
next ;
}
2017-04-29 16:16:58 +02:00
# bracket balance in class/struct tree
if ( $ SIP_RUN == 0 ) {
my $ bracket_balance = 0 ;
2017-05-29 11:26:44 +02:00
$ bracket_balance += $ LINE =~ tr /\{/ / ;
$ bracket_balance -= $ LINE =~ tr /\}/ / ;
2017-04-29 16:16:58 +02:00
if ( $ bracket_balance != 0 ) {
2017-05-29 11:26:44 +02:00
$ GLOB_BRACKET_NESTING_IDX [ $# GLOB_BRACKET_NESTING_IDX ] += $ bracket_balance ;
if ( $ GLOB_BRACKET_NESTING_IDX [ $# GLOB_BRACKET_NESTING_IDX ] == 0 ) {
2017-04-29 16:16:58 +02:00
dbg_info ( " going up in class/struct tree" ) ;
2017-05-15 16:30:34 +02:00
if ( $# ACCESS > 0 ) {
2017-05-29 11:26:44 +02:00
pop ( @ GLOB_BRACKET_NESTING_IDX ) ;
2017-04-29 16:16:58 +02:00
pop ( @ ACCESS ) ;
2017-06-06 08:02:31 +02:00
exit_with_error ( "Class $CLASSNAME[$#CLASSNAME] should be exported with appropriate [LIB]_EXPORT macro. If this should not be available in python, wrap it in a `#ifndef SIP_RUN` block." )
2017-05-24 07:22:46 +02:00
if $ EXPORTED [ - 1 ] == 0 ;
2017-05-21 10:09:57 +02:00
pop @ EXPORTED ;
2017-04-29 16:16:58 +02:00
}
2017-05-22 09:01:45 +02:00
pop ( @ CLASSNAME ) ;
2017-05-15 16:30:34 +02:00
if ( $# ACCESS == 0 ) {
2017-04-30 13:26:45 +02:00
dbg_info ( "reached top level" ) ;
2017-04-29 16:16:58 +02:00
# top level should stasy public
dbg_info
$ ACCESS [ $# ACCESS ] = PUBLIC ;
}
2017-05-29 11:26:44 +02:00
$ COMMENT = '' ;
$ RETURN_TYPE = '' ;
$ PRIVATE_SECTION_LINE = '' ;
2017-04-29 16:16:58 +02:00
}
2017-05-29 11:26:44 +02:00
dbg_info ( "new bracket balance: @GLOB_BRACKET_NESTING_IDX" ) ;
2017-04-29 16:16:58 +02:00
}
}
2017-03-27 09:27:12 +02:00
# Private members (exclude SIP_RUN)
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*private( slots)?:/ ) {
2017-04-29 16:16:58 +02:00
$ ACCESS [ $# ACCESS ] = PRIVATE ;
2017-05-29 11:26:44 +02:00
$ PRIVATE_SECTION_LINE = $ LINE ;
$ COMMENT = '' ;
2017-04-29 16:16:58 +02:00
dbg_info ( "going private" ) ;
2017-03-27 09:27:12 +02:00
next ;
}
2017-05-29 11:26:44 +02:00
elsif ( $ LINE =~ m/^\s*(public( slots)?|signals):.*$/ ) {
2017-04-29 16:16:58 +02:00
dbg_info ( "going public" ) ;
$ ACCESS [ $# ACCESS ] = PUBLIC ;
2017-05-29 11:26:44 +02:00
$ COMMENT = '' ;
2017-04-07 08:50:57 +02:00
}
2017-05-29 11:26:44 +02:00
elsif ( $ LINE =~ m/^\s*(protected)( slots)?:.*$/ ) {
2017-04-29 16:16:58 +02:00
dbg_info ( "going protected" ) ;
$ ACCESS [ $# ACCESS ] = PROTECTED ;
2017-05-29 11:26:44 +02:00
$ COMMENT = '' ;
2017-04-24 08:48:12 +02:00
}
2017-05-29 11:26:44 +02:00
elsif ( $ ACCESS [ $# ACCESS ] == PRIVATE && $ LINE =~ m/SIP_FORCE/ ) {
2017-04-29 16:16:58 +02:00
dbg_info ( "private with SIP_FORCE" ) ;
2017-05-29 11:26:44 +02:00
write_output ( "PRV3" , $ PRIVATE_SECTION_LINE . "\n" ) ;
2017-04-07 08:50:57 +02:00
}
2017-05-22 09:01:45 +02:00
elsif ( PRIVATE ~ ~ @ ACCESS && $ SIP_RUN == 0 ) {
2017-05-29 11:26:44 +02:00
$ COMMENT = '' ;
2017-04-29 16:16:58 +02:00
next ;
2017-03-27 09:27:12 +02:00
}
2017-04-26 11:31:56 +02:00
# Skip operators
2017-06-01 10:54:33 +02:00
if ( $ ACCESS [ $# ACCESS ] != PRIVATE && $ LINE =~ m/operator(=|<<|>>|->)\s*\(/ ) {
2017-04-29 16:16:58 +02:00
dbg_info ( "skip operator" ) ;
2017-05-18 14:16:42 +02:00
detect_and_remove_following_body_or_initializerlist ( ) ;
2017-03-28 09:06:45 +02:00
next ;
}
2017-03-27 09:27:12 +02:00
# save comments and do not print them, except in SIP_RUN
2017-03-28 09:06:45 +02:00
if ( $ SIP_RUN == 0 ) {
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*\/\// ) {
if ( $ LINE =~ m/^\s*\/\/\!\s*(.*?)\n?$/ ) {
$ COMMENT = processDoxygenLine ( $ 1 ) ;
$ COMMENT =~ s/\n+$// ;
2017-04-30 14:33:08 +02:00
}
2017-05-29 11:26:44 +02:00
elsif ( $ INPUT_LINES [ $ LINE_IDX - 1 ] !~ m/\*\/.*/ ) {
$ COMMENT = '' ;
2017-04-30 14:33:08 +02:00
}
2017-03-27 09:27:12 +02:00
next ;
}
2017-03-17 10:47:01 +01:00
}
2017-03-27 09:27:12 +02:00
# Enum declaration
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*enum\s+\w+.*?$/ ) {
write_output ( "ENU1" , "$LINE\n" ) ;
if ( $ LINE =~ m/\{((\s*\w+)(\s*=\s*[\w\s\d<|]+.*?)?(,?))+\s*\}/ ) {
2017-04-24 14:52:10 +02:00
# one line declaration
2017-06-06 08:02:31 +02:00
$ LINE !~ m/=/ or exit_with_error ( "spify.pl does not handle enum one liners with value assignment. Use multiple lines instead." ) ;
2017-04-24 14:54:07 +02:00
next ;
2017-04-24 14:52:10 +02:00
}
else
{
2017-05-29 11:26:44 +02:00
$ LINE = read_line ( ) ;
2017-06-06 08:02:31 +02:00
$ LINE =~ m/^\s*\{\s*$/ or exit_with_error ( 'Unexpected content: enum should be followed by {' ) ;
2017-05-29 11:26:44 +02:00
write_output ( "ENU2" , "$LINE\n" ) ;
while ( $ LINE_IDX < $ LINE_COUNT ) {
$ LINE = read_line ( ) ;
2017-05-10 16:09:20 +02:00
if ( detect_comment_block ( ) ) {
next ;
}
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/\};/ ) {
2017-04-24 14:52:10 +02:00
last ;
}
2017-06-02 12:03:19 +02:00
do { no warnings 'uninitialized' ;
my $ enum_decl = $ LINE =~ s/(\s*\w+)(\s+SIP_\w+(?:\([^()]+\))?)?(?:\s*=\s*[\w\s\d<|]+.*?)?(,?).*$/$1$2$3/ r ;
$ enum_decl = fix_annotations ( $ enum_decl ) ;
write_output ( "ENU3" , "$enum_decl\n" ) ;
} ;
2017-05-18 07:50:23 +02:00
detect_comment_block ( strict_mode = > UNSTRICT ) ;
2017-03-27 09:27:12 +02:00
}
2017-05-29 11:26:44 +02:00
write_output ( "ENU4" , "$LINE\n" ) ;
2017-04-24 14:52:10 +02:00
# enums don't have Docstring apparently
2017-05-29 11:26:44 +02:00
$ COMMENT = '' ;
2017-04-24 14:52:10 +02:00
next ;
2017-03-27 09:27:12 +02:00
}
}
2017-04-08 10:06:55 +02:00
# skip non-method member declaration in non-public sections
2017-05-22 10:17:51 +02:00
# https://regex101.com/r/gUBZUk/9
2017-05-16 08:39:03 +02:00
if ( $ SIP_RUN != 1 &&
$ ACCESS [ $# ACCESS ] != PUBLIC &&
2017-05-29 11:26:44 +02:00
$ LINE =~ m/^\s*(?:template<\w+>\s+)?(?:(const|mutable|static|friend|unsigned)\s+)*\w+(::\w+)?(<([\w<> *&,()]|::)+>)?(,?\s+\*?\w+( = (-?\d+(\.\d+)?|\w+(\([^()]+\))?)|\[\d+\])?)+;/ ) {
2017-04-27 10:38:12 +02:00
dbg_info ( "skip non-method member declaration in non-public sections" ) ;
2017-04-05 09:46:14 +02:00
next ;
}
2017-05-02 20:34:25 +02:00
# remove static const value assignment
2017-05-22 09:01:45 +02:00
# https://regex101.com/r/DyWkgn/4
2017-06-06 08:02:31 +02:00
$ LINE !~ m/^\s*const static \w+/ or exit_with_error ( "const static should be written static const in $CLASSNAME[$#CLASSNAME]" ) ;
2017-06-01 15:39:31 +02:00
$ LINE =~ s/^(\s*static const(?:expr)? \w+(?:<(?:[\w()<>, ]|::)+>)? \w+) = .*([|;])\s*(\/\/.*)?$/$1;/ ;
2017-05-22 09:01:45 +02:00
if ( defined $ 2 && $ 2 =~ m/\|/ ) {
dbg_info ( "multiline const static assignment" ) ;
my $ skip = '' ;
while ( $ skip !~ m/;\s*(\/\/.*?)?$/ ) {
2017-05-29 11:26:44 +02:00
$ skip = read_line ( ) ;
2017-05-22 09:01:45 +02:00
}
}
2017-05-02 20:34:25 +02:00
2017-04-19 15:49:22 +02:00
# remove struct member assignment
2017-05-29 11:26:44 +02:00
if ( $ SIP_RUN != 1 && $ ACCESS [ $# ACCESS ] == PUBLIC && $ LINE =~ m/^(\s*\w+[\w<> *&:,]* \*?\w+) = \w+(\([^()]+\))?;/ ) {
2017-04-27 10:38:12 +02:00
dbg_info ( "remove struct member assignment" ) ;
2017-05-29 11:26:44 +02:00
$ LINE = "$1;" ;
2017-04-19 15:49:22 +02:00
}
2017-04-03 13:53:29 +10:00
# catch Q_DECLARE_FLAGS
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^(\s*)Q_DECLARE_FLAGS\(\s*(.*?)\s*,\s*(.*?)\s*\)\s*$/ ) {
my $ ACTUAL_CLASS = $ CLASSNAME [ $# CLASSNAME ] ;
dbg_info ( "Declare flags: $ACTUAL_CLASS" ) ;
$ LINE = "$1typedef QFlags<$ACTUAL_CLASS::$3> $2;\n" ;
$ QFLAG_HASH { "$ACTUAL_CLASS::$2" } = "$ACTUAL_CLASS::$3" ;
2017-04-03 13:53:29 +10:00
}
# catch Q_DECLARE_OPERATORS_FOR_FLAGS
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^(\s*)Q_DECLARE_OPERATORS_FOR_FLAGS\(\s*(.*?)\s*\)\s*$/ ) {
my $ flag = $ QFLAG_HASH { $ 2 } ;
$ LINE = "$1QFlags<$flag> operator|($flag f1, QFlags<$flag> f2);\n" ;
2017-04-03 13:53:29 +10:00
}
2017-04-19 11:16:09 +02:00
# remove Q_INVOKABLE
2017-05-29 11:26:44 +02:00
$ LINE =~ s/^(\s*)Q_INVOKABLE /$1/ ;
2017-04-19 11:16:09 +02:00
2017-03-27 09:27:12 +02:00
do { no warnings 'uninitialized' ;
2017-03-29 16:15:07 +02:00
# remove keywords
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/\boverride\b/ ) {
$ IS_OVERRIDE = 1 ;
2017-04-20 13:58:56 +02:00
# handle multiline definition to add virtual keyword on opening line
if ( $ MULTILINE_DEFINITION == 1 ) {
2017-05-29 11:26:44 +02:00
my $ virtual_line = $ LINE ;
my $ virtual_line_idx = $ LINE_IDX ;
2017-04-27 10:38:12 +02:00
dbg_info ( "handle multiline definition to add virtual keyword on opening line" ) ;
2017-04-20 13:58:56 +02:00
while ( $ virtual_line !~ m/^[^()]*\(([^()]*\([^()]*\)[^()]*)*[^()]*$/ ) {
$ virtual_line_idx - - ;
2017-05-29 11:26:44 +02:00
$ virtual_line = $ INPUT_LINES [ $ virtual_line_idx ] ;
2017-06-06 08:02:31 +02:00
$ virtual_line_idx >= 0 or exit_with_error ( 'could not reach opening definition' ) ;
2017-04-20 13:58:56 +02:00
}
if ( $ virtual_line !~ m/^(\s*)virtual\b(.*)$/ ) {
2017-05-29 11:26:44 +02:00
my $ idx = $# OUTPUT - $ LINE_IDX + $ virtual_line_idx + 2 ;
#print "len: $#OUTPUT line_idx: $LINE_IDX virt: $virtual_line_idx\n"idx: $idx\n$OUTPUT[$idx]\n";
$ OUTPUT [ $ idx ] = $ virtual_line =~ s/^(\s*?)\b(.*)$/$1 virtual $2\n/ r ;
2017-04-20 13:58:56 +02:00
}
}
2017-05-29 11:26:44 +02:00
elsif ( $ LINE !~ m/^(\s*)virtual\b(.*)$/ ) {
2017-04-18 11:00:13 +10:00
#sip often requires the virtual keyword to be present, or it chokes on covariant return types
#in overridden methods
2017-05-29 11:26:44 +02:00
$ LINE =~ s/^(\s*?)\b(.*)$/$1virtual $2\n/ ;
2017-04-18 11:00:13 +10:00
}
2017-04-17 11:03:02 +10:00
}
2017-05-18 14:16:42 +02:00
# keyword fixes
2017-05-29 11:26:44 +02:00
$ LINE =~ s/^(\s*template<)(?:class|typename) (\w+>)(.*)$/$1$2$3/ ;
$ LINE =~ s/\s*\boverride\b// ;
$ LINE =~ s/^(\s*)?(const )?(virtual |static )?inline /$1$2$3/ ;
2017-06-01 15:39:31 +02:00
$ LINE =~ s/\bconstexpr\b/const/ ;
2017-05-29 11:26:44 +02:00
$ LINE =~ s/\bnullptr\b/0/g ;
$ LINE =~ s/\s*=\s*default\b//g ;
2017-03-27 09:27:12 +02:00
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ /\w+_EXPORT/ ) {
2017-05-21 10:09:57 +02:00
$ EXPORTED [ - 1 ] + + ;
2017-05-29 11:26:44 +02:00
$ LINE =~ s/\b\w+_EXPORT\s+//g ;
2017-05-21 10:09:57 +02:00
}
2017-05-19 21:56:31 +02:00
2017-04-26 08:22:27 +02:00
# remove constructor definition, function bodies, member initializing list
2017-05-18 14:16:42 +02:00
$ SIP_RUN == 1 or detect_and_remove_following_body_or_initializerlist ( ) ;
2017-04-07 11:23:53 +10:00
2017-04-18 09:53:00 +10:00
# remove inline declarations
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^(\s*)?(static |const )*(([\w:]+(<.*?>)?\s+(\*|&)?)?(\w+)( (?:const*?))*)\s*(\{.*\});(\s*\/\/.*)?$/ ) {
2017-04-20 11:18:29 +02:00
my $ newline = "$1$3;" ;
2017-05-29 11:26:44 +02:00
$ LINE = $ newline ;
2017-04-18 09:53:00 +10:00
}
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*(?:const |virtual |static |inline )*(?!explicit)([\w:]+(?:<.*?>)?)\s+(?:\*|&)?(?:\w+|operator.{1,2})\(.*$/ ) {
2017-04-07 11:23:53 +10:00
if ( $ 1 !~ m/(void|SIP_PYOBJECT|operator|return|QFlag)/ ) {
2017-05-29 11:26:44 +02:00
$ RETURN_TYPE = $ 1 ;
2017-04-07 11:23:53 +10:00
# replace :: with . (changes c++ style namespace/class directives to Python style)
2017-05-29 11:26:44 +02:00
$ RETURN_TYPE =~ s/::/./g ;
2017-04-07 11:23:53 +10:00
# replace with builtin Python types
2017-05-29 11:26:44 +02:00
$ RETURN_TYPE =~ s/\bdouble\b/float/ ;
$ RETURN_TYPE =~ s/\bQString\b/str/ ;
$ RETURN_TYPE =~ s/\bQStringList\b/list of str/ ;
if ( $ RETURN_TYPE =~ m/^(?:QList|QVector)<\s*(.*?)[\s*\*]*>$/ ) {
$ RETURN_TYPE = "list of $1" ;
2017-04-07 11:23:53 +10:00
}
2017-05-29 11:26:44 +02:00
if ( $ RETURN_TYPE =~ m/^QSet<\s*(.*?)[\s*\*]*>$/ ) {
$ RETURN_TYPE = "set of $1" ;
2017-04-07 11:23:53 +10:00
}
}
}
2017-03-27 09:27:12 +02:00
} ;
# deleted functions
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^(\s*)?(const )?(virtual |static )?((\w+(<.*?>)?\s+(\*|&)?)?(\w+|operator.{1,2})\(.*?(\(.*\))*.*\)( const)?)\s*= delete;(\s*\/\/.*)?$/ ) {
$ COMMENT = '' ;
2017-03-29 16:15:07 +02:00
next ;
2017-03-27 09:27:12 +02:00
}
2017-04-24 11:50:46 +02:00
# remove export macro from struct definition
2017-05-29 11:26:44 +02:00
$ LINE =~ s/^(\s*struct )\w+_EXPORT (.+)$/$1$2/ ;
2017-04-24 11:50:46 +02:00
2017-06-02 12:03:19 +02:00
$ LINE = fix_annotations ( $ LINE ) ;
2017-04-24 08:48:12 +02:00
2017-03-27 09:27:12 +02:00
# fix astyle placing space after % character
2017-05-29 11:26:44 +02:00
$ LINE =~ s/\s*% (MappedType|Type(Header)?Code|Module(Header)?Code|Convert(From|To)TypeCode|MethodCode|End)/%$1/ ;
$ LINE =~ s/\/\s+GetWrapper\s+\//\/GetWrapper\// ;
2017-03-27 09:27:12 +02:00
2017-05-29 11:26:44 +02:00
write_output ( "NOR" , "$LINE\n" ) ;
2017-03-28 09:06:45 +02:00
# multiline definition (parenthesis left open)
if ( $ MULTILINE_DEFINITION == 1 ) {
2017-04-29 16:16:17 +02:00
dbg_info ( "on multiline" ) ;
# https://regex101.com/r/DN01iM/2
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^([^()]+(\((?:[^()]++|(?1))*\)))*[^()]*\)[^()]*$/ ) {
2017-04-29 16:16:17 +02:00
$ MULTILINE_DEFINITION = 0 ;
dbg_info ( "ending multiline" ) ;
# remove potential following body
2017-05-29 11:26:44 +02:00
if ( $ SIP_RUN == 0 && $ LINE !~ m/(\{.*\}|;)\s*(\/\/.*)?$/ ) {
2017-04-29 16:16:17 +02:00
dbg_info ( "remove following body of multiline def" ) ;
2017-05-29 11:26:44 +02:00
my $ last_line = $ LINE ;
2017-05-18 14:16:42 +02:00
remove_following_body_or_initializerlist ( ) ;
2017-04-29 16:16:17 +02:00
# add missing semi column
2017-05-29 11:26:44 +02:00
my $ dummy = pop ( @ OUTPUT ) ;
write_output ( "MLT" , "$last_line;\n" ) ;
2017-04-29 16:16:17 +02:00
}
}
else
{
next ;
}
2017-03-28 09:06:45 +02:00
}
2017-05-29 11:26:44 +02:00
elsif ( $ LINE =~ m/^[^()]+\([^()]*([^()]*\([^()]*\)[^()]*)*[^)]*$/ ) {
2017-04-27 10:38:12 +02:00
dbg_info ( "Mulitline detected" ) ;
2017-03-28 09:06:45 +02:00
$ MULTILINE_DEFINITION = 1 ;
next ;
}
# write comment
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*$/ )
2017-04-17 10:49:29 +10:00
{
2017-05-29 11:26:44 +02:00
$ IS_OVERRIDE = 0 ;
2017-04-17 10:49:29 +10:00
next ;
}
2017-05-29 11:26:44 +02:00
if ( $ LINE =~ m/^\s*template<.*>/ ) {
2017-05-18 14:16:42 +02:00
# do not comment now for templates, wait for class definition
next ;
}
2017-05-29 11:26:44 +02:00
elsif ( $ LINE =~ m/\/\// ||
$ LINE =~ m/\s*typedef / ||
$ LINE =~ m/\s*struct / ||
$ LINE =~ m/operator\[\]\(/ ||
$ LINE =~ m/operator==/ ||
( $ LINE =~ m/operator[!+-=*\/\[\]]{1,2}/ && $# ACCESS == 0 ) || # apparently global operators cannot be documented
$ LINE =~ m/^\s*%\w+(.*)?$/ ) {
2017-05-01 00:13:26 +02:00
dbg_info ( 'skipping comment' ) ;
2017-05-29 11:26:44 +02:00
$ COMMENT = '' ;
$ RETURN_TYPE = '' ;
2017-03-28 09:06:45 +02:00
}
2017-05-29 11:26:44 +02:00
elsif ( $ COMMENT !~ m/^\s*$/ || $ RETURN_TYPE ne '' ) {
if ( $ IS_OVERRIDE == 1 && $ COMMENT =~ m/^\s*$/ ) {
2017-04-17 11:03:02 +10:00
# overridden method with no new docs - so don't create a Docstring and use
# parent class Docstring
2017-04-07 11:23:53 +10:00
}
2017-04-17 11:03:02 +10:00
else {
2017-05-01 00:13:26 +02:00
dbg_info ( 'writing comment' ) ;
2017-05-29 11:26:44 +02:00
write_output ( "CM1" , "%Docstring\n" ) ;
if ( $ COMMENT !~ m/^\s*$/ ) {
write_output ( "CM2" , "$COMMENT\n" ) ;
2017-04-17 11:03:02 +10:00
}
2017-05-29 11:26:44 +02:00
if ( $ RETURN_TYPE ne '' ) {
write_output ( "CM3" , " :rtype: $RETURN_TYPE\n" ) ;
2017-04-17 11:03:02 +10:00
}
2017-05-29 11:26:44 +02:00
write_output ( "CM4" , "%End\n" ) ;
2017-04-07 11:23:53 +10:00
}
2017-05-29 11:26:44 +02:00
$ COMMENT = '' ;
$ RETURN_TYPE = '' ;
$ IS_OVERRIDE = 0 ;
2017-03-28 09:06:45 +02:00
}
2017-03-17 10:47:01 +01:00
}
2017-05-29 11:26:44 +02:00
write_header_footer ( ) ;
2017-04-20 11:18:29 +02:00
2017-05-29 11:26:44 +02:00
print join ( '' , @ OUTPUT ) ;