#!/usr/bin/perl -w
our
$VERSION
= 0;
my
$action
=
'run'
;
my
$verbose
= 0;
my
$stdin
= 0;
my
$gp_f
= 1;
{
my
$help
=
sub
{
print
"gp-inline [--options] filename...\n"
;
my
@opts
=
([
'-h, --help'
,
'Print this help'
],
[
'-v, --version'
,
'Print program version'
],
[
'--verbose'
,
'Print extra messages'
],
[
'--run'
,
'Run the inline tests in each FILENAME'
],
[
'--extract'
,
'Print the test code from each FILENAME'
],
[
'--defines'
,
'Print just the definitions from each FILENAME'
],
);
my
$width
= 2 + max (
map
{
length
(
$_
->[0]) }
@opts
);
foreach
(
@opts
) {
printf
"%-*s%s\n"
,
$width
,
$_
->[0],
$_
->[1];
}
print
"\n"
;
exit
0;
};
GetOptions (
'help|?'
=>
$help
,
version
=>
sub
{
print
"$FindBin::Script version $VERSION\n"
;
exit
0;
},
run
=>
sub
{
$action
=
'run'
},
defines
=>
sub
{
$action
=
'defines'
},
extract
=>
sub
{
$action
=
'extract'
},
f
=> \
$gp_f
,
stdin
=> \
$stdin
,
verbose
=> \
$verbose
,
)
or
exit
1;
(
$stdin
||
@ARGV
) or
$help
->();
}
my
$total_files
= 0;
my
$total_expressions
= 0;
my
$harness
;
if
(
$action
eq
'run'
) {
$harness
= IPC::Run::start([
'gp'
,
'--quiet'
,
(
$gp_f
?
'-f'
: ()),
'--default'
,
'recover=0'
,
],
'<pipe'
, \
*GP
)
or
die
"Cannot run gp"
;
my
$flags
=
fcntl
(GP, Fcntl::F_GETFL(),0);
$flags
&= ~ POSIX::O_NONBLOCK();
fcntl
(GP, Fcntl::F_SETFL(),
$flags
)
or
die
"fcntl: $!"
;
}
sub
output {
if
(
$harness
) {
print
GP
@_
or
die
"Error writing to gp sub-process: $!"
;
}
else
{
print
@_
;
}
}
sub
output_test {
if
(
$action
ne
'defines'
) {
output(
@_
);
}
}
output_test(
<<'HERE');
check_location = "";
check_count = 0; check_good = 0; check_bad = 0;
check(x) =
{
check_count++;
if(x, check_good++,
check_bad++;
print(check_location"check fail"));
print1();
}
check_equal(got,want) =
{
check_count++;
if(x==y,check_good++,
check_bad++;
print(check_location"check fail got "got" want "want));
print1();
}
HERE
if
(
$verbose
) {
output(
"\\e 1\n"
);
}
if
(
$stdin
) {
test_fh(\
*STDIN
,
'(stdin)'
);
}
test_files(
@ARGV
);
sub
test_files {
foreach
my
$filename
(
@_
) {
test_file(
$filename
);
}
}
sub
test_file {
my
(
$filename
) =
@_
;
$total_files
++;
open
my
$fh
,
'<'
,
$filename
or
die
"Cannot open $filename: $!"
;
test_fh(
$fh
,
$filename
);
close
$fh
or
die
"Error closing $filename: $!"
;
}
sub
test_fh {
my
(
$fh
,
$filename
) =
@_
;
my
$end
=
''
;
my
$within
=
''
;
my
$within_linenum
;
my
$join
=
''
;
my
$linenum
= 1;
while
(
defined
(
my
$line
=
readline
$fh
)) {
$linenum
= $.;
if
(
$line
=~ s{^(([\
my
$c_comment
= $3;
my
$type
= ($6 ||
''
);
if
(
$c_comment
) {
$line
=~ s{\*/\s*$}{};
}
$line
=~ s/\n$//;
$type
=
uc
(
$type
);
if
(
$type
eq
''
) {
output_test(
"check_location="
,gp_quote(
$filename
),
"\":\""
,
gp_quote(
$linenum
),
"\": \""
,
"; check((()-> $line )())\n"
);
}
elsif
(
$type
eq
'DEFINE'
) {
output(
$line
,
"\n"
);
}
elsif
(
$type
eq
'CONSTANT'
) {
output(
"$line = {"
);
$join
=
"\n"
;
$end
=
"};\n"
;
$within
=
'Constant'
;
$within_linenum
=
$linenum
;
}
elsif
(
$type
eq
'VECTOR'
) {
output(
"$line = {["
);
$join
=
"\n"
;
$end
=
"]};\n"
;
$within
=
'Vector'
;
$within_linenum
=
$linenum
;
}
elsif
(
$type
eq
'MATRIX'
) {
output(
"$line = {["
);
$join
=
"\n"
;
$end
=
"]};\n"
;
$within
=
'Matrix'
;
$within_linenum
=
$linenum
;
}
elsif
(
$type
eq
'END'
) {
if
(
defined
$end
) {
output(
$end
);
undef
$end
;
}
else
{
print
STDERR
"$filename:$linenum: End without Begin\n"
;
exit
1;
}
$within
=
''
;
}
else
{
print
STDERR
"$filename:$linenum: ignoring unrecognised \"$type\"\n"
;
}
}
elsif
(
$within
eq
'Constant'
||
$within
eq
'Vector'
||
$within
eq
'Matrix'
) {
$line
=~ s/(^|[^\\])(\\\\)*%.*//;
$line
=~ s/\\[,;]/ /g;
$line
=~ s/\\(phantom|hspace){[^}]*}/ /g;
$line
=~ s/\{([+-])\}/$1/g;
$line
=~ s/&/,/g;
$line
=~ s|\\[td]?frac\{([^}]*)}\{([^}]*)}|($1)/($2)|g;
$line
=~ s/\\(
sqrt
\d+)\s*(i?)/$1$2/g;
$line
=~ s/([0-9.)]+)[ \t]
*i
/$1
*I
/g;
$line
=~ s/\bi[ \t]*([0-9.]+)/I*$1/g;
$line
=~ s/([+-])[ \t]*(I)\b/$1$2/g;
$line
=~ s/\bi\b/I/g;
if
(
$within
eq
'Matrix'
) {
$line
=~ s/\\\\/;/g;
}
else
{
$line
=~ s/;/,/g;
}
$line
=~ s|[^-+*/^()0-9.I,; \t]||sg;
$line
=~ s/(^|;)(\s*,)+/$1/sg;
$line
=~ s/,(\s*,)+/,/sg;
$line
=~ s/,[ \t]*$//;
$line
=~ s/[ \t]*$//;
if
(
$line
ne
''
) {
output(
$join
,
$line
,
"\n"
);
$join
= (
$line
=~ /;$/ ?
"\n"
:
",\n"
);
}
next
;
}
else
{
}
}
if
(
$within
) {
print
STDERR
"$filename:$linenum: end of file within \"$within\"\n"
;
exit
1;
}
}
sub
diag {
my
$self
=
shift
;
if
(
eval
{ Test::More->can(
'diag'
) }) {
Test::More::diag (
@_
);
}
else
{
my
$msg
=
join
(
''
,
map
{
defined
(
$_
)?
$_
:
'[undef]'
}
@_
).
"\n"
;
print
STDERR
$msg
;
}
}
sub
gp_quote {
my
(
$str
) =
@_
;
$str
=~ s/\
"/\\"
/g;
return
'"'
.
$str
.
'"'
;
}
output_test(
<<'HERE');
print("Total "check_count" tests, "check_good" good, "check_bad" bad");
if(check_bad,quit(1))
HERE
if
(
$harness
) {
close
GP;
if
(!
$harness
->finish) {
my
$exit
= $?;
if
(POSIX::WIFEXITED(
$exit
)) {
exit
(POSIX::WEXITSTATUS(
$exit
));
}
else
{
die
"Error finishing gp sub-process: $?"
;
}
}
}
exit
0;