#!/usr/bin/env perl
our
(
$mydir
,
$myname
);
BEGIN {
my
$location
= (-l $0) ? abs_path($0) : $0;
$location
=~ /(.*?)([^\/]+?)_?\z/s or
die
"?"
;
(
$mydir
,
$myname
) = ($1, $2);
}
sub
usage {
print
"usage:
$myname
in out
expand `tail ` syntax in Perl code using `Sub::Call::Tail`, so that it
doesn't depend on that module anymore.
This is just a crude hack (totally imprecise).
";
exit
1;
}
our
$verbose
= 0;
our
$opt_repl
;
GetOptions(
"verbose"
=> \
$verbose
,
"help"
=>
sub
{usage},
"repl"
=> \
$opt_repl
,
) or
exit
1;
usage
unless
@ARGV
== 2;
our
(
$inpath
,
$outpath
) =
@ARGV
;
our
$code
= xgetfile_utf8(
$inpath
);
our
$IDENT
=
qr/\w+(?:::\w+)*/
;
sub
translate {
my
(
$c
) =
@_
;
$c
=~ s/\s+\z//s;
$c
=~ s/^\s+//s;
my
@p
;
if
(
$c
=~ /\
undef
}
elsif
(
@p
=
split
/->/,
$c
and
@p
== 2) {
my
(
$before
,
$after
) =
@p
;
'@_='
.
$after
.
'; goto &{'
.
$before
.
'}'
}
elsif
(
$c
=~ s/^\&//) {
if
(
my
(
$ident
,
$args
) =
$c
=~ m/^(\$${IDENT})\s*(\(.*)/s) {
'@_='
.
$args
.
'; goto &'
.
$ident
}
else
{
die
"dunno about '$c'"
;
}
}
elsif
(
my
(
$ident
,
$args
) =
$c
=~ m/^(
$IDENT
)\s*(\(.*)/s) {
'@_='
.
$args
.
'; goto \&'
.
$ident
}
else
{
undef
}
}
TEST { translate
'&$odd ($n - 1)'
.
"\n\t "
}
'@_=($n - 1); goto &$odd'
;
TEST { translate
'Weakened($even)->($n)'
}
'@_=($n); goto &{Weakened($even)}'
;
TEST {
translate '
&$then
(
$$config
{downcaps} && is_allcaps ($2) ? $1.
lc
($2).
".xhtml"
:
$path0
)'
}
'
@_
=(
$$config
{downcaps} && is_allcaps ($2) ? $1.
lc
($2).
".xhtml"
:
$path0
);
goto
&$then
';
sub
min_maybe {
min
grep
{
defined
$_
}
@_
}
sub
get_line_position_and_indents {
my
$line_position_and_indents
= [];
my
$lineno
= -1;
while
(
$code
=~ /(?:^|\n)([ \t]*)/g) {
$lineno
++;
my
$indentstr
= $1;
my
$pos
=
pos
(
$code
);
my
$pos0
=
$pos
-
length
(
$indentstr
);
my
$i
= 0;
for
(
split
//,
$indentstr
) {
if
(
$_
eq
' '
) {
$i
++
}
elsif
(
$_
eq
"\t"
) {
$i
= (
int
(
$i
/ 8) + 1) * 8
}
else
{
die
"??"
}
}
push
@$line_position_and_indents
, [
$lineno
,
$pos0
,
$i
];
}
$line_position_and_indents
}
our
$line_position_and_indents
= get_line_position_and_indents;
sub
find_line_by_pos {
my
(
$pos
) =
@_
;
my
$prevline
=
$$line_position_and_indents
[0];
for
(
@$line_position_and_indents
[1 ..
$#$line_position_and_indents
]) {
my
(
$lineno
,
$pos0
,
$i
) =
@$_
;
return
$prevline
if
$pos
<
$pos0
;
$prevline
=
$_
;
}
return
$prevline
}
sub
expand_tail_at_pos {
my
$pos
=
pos
(
$code
);
my
$maybe_endpos_semicolon
=
pos
(
$code
) - 1
if
$code
=~ /;/g;
my
(
$tailline_lineno
,
$tailline_pos0
,
$tailline_i
)
= @{ find_line_by_pos
$pos
};
my
$afterline
;
for
my
$lineno
(
$tailline_lineno
+ 1 ..
$#$line_position_and_indents
) {
$afterline
=
$$line_position_and_indents
[
$lineno
];
last
if
$$afterline
[2] <=
$tailline_i
;
}
my
$maybe_endpos_indent
=
$$afterline
[1] - 1
if
$afterline
;
my
$maybe_endpos
= min_maybe(
$maybe_endpos_semicolon
,
$maybe_endpos_indent
);
if
(
defined
$maybe_endpos
) {
my
$endpos
=
$maybe_endpos
;
my
$args
=
substr
$code
,
$pos
,
$endpos
-
$pos
;
if
(
defined
(
my
$replacement
= translate
$args
)) {
my
$startpos
=
$pos
- 4;
substr
$code
,
$startpos
,
$endpos
-
$startpos
,
$replacement
;
$line_position_and_indents
= get_line_position_and_indents;
pos
(
$code
) =
$startpos
+
length
$replacement
;
}
else
{
pos
(
$code
) =
$pos
+ 1;
}
}
else
{
warn
"wrong2"
}
}
if
(
$opt_repl
) {
FP::Repl::repl();
exit
;
}
else
{
$code
=~ s=\n[\t ]*
while
(
$code
=~ m/(?<!\$)\btail\b/g) {
expand_tail_at_pos
}
$code
=~ s/\buse\s
*Sub::Call::Tail
\b.*?;//s;
my
$o
= xopen_write
$outpath
;
$o
->xprint(
$code
);
$o
->xclose;
chmod
0755,
$outpath
if
-x
$inpath
;
}