Added experimental Perl 6 support
parent
3e8acce5f3
commit
fe8e030cdc
@ -0,0 +1,50 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en-us">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<title>WebPerl Perl 6 Demos (Experimental)</title>
|
||||||
|
|
||||||
|
<script src="webperl.js"></script>
|
||||||
|
|
||||||
|
<!-- Please see the documentation at http://webperl.zero-g.net/perl6.html -->
|
||||||
|
|
||||||
|
<!-- Example 1: A really basic script -->
|
||||||
|
<script type="text/perl6">
|
||||||
|
print "Hello, Perl 6 World!\n";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Example 2: Accessing JavaScript -->
|
||||||
|
<script type="text/perl6">
|
||||||
|
my $document = EVAL(:lang<JavaScript>, 'return document');
|
||||||
|
$document.getElementById('my_button')
|
||||||
|
.addEventListener("click", -> $event {
|
||||||
|
print "You clicked 'Testing!'\n";
|
||||||
|
} );
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Optional STDOUT/STDERR text area (if you don't use this, output goes to Javascript console) -->
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
document.getElementById('output')
|
||||||
|
.appendChild( Raku.makeOutputTextarea() );
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<p>This is a demo of the
|
||||||
|
<a href="http://webperl.zero-g.net/perl6.html" target="_blank">experimental
|
||||||
|
Perl 6 support</a> in
|
||||||
|
<a href="http://webperl.zero-g.net" target="_blank">WebPerl</a>!</p>
|
||||||
|
|
||||||
|
<p><em>Currently only works in Chrome (needs BigInt support) and
|
||||||
|
may take a few seconds to load.</em></p>
|
||||||
|
|
||||||
|
<div id="output"></div>
|
||||||
|
<div id="buttons">
|
||||||
|
<button id="my_button">Testing!</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
use FindBin;
|
||||||
|
use Path::Class qw/dir/;
|
||||||
|
use HTTP::Tiny;
|
||||||
|
use File::Copy qw/copy/;
|
||||||
|
$|++;
|
||||||
|
|
||||||
|
# Quick & dirty script to patch P6 into the "web" dir
|
||||||
|
|
||||||
|
# Note: To restore webperl.js to the original version:
|
||||||
|
# $ git checkout web/webperl.js
|
||||||
|
|
||||||
|
my $p6url = 'https://perl6.github.io/6pad/gen/eval_code.js';
|
||||||
|
|
||||||
|
my $mydir = dir($FindBin::Bin);
|
||||||
|
my $webdir = $mydir->parent->parent->subdir('web');
|
||||||
|
|
||||||
|
print "Patching experimental Perl 6 support into ",$webdir->relative,"...\n";
|
||||||
|
|
||||||
|
my $wpfile = $webdir->file('webperl.js');
|
||||||
|
die "File structure not as I expected" unless -e $wpfile;
|
||||||
|
|
||||||
|
my $http = HTTP::Tiny->new();
|
||||||
|
my $jsfile = $webdir->file('perl6.js');
|
||||||
|
print "$p6url: ";
|
||||||
|
my $resp = $http->mirror($p6url, "$jsfile");
|
||||||
|
print "$resp->{status} $resp->{reason}\n";
|
||||||
|
die unless $resp->{success};
|
||||||
|
print "-> mirrored to ",$jsfile->relative,"\n";
|
||||||
|
|
||||||
|
my $wp = $wpfile->slurp(iomode=>'<:raw:encoding(UTF-8)');
|
||||||
|
$wp =~ s{
|
||||||
|
^ \N* \bbegin_webperl6_patch\b \N* $
|
||||||
|
.*
|
||||||
|
^ \N* \bend_webperl6_patch\b \N* $
|
||||||
|
}{}msxi;
|
||||||
|
die "I thought I clobbered the webperl6.js patch, why is there still a reference to Raku?"
|
||||||
|
if $wp=~/\bRaku\./;
|
||||||
|
my $wp6file = $mydir->file('webperl6.js');
|
||||||
|
my $wp6 = $wp6file->slurp(iomode=>'<:raw:encoding(UTF-8)');
|
||||||
|
1 while chomp($wp6);
|
||||||
|
$wpfile->spew(iomode=>'>:raw:encoding(UTF-8)', $wp.$wp6);
|
||||||
|
print "Patched ",$wp6file->relative," into ",$wpfile->relative,"\n";
|
||||||
|
|
||||||
|
for my $f ($mydir->children) {
|
||||||
|
next unless $f->basename=~/(?:html?|css)\z/i;
|
||||||
|
link_or_copy($f, $webdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub link_or_copy {
|
||||||
|
my ($src,$dest) = @_;
|
||||||
|
die "Not a dir: $dest" unless -d $dest;
|
||||||
|
$dest = $dest->file( $src->basename );
|
||||||
|
if ( eval { symlink("",""); 1 } ) { # we have symlink support
|
||||||
|
if (!-l $dest) {
|
||||||
|
$dest->remove or die "$dest: $!" if -e $dest;
|
||||||
|
my $targ = $src->relative( $dest->dir );
|
||||||
|
symlink($targ,$dest) or die "symlink: $!";
|
||||||
|
print "Linked ",$dest->relative," to $targ\n";
|
||||||
|
}
|
||||||
|
else { print "Link ",$dest->relative," exists\n"; }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$dest->remove or die "$dest: $!" if -e $dest;
|
||||||
|
copy($src,$dest) or die "copy: $!";
|
||||||
|
print "Copied ",$src->relative," to ",$dest->relative,"\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en-us">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<title>WebPerl Perl 6 Experiments</title>
|
||||||
|
|
||||||
|
<script src="webperl.js"></script>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
The following is a demo of Perl 5 and Perl 6 calling each other via JavaScript.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.Foo = {
|
||||||
|
set: function (x,y) { window.Foo[x]=y }, // workaround, see P6 below
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/perl">
|
||||||
|
use warnings;
|
||||||
|
use 5.028;
|
||||||
|
|
||||||
|
sub hello {
|
||||||
|
my $x = shift;
|
||||||
|
say "Hello from Perl 5! You said '$x'";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $Foo = js('window.Foo');
|
||||||
|
$Foo->{p5} = \&hello;
|
||||||
|
|
||||||
|
js('document')->getElementById('btn_p5')
|
||||||
|
->addEventListener("click", sub {
|
||||||
|
say "This is Perl 5, attempting to call Perl 6...";
|
||||||
|
$Foo->p6("I am Perl 5!");
|
||||||
|
} );
|
||||||
|
|
||||||
|
say "Perl 5 is ready.";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/raku">
|
||||||
|
|
||||||
|
sub hello ($x) {
|
||||||
|
say "Hello from Perl 6! You said '$x'"
|
||||||
|
}
|
||||||
|
|
||||||
|
my $Foo = EVAL(:lang<JavaScript>, 'return window.Foo');
|
||||||
|
# I'm not yet sure why the following doesn't work, Foo.set is a workaround
|
||||||
|
#$Foo<p6> = &hello;
|
||||||
|
$Foo.set("p6", &hello);
|
||||||
|
|
||||||
|
my $document = EVAL(:lang<JavaScript>, 'return document');
|
||||||
|
$document.getElementById('btn_p6')
|
||||||
|
.addEventListener("click", -> $event {
|
||||||
|
say "This is Perl 6, attempting to call Perl 5...";
|
||||||
|
$Foo.p5("I am Perl 6!");
|
||||||
|
} );
|
||||||
|
|
||||||
|
say "Perl 6 is ready.";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<p>See the JS console! Don't click the buttons until both languages are ready.</p>
|
||||||
|
|
||||||
|
<div id="buttons">
|
||||||
|
<button id="btn_p5">Perl 5</button>
|
||||||
|
<button id="btn_p6">Perl 6</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -0,0 +1,148 @@
|
|||||||
|
"use strict"; /* DO NOT EDIT THIS LINE! begin_webperl6_patch */
|
||||||
|
|
||||||
|
/***** NOTICE: This is part of the experimental WebPerl Perl 6 support.
|
||||||
|
* This file (webperl6.js) is currently patched into webperl.js by 6init.pl.
|
||||||
|
* There is currently a fair amount of duplication between the following code
|
||||||
|
* and webperl.js that should probably be reduced.
|
||||||
|
* This file should eventually be merged permanently into webperl.js.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** ***** WebPerl - http://webperl.zero-g.net *****
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Hauke Daempfling (haukex@zero-g.net)
|
||||||
|
* at the Leibniz Institute of Freshwater Ecology and Inland Fisheries (IGB),
|
||||||
|
* Berlin, Germany, http://www.igb-berlin.de
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the same terms as Perl 5 itself: either the GNU General Public
|
||||||
|
* License as published by the Free Software Foundation (either version 1,
|
||||||
|
* or, at your option, any later version), or the "Artistic License" which
|
||||||
|
* comes with Perl 5.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the licenses for details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the licenses along with this program.
|
||||||
|
* If not, see http://perldoc.perl.org/index-licence.html
|
||||||
|
**/
|
||||||
|
|
||||||
|
// I'm using "Raku" because the Hamming distance from Perl <-> Perl6 is too small for me,
|
||||||
|
// it's too much of a risk for typos since webperl.js also provides the "Perl" object.
|
||||||
|
// But the following functions are currently available on both the Raku.* and Perl6.* objects:
|
||||||
|
// .init(), .eval(), .addStateChangeListener(), .makeOutputTextarea()
|
||||||
|
// but everything else, such as Raku.state or Raku.output, needs to go via the Raku object.
|
||||||
|
var Raku = {
|
||||||
|
state: "Uninitialized", // user may read (only!) this
|
||||||
|
// internal variables:
|
||||||
|
stdout_buf: "", stderr_buf: "", // for our default Raku.output implementation
|
||||||
|
};
|
||||||
|
var Perl6 = {};
|
||||||
|
|
||||||
|
Raku.changeState = function (newState) {
|
||||||
|
if (Raku.state==newState) return;
|
||||||
|
var oldState = Raku.state;
|
||||||
|
Raku.state = newState;
|
||||||
|
for( var i=0 ; i<Raku.stateChangeListeners.length ; i++ )
|
||||||
|
Raku.stateChangeListeners[i](oldState,newState);
|
||||||
|
};
|
||||||
|
Raku.stateChangeListeners = [ function (from,to) {
|
||||||
|
console.debug("Raku: state changed from "+from+" to "+to);
|
||||||
|
} ];
|
||||||
|
Raku.addStateChangeListener = Perl6.addStateChangeListener = function (handler) {
|
||||||
|
Raku.stateChangeListeners.push(handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
// chan: 1=STDOUT, 2=STDERR
|
||||||
|
// implementations are free to ignore the "chan" argument if they want to merge the two streams
|
||||||
|
Raku.output = function (str,chan) { // can be overridden by the user
|
||||||
|
var buf = chan==2 ? 'stderr_buf' : 'stdout_buf';
|
||||||
|
Raku[buf] += str;
|
||||||
|
var pos = Raku[buf].indexOf("\n");
|
||||||
|
while (pos>-1) {
|
||||||
|
console.log( chan==2?"STDERR":"STDOUT", Raku[buf].slice(0,pos) );
|
||||||
|
Raku[buf] = Raku[buf].slice(pos+1);
|
||||||
|
pos = Raku[buf].indexOf("\n");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Raku.makeOutputTextarea = Perl6.makeOutputTextarea = function (id) {
|
||||||
|
var ta = document.createElement('textarea');
|
||||||
|
if (id) ta.id = id;
|
||||||
|
ta.rows = 24; ta.cols = 80;
|
||||||
|
ta.setAttribute("readonly",true);
|
||||||
|
Raku.output = function (str) {
|
||||||
|
ta.value = ta.value + str;
|
||||||
|
ta.scrollTop = ta.scrollHeight;
|
||||||
|
};
|
||||||
|
return ta;
|
||||||
|
};
|
||||||
|
|
||||||
|
Raku.init = Perl6.init = function (readyCallback) {
|
||||||
|
if (Raku.state != "Uninitialized")
|
||||||
|
throw "Raku: can't call init in state "+Raku.state;
|
||||||
|
Raku.changeState("Initializing");
|
||||||
|
var baseurl = Perl.Util.baseurl(getScriptURL()); // from webperl.js
|
||||||
|
|
||||||
|
// NOTE that NQP_STDOUT currently gets handed HTML,
|
||||||
|
// so we jump through some hoops to decode it here:
|
||||||
|
var decode_div = document.createElement('div');
|
||||||
|
window.NQP_STDOUT = function (str) {
|
||||||
|
str = str.replace(/[\<\>]/g,''); // declaw unexpected tags
|
||||||
|
decode_div.innerHTML = str;
|
||||||
|
str = decode_div.textContent;
|
||||||
|
decode_div.textContent = '';
|
||||||
|
Raku.output(str,1);
|
||||||
|
};
|
||||||
|
|
||||||
|
console.debug("Raku: Fetching Perl6...");
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.async = true; script.defer = true;
|
||||||
|
// Order is important here: 1. Add to DOM, 2. set onload, 3. set src
|
||||||
|
document.getElementsByTagName('head')[0].appendChild(script);
|
||||||
|
script.onload = function () {
|
||||||
|
Raku.eval = Perl6.eval = window.evalP6;
|
||||||
|
Raku.changeState("Ready");
|
||||||
|
if (readyCallback) readyCallback();
|
||||||
|
};
|
||||||
|
script.src = baseurl+"/perl6.js";
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var scripts = [];
|
||||||
|
var script_src;
|
||||||
|
document.querySelectorAll("script[type='text/perl6'],script[type='text/raku']")
|
||||||
|
.forEach(function (el) {
|
||||||
|
if (el.src) {
|
||||||
|
if (script_src || scripts.length)
|
||||||
|
console.error('Only a single Perl6 script may be loaded via "script src=", ignoring others');
|
||||||
|
else
|
||||||
|
script_src = el.src;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (script_src)
|
||||||
|
console.error('Only a single Perl6 script may be loaded via "script src=", ignoring others');
|
||||||
|
else
|
||||||
|
scripts.push(el.innerHTML);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (script_src) {
|
||||||
|
console.debug("Raku: Found a script with src, fetching and running...", script_src);
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.addEventListener("load", function () {
|
||||||
|
var code = this.responseText;
|
||||||
|
Raku.init(function () { Raku.eval(code); });
|
||||||
|
});
|
||||||
|
xhr.open("GET", script_src);
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
else if (scripts.length) {
|
||||||
|
console.debug("Raku: Found",scripts.length,"embedded script(s), autorunning...");
|
||||||
|
var code = scripts.join(";\n");
|
||||||
|
Raku.init(function () { Raku.eval(code); });
|
||||||
|
}
|
||||||
|
else console.debug("Raku: No embedded scripts");
|
||||||
|
});
|
||||||
|
|
||||||
|
/* DO NOT EDIT THIS LINE! end_webperl6_patch */
|
||||||
Loading…
Reference in New Issue