From fe8e030cdc361e4e40ce764528e44c6ef991d259 Mon Sep 17 00:00:00 2001 From: Hauke D Date: Mon, 12 Nov 2018 16:45:55 +0100 Subject: [PATCH] Added experimental Perl 6 support --- .gitignore | 4 + experiments/cpanfile | 1 + experiments/p6/6demo.html | 50 +++++++++++++ experiments/p6/6init.pl | 71 ++++++++++++++++++ experiments/p6/test6.html | 72 ++++++++++++++++++ experiments/p6/webperl6.js | 148 +++++++++++++++++++++++++++++++++++++ 6 files changed, 346 insertions(+) create mode 100644 experiments/p6/6demo.html create mode 100755 experiments/p6/6init.pl create mode 100644 experiments/p6/test6.html create mode 100644 experiments/p6/webperl6.js diff --git a/.gitignore b/.gitignore index 46c06f9..32c8378 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ /web/_cache/ /pages/ /wiki/ +# For experimental P6 support: +/web/perl6.js +/web/6demo.html +/web/test6.html diff --git a/experiments/cpanfile b/experiments/cpanfile index 73ec0c2..5e499eb 100644 --- a/experiments/cpanfile +++ b/experiments/cpanfile @@ -5,3 +5,4 @@ requires 'Data::Dump'; requires 'Graph'; requires 'MetaCPAN::Client'; +requires 'Path::Class'; diff --git a/experiments/p6/6demo.html b/experiments/p6/6demo.html new file mode 100644 index 0000000..1561f82 --- /dev/null +++ b/experiments/p6/6demo.html @@ -0,0 +1,50 @@ + + + + +WebPerl Perl 6 Demos (Experimental) + + + + + + + + + + + + + + + + + +

This is a demo of the +experimental +Perl 6 support in +WebPerl!

+ +

Currently only works in Chrome (needs BigInt support) and +may take a few seconds to load.

+ +
+
+ +
+ + + diff --git a/experiments/p6/6init.pl b/experiments/p6/6init.pl new file mode 100755 index 0000000..8e19bb0 --- /dev/null +++ b/experiments/p6/6init.pl @@ -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"; + } +} diff --git a/experiments/p6/test6.html b/experiments/p6/test6.html new file mode 100644 index 0000000..279175d --- /dev/null +++ b/experiments/p6/test6.html @@ -0,0 +1,72 @@ + + + + +WebPerl Perl 6 Experiments + + + + + + + + + + + + + + +

See the JS console! Don't click the buttons until both languages are ready.

+ +
+ + +
+ + + diff --git a/experiments/p6/webperl6.js b/experiments/p6/webperl6.js new file mode 100644 index 0000000..139fb2a --- /dev/null +++ b/experiments/p6/webperl6.js @@ -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-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 */