package Function; use strict; use warnings; use Util; use FunctionBase; BEGIN { use Exporter (); our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS); # set the version for version checking $VERSION = 1.00; @ISA = qw(FunctionBase); @EXPORT = qw(&func1 &func2 &func4); %EXPORT_TAGS = ( ); # your exported package globals go here, # as well as any optionally exported functions @EXPORT_OK = qw($Var1 %Hashit &func3); } our @EXPORT_OK; ################################################## ### Function # Commonly used algorithm for parsing a function declaration into # its component pieces # # class Function : FunctionBase # { # string rettype; # bool const; # bool static; # string name; e.g. gtk_accelerator_valid # string c_name; # string array param_type; # string array param_name; # string array param_default_value; # string in_module; e.g. Gtk # string signal_when. e.g. first, last, or both. # string class e.g. GtkButton ( == of-object. Useful for signal because their names are not unique. # string entity_type. e.g. method or signal # } sub new_empty() { my $self = {}; bless $self; return $self; } # $objFunction new($function_declaration, $objWrapParser) sub new($$) { #Parse a function/method declaration. #e.g. guint gtk_something_set_thing(guint a, const gchar* something) my ($line, $objWrapParser) = @_; my $self = {}; bless $self; #Initialize member data: $$self{rettype} = ""; $$self{rettype_needs_ref} = 0; #Often the gtk function doesn't do an extra ref for the receiver. $$self{const} = 0; $$self{name} = ""; $$self{param_types} = []; $$self{param_names} = []; $$self{param_default_values} = []; $$self{in_module} = ""; $$self{class} = ""; $$self{entity_type} = "method"; $line =~ s/^\s+//; # Remove leading whitespace. $line =~ s/\s+/ /g; # Compress white space. if ($line =~ /^static\s+([^()]+)\s+(\S+)\s*\((.*)\)\s*$/) { $$self{rettype} = $1; $$self{name} = $2; $$self{c_name} = $2; $self->parse_param($3); $$self{static} = 1; } elsif ($line =~ /^([^()]+)\s+(\S+)\s*\((.*)\)\s*(const)*$/) { no warnings qw(uninitialized); # disable the uninitialize warning for $4 $$self{rettype} = $1; $$self{name} = $2; $$self{c_name} = $2; $self->parse_param($3); $$self{const} = ($4 eq "const"); } else { $objWrapParser->error("fail to parse $line\n"); } return $self; } # $objFunction new_ctor($function_declaration, $objWrapParser) # Like new(), but the function_declaration doesn't need a return type. sub new_ctor($$) { #Parse a function/method declaration. #e.g. guint gtk_something_set_thing(guint a, const gchar* something) my ($line, $objWrapParser) = @_; my $self = {}; bless $self; #Initialize member data: $$self{rettype} = ""; $$self{rettype_needs_ref} = 0; $$self{const} = 0; $$self{name} = ""; $$self{param_types} = []; $$self{param_names} = []; $$self{param_default_values} = []; $$self{in_module} = ""; $$self{class} = ""; $$self{entity_type} = "method"; $line =~ s/^\s+//; # Remove leading whitespace. $line =~ s/\s+/ /g; # Compress white space. if ($line =~ /^(\S+)\s*\((.*)\)\s*/) { $$self{name} = $1; $$self{c_name} = $2; $self->parse_param($2); } else { $objWrapParser->error("fail to parse $line\n"); } return $self; } # $num num_args() sub num_args #($) { my ($self) = @_; my $param_types = $$self{param_types}; return $#$param_types+1; } # parses C++ parameter lists. # forms a list of types, names, and initial values # (we don't currently use values) sub parse_param($$) { my ($self, $line) = @_; my $type = ""; my $name = ""; my $value = ""; my $id = 0; my $has_value = 0; my $param_types = $$self{param_types}; my $param_names = $$self{param_names}; my $param_default_values = $$self{param_default_values}; # clean up space and handle empty case $line = string_trim($line); $line =~ s/\s+/ /g; # Compress whitespace. return if ($line =~ /^$/); # parse through argument list my @str = (); my $par = 0; foreach (split(/(const )|([,=&*()])|(<[^,]*>)|(\s+)/, $line)) #special characters OR OR whitespace. { next if ( !defined($_) or $_ eq "" ); if ( $_ eq "(" ) #Detect the opening bracket. { push(@str, $_); $par++; #Increment the number of parameters. next; } elsif ( $_ eq ")" ) { push(@str, $_); $par--; #Decrement the number of parameters. next; } elsif ( $par || /^(const )|(<[^,]*>)|([*&])|(\s+)/ ) #TODO: What's happening here? { push(@str, $_); #This looks like part of the type, so we store it. next; } elsif ( $_ eq "=" ) #Default value { $type = join("", @str); #The type is everything before the = character. @str = (); #Wipe it so that it will only contain the default value, which comes next. $has_value = 1; next; } elsif ( $_ eq "," ) #The end of one parameter: { if ($has_value) { $value = join("", @str); # If there's a default value, then it's the part before the next ",". } else { $type = join("", @str); } if ($name eq "") { $name = sprintf("p%s", $#$param_types + 2) } $type = string_trim($type); push(@$param_types, $type); push(@$param_names, $name); push(@$param_default_values, $value); #Clear variables, ready for the next parameter. @str = (); $type= ""; $value = ""; $has_value = 0; $name = ""; $id = 0; next; } if ($has_value) { push(@str, $_); next; } $id++; $name = $_ if ($id == 2); push(@str, $_) if ($id == 1); if ($id > 2) { print STDERR "Can't parse $line.\n"; print STDERR " arg type so far: $type\n"; print STDERR " arg name so far: $name\n"; print STDERR " arg default value so far: $value\n"; } } # handle last argument (There's no , at the end.) if ($has_value) { $value = join("", @str); } else { $type = join("", @str); } if ($name eq "") { $name = sprintf("p%s", $#$param_types + 2) } $type = string_trim($type); push(@$param_types, $type); push(@$param_names, $name); push(@$param_default_values, $value); } # add_parameter_autoname($, $type, $name) # Adds e.g "sometype somename" sub add_parameter_autoname($$) { my ($self, $type) = @_; add_parameter($self, $type, ""); } # add_parameter($, $type, $name) # Adds e.g GtkSomething* p1" sub add_parameter($$$) { my ($self, $type, $name) = @_; $type = string_unquote($type); $type =~ s/-/ /g; my $param_names = $$self{param_names}; if ($name eq "") { $name = sprintf("p%s", $#$param_names + 2); } push(@$param_names, $name); my $param_types = $$self{param_types}; push(@$param_types, $type); return $self; } # $string get_refdoc_comment() # Generate a readable prototype for signals. sub get_refdoc_comment($) { my ($self) = @_; my $str = " /**\n"; $str .= " * \@par Prototype:\n"; $str .= " * $$self{rettype} on_my_\%$$self{name}("; my $param_names = $$self{param_names}; my $param_types = $$self{param_types}; my $num_params = scalar(@$param_types); # List the parameters: for(my $i = 0; $i < $num_params; ++$i) { $str .= $$param_types[$i] . ' ' . $$param_names[$i]; $str .= ", " if($i < $num_params - 1); } $str .= ")\n"; $str .= " */"; return $str; } sub get_is_const($) { my ($self) = @_; return $$self{const}; } 1; # indicate proper module load.