#!/usr/local/bin/perl -T package SystemIDemo; $false = 0; $true = 1; #use warnings; #use strict; use Sys::Hostname; use POSIX ":signal_h"; use CGI qw(:standard); $CGI::POST_MAX=32768; # max 32K posts $query = new CGI; $| = 1; $valid_rank = $true; $valid_term = $true; $valid_impl = $true; $valid_epath = $true; ############################################################################## $error_report_address = "compositional-web-bugs\@types.bu.edu"; # Web page style our $background_color = "#fffff9"; our $figure_color = "#eeeeee"; our $figure2_color = "#dddddd"; our $header_color = "#cccccc"; $done = "(Done)"; $processing = ""; $error = "(Error)"; $javadir = "church/java"; $lambda2xml = "church/src/lambda2xml-haskell.old-but-still-used/lambda2xml"; $java_inference="systemi.DriverXML"; $haskell_inference="church/src/Carlier-implementation-I/infer"; $sml_inference="church/src/Kfoury-Wells-implementation/bin/infer"; $lambda_schema = "church/compositional-analysis/lambda-xml/lambda.xsd"; $systemi_schema = "church/compositional-analysis/system-i/system-i.xsd"; $style_dir = "church/compositional-analysis/system-i"; $xml_stylesheet = $style_dir."/system-i.xml.xsl"; $postscript_stylesheet = $style_dir."/system-i.latex.xsl"; $text_stylesheet = $style_dir."/system-i.txt.xsl"; $xhtml_stylesheet = $style_dir."/system-i.xhtml.xsl"; if (hostname eq "buddha") { $ENV{PATH}="/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin"; $sml = "/usr/bin/sml"; # 110.0.7 $gzip = "/bin/gzip"; $ps2pdf = "/u1/pg/sebc/opt/i686-pc-linux-gnu/ghostscript-7.05/bin/ps2pdf"; $java = "/usr/bin/java"; # 1.4.0 $saxon = "com.icl.saxon.StyleSheet"; $msv = "com.sun.msv.driver.textui.Driver"; $dvips = "/usr/bin/dvips -z -Ppdf -G0 -D600"; $latex = "/usr/bin/latex"; $ENV{CLASSPATH}="./:/usr/java/j2sdk1.4.0/jre/lib/rt.jar"; } else { $ENV{PATH}="/usr/local/bin:/bin:/usr/bin:/usr/ucb:/usr/bin/X11"; $ENV{LD_LIBRARY_PATH}="/usr/local/lib"; $sml = "/usr/local/bin/sml"; $gzip = "/usr/local/bin/gzip"; $ps2pdf = "ps2pdf14"; $java = "/bin/java"; $saxon = "com.icl.saxon.StyleSheet"; $msv = "com.sun.msv.driver.textui.Driver"; $dvips = "/usr/local/bin/dvips -z -Ppdf -G0 -D600"; $latex = "/usr/local/bin/latex"; $ENV{CLASSPATH}="./:/usr/java/jre/lib/rt.jar"; } $ENV{CLASSPATH}=$ENV{CLASSPATH}.":$javadir/saxon/saxon-fop.jar:$javadir/saxon/saxon-jdom.jar:$javadir/saxon/saxon.jar:$javadir/jaxp-1.1/crimson.jar:$javadir/jaxp-1.1/jaxp.jar:$javadir/jaxp-1.1/xalan.jar:$javadir/msv-20010910/isorelax.jar:$javadir/msv-20010910/relaxngdatatype.jar:$javadir/msv-20010910/xsdlib.jar:$javadir/msv-20010910/msv.jar:./church/src/Ori-Implementation/systemi.jar:$javadir"; $convert_message = "Parsing and converting your term into XML."; # Status messages $inference_message = "Performing System I principal typing inference on your term."; $validate1_message = "Validating XML output from parsing against the Lambda schema."; $validate2_message = "Validating XML output from typing inference against the System I schema."; $style_message = "Applying the selected XML Stylesheet on the output from inference."; $max_rank = 8; # Assign a session code $session = unpack("H*", pack("Nn", time, $$)); $general_style_params = ['Initial Typing Judgement', 'Initial Skeleton', 'Unification Information', 'Final Typing Judgement', 'Final Skeleton or Derivation']; $standard_style_params = ['Initial Generated Constraint Set', 'Constraint Set at Failure', 'Final Substitution']; $tracing_style_params = ['Constraint Sets', 'Selected Substitutions', 'Substitutions', 'Incremental Skeletons']; $xml_tracing_style_params = ['Selected Substitutions', 'Incremental Skeletons']; ############################################################################## if($query->param("Action") eq "Generate") { $new_url = $query->self_url(); $new_url =~ s/Action=Generate\;//; print $query->redirect($new_url); } elsif(!$query->param("Action")) { display_form($valid_rank, $valid_term, $valid_impl, $valid_epath); } else { ############################################################################## ############################################################################## # The code that performs the inference and creates the status/progress page ############################################################################## # Code to make sure the inputs we were given are sane $upload_file = $query->param('Upload'); if(!($query->param("Rank") =~ /\d/) || ($query->param("Rank") =~ /\D/) || $query->param("Rank") > $max_rank) { $valid_rank = $false; } if(($query->param("Term") =~ /^\s*$/) && ($query->param("Examples") =~ /^\s*$/) && !$upload_file) { $valid_term = $false; } if(!($query->param("Examples") =~ /^\s*$/) && (!$upload_file) && ($query->param("Term") =~ /^\s*$/) && !($query->param("TermLanguage") eq "SML")) { $valid_impl = $false; } if(($query->param("Implementation") eq "Java") && ($query->param("EPathEnvironment") eq "on")) { $valid_epath = $false; } # If we got bad inputs notify the user by redisplaying the original form if(!$valid_rank || !$valid_term || !$valid_impl || !$valid_epath) { display_form($valid_rank, $valid_term, $valid_impl, $valid_epath); exit } ############################################################################## # Initially the status is empty @status = (); ############################################################################## # Write out our first progress message push @status, "$convert_message $processing"; write_status_page(-status=>[@status]); # Fork a child to handle the remainder of the session after redirecting $childpid = fork; if($childpid != 0) { $new_url = $query->self_url(); $new_url =~ s/^(.*)\/(.*)$/$1\//; print $query->redirect($new_url."$session.html"); #waitpid($childpid, 0); exit; } open STDIN, "/dev/null"; # Figure out where we are getting our term from. if($upload_file) { @text = <$upload_file>; $term = "@text"; } elsif (!($query->param("Term") =~ /^\s*$/)) { $term = $query->param("Term"); } else { $term = $query->param("Examples"); } if($query->param("TermLanguage") eq "SML") { $syntax = "s"; } elsif($query->param("TermLanguage") eq "Haskell") { $syntax = "c"; } elsif($query->param("TermLanguage") eq "Scheme") { $syntax = "l"; } else { pop @status; push @status, "$convert_message $error"; write_report_page(-status => [@status], -reportsub => sub { my $FILE = shift(@_); print $FILE "You somehow managed to send us an invalid syntax selection, perhaps even intentionally. Naughty Naughty. Try again.", br;}); } # Parse the term, converting to XML $errors = parse_term(-term=>$term, -language=>$syntax, -output=>"/tmp/input-xml.$$"); # If there were errors, report them to the user if($errors) { pop @status; push @status, "$convert_message $error"; write_report_page(-status => [@status], -reportsub => sub { my $FILE = shift(@_); print $FILE "Unable to parse your term:", br, "
\n", $errors, "", br, "The maintainers have been notified."; }); delete_files("/tmp/input-xml.$$"); exit; } pop @status; push @status, "$validate1_message $done"; ############################################################################## push @status, "$inference_message $processing"; write_status_page(-status=>[@status]); if($query->param("Rank") =~ /\d/) { $untainted_rank = $&; } else { pop @status; push @status, "$inference_message $error"; write_report_page(-status => [@status], -reportsub => sub { my $FILE = shift(@_); print $FILE "You somehow managed to send us an invalid rank, perhaps even intentionally. Naughty Naughty. Try again.", br;}); # Do something better here } # Peform the actual typing inference $errors = infer_typing(-input=>"/tmp/input-xml.$$", -output=>"/tmp/output-xml.$$", -rank=>$untainted_rank, -implementation=>$query->param("Implementation")); # Two possible types of errors: inference failed or inference timed out. # If the inference engine chokes for other reasons # we have no way of knowing about it at present pop @status; if($errors == 1) { $inference_result = "(Done - inference failed)"; } elsif($errors == 2) { push @status, "$inference_message $error"; write_report_page(-status=>[@status], -reportsub => sub { my $FILE = shift(@_); print $FILE br, "", "Type inference timed out. This may mean that the term you requested requires more time to process than we allow.", ""; }); delete_files("/tmp/input-xml.$$"); exit; } else { $inference_result = "(Done - inference succeed)"; } push @status, "$inference_message $inference_result"; delete_files("/tmp/input-xml.$$"); ############################################################################## push @status, "$validate2_message $processing"; write_status_page(-status=>[@status]); # Validate the XML output from typing inference as a sanity check $errors = validate_xml(-input=>"/tmp/output-xml.$$", -schema=>$systemi_schema); # If there were errors, tell the user and maintainers if($errors) { pop @status; push @status, "$validate2_message $error"; send_error_report($errors); write_report_page(-status=>[@status], -reportsub => sub { my $FILE = shift(@_); print $FILE "Internal Consistency Error:", br, "
\n", $errors, "", br, "The maintainers have been notified."; }); delete_files("/tmp/output-xml.$$"); exit; } pop @status; push @status, "$validate2_message $done"; ############################################################################## push @status, "$style_message $processing"; write_status_page(-status=>[@status]); # Figure out what options apply if($query->param("UnifyOptions") eq "Tracing") { $options = [$query->param("GeneralStyleOptions"), $query->param("TracingStyleOptions")]; } else { $options = [$query->param("GeneralStyleOptions"), $query->param("StandardStyleOptions")]; } if($query->param("EPathEnvironment") eq "on") { $options = [@{$options}, 'E-path Environment']; } if($query->param("IncludeLegend") eq "on") { $options = [@{$options}, 'Legend']; } # Apply a stylesheet to the output from typing inference %output = style_xml(-input=>"/tmp/output-xml.$$", -output_prefix=>$session, -style=>$query->param("OutputStyle"), -options=>$options); delete_files("/tmp/output-xml.$$"); if($output{'errors'}) { pop @status; push @status, "$style_message $error"; send_error_report($output{'errors'}); write_report_page(-status=>[@status], -reportsub => sub { my $FILE = shift(@_); print $FILE "Internal Consistency Error:", br, "
\n", $output{'errors'}, "", br, "The maintainers have been notified."; }); delete_files($output{'file'}); exit; } pop @status; push @status, "$style_message $done"; ############################################################################## # Done, redirect the user to the output file write_report_page(-status=>[@status], -refresh=>$output{'file'}, -reportsub=> sub { my $FILE = shift(@_); print $FILE br, "
";
print "System I Experimentation Tool"; print "Welcome user@".$query->remote_host()."! "; print <Unfortunately, this tool does not presently work with web browsers, such as , which do not support the use of <meta http-equiv="refresh">. Direct bug reports and questions to: (fn [user, host] => user ^ "@" ^ host) ["compositional-web-bugs", "types.bu.edu"]; |
|
END
$body = $body.$query->textarea(-name=>'Term',
-rows=>4,
-cols=>50);
$body = $body.< |
END
$body = $body."File: ".$query->filefield(-name=>'Upload',-size=>40,-maxlength=>32768);
$body = $body.< |
In some examples the types may become very large making the skeletons
and derivation difficult to read. One may opt to only apply expansion
variable substitutions to the skeletons and derivations
displayed in the output, which may make those examples easier to read.
END
$body = $body.$query->checkbox(-name=>'ExpandOnly',
-checked=>'on',
-label=>'Apply Expansions Only');
$body = $body.<
The Alan-Washburn implementation computes composed substitutions using safe composition,
while the Yates-Schwartz implementation computes chains of small substitutions.
The Carlier implementation works with chains internally, but has an
option to compose them (using an algorithm different from safe composition).
END
$body = $body.$query->checkbox(-name=>'ComposeSubstitutions',
-checked=>'on',
-label=>'Compose Substitutions');
$body = $body.<
In the Alan-Washburn implementation, E-path Environments are generated and may optionally be included in the output.
END
$body = $body.$query->checkbox(-name=>'EPathEnvironment',
-value=>'on',
-label=>'Include E-path Environment');
if(!$valid_epath) {
$body = $body." (cannot include E-Path Environment when using the Java implementation)";
}
$body = $body.<
The output from our inference engines can be rendered using
into several different file formats, which would you like?
For these formats, you can choose among the following
items to be included in your output:
END
$body = $body.$query->checkbox_group(-name=>"GeneralStyleOptions",
-values=>$general_style_params,
-defaults=>$general_style_params,
-rows=>2);
$body = $body."
Additional options relevant for standard unification output:
END
$body = $body.$query->checkbox_group(-name=>"StandardStyleOptions",
-values=>$standard_style_params,
-defaults=>$standard_style_params,
-rows=>2);
$body = $body.<
Additional options relevant for tracing unification output:
END
$body = $body.$query->checkbox_group(-name=>"TracingStyleOptions",
-values=>$tracing_style_params,
-defaults=>$tracing_style_params,
-rows=>2);
$body = $body."
For XML output, the following options are relevant for
tracing unification output:
END
$body = $body.$query->checkbox_group(-name=>"XMLTracingStyleOptions",
-values=>$xml_tracing_style_params,
-defaults=>$xml_tracing_style_params,
-rows=>1);
$body = $body."
END
@radio = $query->radio_group(
-name=>'OutputStyle',
-values=>['Raw XML', 'PDF', 'Gzipped PostScript', 'PostScript','XHTML', 'ASCII Text'],
-default=>'PDF');
$xml_radio = shift @radio;
$body = $body."";
$body = $body."
";
print gen_box("Output Format", $body), br;
$bookmark_url = $query->self_url();
$body = <System I Experimentation Tool
";
print INFO gen_altfigure(@status);
print INFO $query->end_html;
close(INFO);
}
##############################################################################
sub write_report_page {
my %params = @_;
my @status = @{$params{-status}};
my $reportsub = $params{-reportsub};
my $refresh = $params{-refresh} ||= "" ;
open(INFO, ">$session.html");
if($refresh) {
print INFO $query->start_html(-title=>"System I Experimentation Tool",
-BGCOLOR=>$background_color,
-head=>[refresh_to_file(-file=>$refresh)]);
} else {
print INFO $query->start_html(-title=>"System I Web Experimentation Tool",
-BGCOLOR=>$background_color);
}
print INFO "System I Experimentation Tool
";
print INFO gen_altfigure(@status), br;
&{$reportsub}(INFO);
print INFO $query->end_html;
close(INFO);
}
##############################################################################
sub refresh_to_file {
my %params = @_;
my $file = $params{-file};
return "";
}
##############################################################################
# A function to delete a list of files. Mainly to abstract away some, rather
# than calling system everywhere, and it proves a central location to turn
# of file deletion for debugging purposes
sub delete_files {
system("rm @_");
}
##############################################################################
sub create_param_string {
my @args = @_;
$params = "";
for(@$general_style_params,@$standard_style_params,@$tracing_style_params, ('Legend')) {
$option = $_;
$option =~ tr/[A-Z\ ]/[a-z_]/;
$opt = $_;
$flag = 0;
for(@args) {
if($_ eq $opt) {
$params = $params." ".$option."=1";
$flag = 1;
break;
}
}
if($flag == 0) {
$params = $params." ".$option."=0";
}
}
return $params;
}
##############################################################################
# Code to take a title and content and generated HTML for a titled box
sub gen_box {
my $title = shift;
my $content = shift;
my $box_html = <
END
return $box_html;
}
##############################################################################
# Code to take a list of elements and generate a figure with alternating
# colors
sub gen_altfigure {
my $box_html = <$title $content
END
return $box_html;
}
##############################################################################
# Code to take content and produce a figure box
sub gen_figure {
my $figure_html = <
END
my $index = 0;
for(@_) {
my $color = undef;
if(($index % 2) == 0) {
$color = $figure_color;
} else {
$color = $figure2_color;
}
$box_html = $box_html.<
END
$index++;
}
$box_html = $box_html.<$_
END
return $figure_html;
}
##############################################################################
sub parse_term {
my %params = @_;
my $term = $params{-term};
my $language = $params{-language};
my $output = $params{-output};
my $errors = "/tmp/errors.$$";
$language =~ tr/[A-Z]/[a-z]/;
open(PARSER, "| $lambda2xml -$language > $output 2> $errors");
print PARSER $term;
close(PARSER);
open(ERRORS, $errors);
@output = @_