initial working perl-space version
[p5sagit/Devel-Declare.git] / lib / Devel / Declare.pm
index 8349890..558074c 100644 (file)
@@ -4,7 +4,7 @@ use strict;
 use warnings;
 use 5.008001;
 
-our $VERSION = '0.001003';
+our $VERSION = '0.001011';
 
 # mirrored in Declare.xs as DD_HANDLE_*
 
@@ -63,17 +63,16 @@ sub teardown_for {
   my ($class, $target) = @_;
   delete $declarators{$target};
   delete $declarator_handlers{$target};
-  teardown();
 }
 
 my $temp_name;
 my $temp_save;
 
 sub init_declare {
-  my ($usepack, $use, $inpack, $name, $proto) = @_;
+  my ($usepack, $use, $inpack, $name, $proto, $traits) = @_;
   my ($name_h, $XX_h, $extra_code)
        = $declarator_handlers{$usepack}{$use}->(
-           $usepack, $use, $inpack, $name, $proto, defined(wantarray)
+           $usepack, $use, $inpack, $name, $proto, defined(wantarray), $traits
          );
   ($temp_name, $temp_save) = ([], []);
   if ($name) {
@@ -120,7 +119,10 @@ sub build_sub_installer {
     package ${pack};
     my \$body;
     sub ${name} (${proto}) :lvalue {\n"
-    .'my $ret = $body->(@_);
+    .'  if (wantarray) {
+        goto &$body;
+      }
+      my $ret = $body->(@_);
       return $ret;
     };
     sub { ($body) = @_; };';
@@ -142,22 +144,19 @@ sub setup_declarators {
     $sub_proto =~ s/;//; $sub_proto = ';'.$sub_proto;
     #my $installer = $class->build_sub_installer($pack, $name, $proto);
     my $installer = $class->build_sub_installer($pack, $name, '@');
-    my $proto_maker = eval q!
-      sub {
-        my $body = shift;
-        sub (!.$sub_proto.q!) {
-          $body->(@_);
-        };
-      };
-    !;
     $installer->(sub :lvalue {
+#{ no warnings 'uninitialized'; warn 'INST: '.join(', ', @_)."\n"; }
       if (@_) {
         if (ref $_[0] eq 'HASH') {
           shift;
+          if (wantarray) {
+            my @ret = $run->(undef, undef, @_);
+            return @ret;
+          }
           my $r = $run->(undef, undef, @_);
           return $r;
         } else {
-          return $_[1];
+          return @_[1..$#_];
         }
       }
       return my $sv;
@@ -165,21 +164,20 @@ sub setup_declarators {
     $setup_for_args{$name} = [
       $flags,
       sub {
-        my ($usepack, $use, $inpack, $name, $proto) = @_;
-        my $extra_code = $compile->($name, $proto);
-        my $main_handler = $proto_maker->(sub {
+        my ($usepack, $use, $inpack, $name, $proto, $shift_hashref, $traits) = @_;
+        my $extra_code = $compile->($name, $proto, $traits);
+        my $main_handler = sub { shift if $shift_hashref;
           ("DONE", $run->($name, $proto, @_));
-        });
+        };
         my ($name_h, $XX);
         if (defined $proto) {
           $name_h = sub :lvalue { return my $sv; };
           $XX = $main_handler;
         } elsif (defined $name && length $name) {
           $name_h = $main_handler;
-        } else {
-          $extra_code ||= '';
-          $extra_code = '}, sub {'.$extra_code;
         }
+        $extra_code ||= '';
+        $extra_code = '}, sub {'.$extra_code;
         return ($name_h, $XX, $extra_code);
       }
     ];
@@ -198,6 +196,81 @@ sub install_declarator {
   });
 }
 
+sub linestr_callback_rv2cv {
+  my ($name, $offset) = @_;
+  $offset += toke_move_past_token($offset);
+  my $pack = get_curstash_name();
+  my $flags = $declarators{$pack}{$name};
+  my ($found_name, $found_proto);
+  my $in_declare = 0;
+  if ($flags & DECLARE_NAME) {
+    $offset += toke_skipspace($offset);
+    my $linestr = get_linestr();
+    if (substr($linestr, $offset, 2) eq '::') {
+      substr($linestr, $offset, 2) = '';
+      set_linestr($linestr);
+    }
+    if (my $len = toke_scan_word($offset, $flags & DECLARE_PACKAGE)) {
+      $found_name = substr($linestr, $offset, $len);
+      $offset += $len;
+      $in_declare++;
+    }
+  }
+  if ($flags & DECLARE_PROTO) {
+    $offset += toke_skipspace($offset);
+    my $linestr = get_linestr();
+    if (substr($linestr, $offset, 1) eq '(') {
+      my $length = toke_scan_str($offset);
+      $found_proto = get_lex_stuff();
+      clear_lex_stuff();
+      my $replace =
+        ($found_name ? ' ' : '=')
+        .'X'.(' ' x length($found_proto));
+      $linestr = get_linestr();
+      substr($linestr, $offset, $length) = $replace;
+      set_linestr($linestr);
+      $offset += $length;
+      $in_declare++;
+    }
+  }
+  my @args = ($pack, $name, $pack, $found_name, $found_proto);
+  set_in_declare($in_declare);
+  $offset += toke_skipspace($offset);
+  my $linestr = get_linestr();
+  if (substr($linestr, $offset, 1) eq '{') {
+    my $ret = init_declare(@args);
+    $offset++;
+    if (defined $ret && length $ret) {
+      substr($linestr, $offset, 0) = $ret;
+      set_linestr($linestr);
+    }
+  } else {
+    init_declare(@args);
+  }
+  #warn "linestr now ${linestr}";
+}
+
+sub linestr_callback_const {
+  my ($name, $offset) = @_;
+  my $pack = get_curstash_name();
+  my $flags = $declarators{$pack}{$name};
+  if ($flags & DECLARE_NAME) {
+    $offset += toke_move_past_token($offset);
+    $offset += toke_skipspace($offset);
+    if (toke_scan_word($offset, $flags & DECLARE_PACKAGE)) {
+      my $linestr = get_linestr();
+      substr($linestr, $offset, 0) = '::';
+      set_linestr($linestr);
+    }
+  }
+}
+
+sub linestr_callback {
+  my $type = shift;
+  my $meth = "linestr_callback_${type}";
+  __PACKAGE__->can($meth)->(@_);
+}
+
 =head1 NAME
 
 Devel::Declare -