Acme-EyeDrops

 view release on metacpan or  search on metacpan

lib/Acme/EyeDrops.pm  view on Meta::CPAN

}

sub regex_binmode_print_sightly {
   q#''=~('('.'?'.'{'.# . ascii_to_sightly('binmode(STDOUT);print')
   . q#.'"'.# .  &ascii_to_sightly . q#.'"'.'}'.')')#;
}

sub regex_eval_sightly {
   q#''=~('('.'?'.'{'.# . ascii_to_sightly('eval') . q#.'"'.# .
   &ascii_to_sightly . q#.'"'.'}'.')')#;
}

sub clean_print_sightly {
   qq#print eval '"'.\n\n\n# . &ascii_to_sightly . q#.'"'#;
}

sub clean_binmode_print_sightly {
   qq#binmode(STDOUT);print eval '"'.\n\n\n# .
   &ascii_to_sightly . q#.'"'#;
}

sub clean_eval_sightly {
   qq#eval eval '"'.\n\n\n# . &ascii_to_sightly . q#.'"'#;
}

# -----------------------------------------------------------------

sub _slurp_tfile {
   my $f = shift;
   my $b = shift;
   open my $fh, '<', $f or die "open '$f': $!";
   $b and binmode($fh);
   local $/; my $s = <$fh>; close($fh); $s;
}

# Poor man's properties (see also YAML, java.util.Properties).
# Return ref to property hash.
sub _get_properties {
   my $f = shift;
   open my $fh, '<', $f or die "open '$f': $!";
   my $l; my %h;
   while (defined($l = <$fh>)) {
      chomp($l);
      if ($l =~ s/\\$//) {
         my $n = <$fh>; $n =~ s/^\s+//; $l .= $n;
         redo unless eof($fh);
      }
      $l =~ s/^\s+//; $l =~ s/\s+$//;
      next unless length($l);
      next if $l =~ /^#/;
      my ($k, $v) = split(/\s*:\s*/, $l, 2);
      $h{$k} = $v;
   }
   close($fh);
   return \%h;
}

sub _def_ihandler { print STDERR $_[0] }

# Return largest no. of tokens with total length less than $slen ($slen > 0).
sub _guess_ntok {
   my ($rtok, $sidx, $slen, $rexact) = @_; my $tlen = 0;
   for my $i ($sidx .. $sidx + $slen) {
      ($tlen += length($rtok->[$i])) < $slen or
         return $i - $sidx + (${$rexact} = $tlen == $slen);
   }
   # should never get here
}

sub _guess_compact_ntok {
   my ($rtok, $sidx, $slen, $rexact, $fcompact) = @_; my $tlen = 0;
   for my $i ($sidx .. $sidx + $slen + $slen) {
      ($tlen += length($rtok->[$i]) - ($i > $sidx+1 && $rtok->[$i-1] eq '.'
      && substr($rtok->[$i], 0, 1) eq "'" && substr($rtok->[$i-2], 0, 1)
      eq "'" ? (${$fcompact} = 3) : 0)) < $slen or
         return $i - $sidx + ($tlen > $slen ? 0 : (${$rexact} = 1) +
         ($i > $sidx && $rtok->[$i] eq '.' && substr($rtok->[$i-1], 0, 1)
         eq "'" && $rtok->[$i+1] =~ /^'..$/ ? (${$fcompact} = 1) : 0));
   }
   # should never get here
}

sub _compact_join {
   my ($rtok, $sidx, $n) = @_; my $s = "";
   for my $i ($sidx .. $sidx + $n - 1) {
      if ($i > $sidx+1 && $rtok->[$i-1] eq '.' && substr($rtok->[$i], 0, 1)
      eq "'" && substr($rtok->[$i-2], 0, 1) eq "'") {
         substr($s, -2) = substr($rtok->[$i], 1);  # 'a'.'b' to 'ab'
      } else {
         $s .= $rtok->[$i];
      }
   }
   $s;
}

# Pour $n tokens from @{$rtok} (starting at index $sidx) into string
# of length $slen. Return string or undef if unsuccessful.
sub _pour_chunk {
   my ($rtok, $sidx, $n, $slen) = @_;
   my $eidx = $sidx + $n - 1; my $tlen = 0;
   my $idot = my $iquote = my $i3quote = my $iparen = my $idollar = -1;
   for my $i ($sidx .. $eidx) {
      $tlen += length($rtok->[$i]);
      if    ($rtok->[$i] eq '.') { $idot = $i }
      elsif ($rtok->[$i] eq '(') { $iparen = $i }
      elsif (substr($rtok->[$i], 0, 1) eq '$') { $idollar = $i }
      elsif ($rtok->[$i] =~ /^['"]/) {
         $iquote = $i; $i3quote = $i if length($rtok->[$i]) == 3;
      }
   }
   die "oops" if $tlen >= $slen;
   my $i2 = (my $d = $slen - $tlen) >> 1;
   $idot >= 0 && !($d%3) and return join("", @{$rtok}[$sidx .. $idot-1],
      ".''" x int($d/3), @{$rtok}[$idot .. $eidx]);
   if (!($d&1) and $iquote >= 0 || $idollar >= 0) {
      $iquote = $idollar if $iquote < 0;
      return join("", @{$rtok}[$sidx .. $iquote-1], '(' x $i2 .
      $rtok->[$iquote] . ')' x $i2, @{$rtok}[$iquote+1 .. $eidx]);
   }
   $i3quote >= 0 and return join("", @{$rtok}[$sidx .. $i3quote-1],
      $d == 1 ? '"\\' . substr($rtok->[$i3quote], 1, 1) . '"' :
      '(' x $i2  . '"\\' . substr($rtok->[$i3quote], 1, 1) . '"' .
      ')' x $i2, @{$rtok}[$i3quote+1 .. $eidx]);
   return unless $d == 1;
   $iparen >= 0 and return join("", @{$rtok}[$sidx .. $iparen-1],
      '+' . $rtok->[$iparen], @{$rtok}[$iparen+1 .. $eidx]);
   # ouch, can't test for eq '(' in case next chunk also adds '+'
   $rtok->[$eidx] ne '=' && $rtok->[$sidx+$n] =~ /^['"]/ ?
      join("", @{$rtok}[$sidx .. $eidx], '+') : undef;
}

lib/Acme/EyeDrops.pm  view on Meta::CPAN

   # END block is trouble because it is executed after this filler.
   # Setting $^ or $~ (but not $:) to weird values resets $@.
   # For example: $~='?'&'!'; (this looks like a Perl bug to me).
   # For now, just stick with letters and numbers.
   my @filleqto = (
      [ q#'.'#, '^', q^'~'^ ], [ q#'@'#, '|', q^'('^ ],
      [ q#')'#, '^', q^'['^ ], [ q#'`'#, '|', q^'.'^ ],
      [ q#'('#, '^', q^'}'^ ], [ q#'`'#, '|', q^'!'^ ],
      [ q#')'#, '^', q^'}'^ ], [ q#'*'#, '|', q^'`'^ ],
      [ q#'+'#, '^', q^'_'^ ], [ q#'&'#, '|', q^'@'^ ],
      [ q#'['#, '&', q^'~'^ ], [ q#','#, '^', q^'|'^ ]
   );
   $nfv > @filleqto and die "too many fv";
   my $rem = @filleqto % $nfv;
   $rem and splice(@filleqto, -$rem);
   my $v = -1;
   map(($fv->[++$v % $nfv], '=', @{$_}, ';'), @filleqto);
}

# Pour sightly program $prog into shape defined by string $tlines.
sub pour_sightly {
   my ($tlines, $prog, $gap, $fillv, $compact, $ihandler) = @_;
   $ihandler ||= \&_def_ihandler;
   my $ttlen = 0;
   my @tnlines = map(length() ? [map length, split/([^ ]+)/] : undef,
      split(/\n/, $tlines));
   for my $r (grep($_, @tnlines)) {
      for my $i (0 .. $#{$r}) { $i & 1 and $ttlen += $r->[$i] }
   }
   my $outstr = ""; my @ptok;
   if ($prog) {
      if ($prog =~ /^''=~/g) {
         push(@ptok, ($tlines =~ /(\S+)/ ? length($1) : 0) == 3 ?
            "'?'" : "''", '=~');
      } elsif ($prog =~ /(.*eval.*\n\n\n)/g) {
         $outstr .= $1;
      }
      push(@ptok, $prog =~ /[().&|^]|'\\\\'|.../g);  # ... is "'"|'.'
   }
   my $iendprog = @ptok;
   my @filler = _make_filler(ref($fillv) ? $fillv : [ '$:', '$~', '$^' ]);
   # Note: 11 is the length of a filler item, for example, $:='.'^'~';
   # And there are 6 tokens in each filler item: $: = '.' ^ '~' ;
   push(@ptok, 'Z', (@filler) x (int($ttlen/(11 * int(@filler / 6))) + 1));
   my $sidx = 0;
   for (my $nshape = 1; 1; ++$nshape, $outstr .= "\n" x $gap) {
      for my $rline (@tnlines) {
         unless ($rline) { $outstr .= "\n"; next }
         for my $it (0 .. $#{$rline}) {
            unless ($it & 1) {$outstr .= ' ' x $rline->[$it]; next }
            (my $tlen = $rline->[$it]) == (my $plen = length($ptok[$sidx]))
               and $outstr .= $ptok[$sidx++], next;
            if ($plen > $tlen) {
               $outstr .= '(' x $tlen;
               splice(@ptok, $sidx+1, 0, (')') x $tlen);
               $iendprog += $tlen if $sidx < $iendprog;
               next;
            }
            my $fcompact = my $fexact = 0;
            my $n = $compact ?
            _guess_compact_ntok(\@ptok, $sidx, $tlen, \$fexact, \$fcompact)
            :       _guess_ntok(\@ptok, $sidx, $tlen, \$fexact);
            if ($fexact) {
               $outstr .= $fcompact ? _compact_join(\@ptok, $sidx, $n) :
                             join("", @ptok[$sidx .. $sidx+$n-1]);
               $sidx += $n; next;
            }
            my $str;
            --$n while $n > 0 && !defined($str = $fcompact ?
                    _pour_compact_chunk(\@ptok, $sidx, $n, $tlen) :
                    _pour_chunk(\@ptok, $sidx, $n, $tlen));
            if ($n) { $outstr .= $str; $sidx += $n; next }
            ++$n while $n < $tlen && length($ptok[$sidx+$n]) < 2;
            die "oops ($n >= $tlen)" if $n >= $tlen;
            $outstr .= join("", @ptok[$sidx .. $sidx+$n-1]);
            $sidx += $n;
            $outstr .= '(' x (my $nleft = $tlen - $n);
            splice(@ptok, $sidx+1, 0, (')') x $nleft);
            $iendprog += $nleft if $sidx < $iendprog;
         }
         $outstr .= "\n";
      }
      $ihandler->("$nshape shapes completed.\n");
      last if $sidx >= $iendprog;
   }
   my $eidx = rindex($outstr, 'Z');
   substr($outstr, $eidx, 1) = ';' if $eidx >= 0;
   return $outstr if $sidx == $iendprog || $sidx == $iendprog+1;
   die "oops" if $eidx < 0;
   ref($fillv) or return substr($outstr, 0, $eidx) . (length($fillv) ?
      pour_text(substr($outstr, $eidx), "", 0, $fillv) : "\n");
   (my $idx = rindex($outstr, ';')) >= 0 or return $outstr;
   my @t = substr($outstr, $idx+1) =~
   /[()&|^=;]|\$.|'[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"/g
      or return $outstr;
   my $nl = my $nr = my $ne = 0;
   for my $c (@t) {
      if ($c eq '(') {++$nl} elsif ($c eq ')') {++$nr}
      elsif ($c eq '=') {++$ne}
   }
   if ($ne == 0 || $nl != $nr || $t[-1] eq '=') {
      my $f = ';';  # Trouble: wipe out last bit with filler
      for my $i ($idx+1 .. length($outstr)-2) {
         substr($outstr, $i, 1) =~ tr/ \n// or
            substr($outstr, $i, 1) = $f = $f eq '#' ? ';' : '#';
      }
   } elsif ($t[-1] eq '|' or $t[-1] eq '^' or $t[-1] eq '&') {
      $outstr =~ s/\S(\s*)$/;$1/;
   }
   $outstr;
}

# -----------------------------------------------------------------

sub _border {
   my ($a, $w, $c, $l, $r, $t, $b) = @_;
   my $z = $c x ($w+$l+$r); my $f = $c x $l; my $g = $c x $r;
   for (@{$a}) { $_ = $f . $_ . $g }
   unshift(@{$a}, ($z) x $t); push(@{$a}, ($z) x $b);
}

sub border_shape {



( run in 1.461 second using v1.01-cache-2.11-cpan-d7f47b0818f )