简体   繁体   中英

How to call Perl 6 from Java?

Perl 6 regexes/grammars are much better structured, more powerful and readable than Perl 5 or related Perl compatible regexes everywhere, including regexes in Java. I am looking for a way to execute Perl 6 code with that regex/grammar code from Java.

Here is a common example similar I want to do:

grammar Calculator {
    token TOP { [ <add> | <sub> ] }
    rule  add { <num> '+' <num> }
    rule  sub { <num> '-' <num> }
    token num { \d+ }
}

class Calculations {
    method TOP ($/) { make $<add> ?? $<add>.made !! $<sub>.made; }
    method add ($/) { make [+] $<num>; }
    method sub ($/) { make [-] $<num>; }
}

say Calculator.parse('2 + 3', actions => Calculations).made;

# OUTPUT: «5␤» 

Maybe I have to write a Class in Perl 6 and have to compile this for JVM Bytecode and then I can call this. Is that a solution or not? Or is that not possible?

Maybe it is too hard to call Perl 6 from Java. There is also another direction. In Perl 6 are lots of Inline modules like Inline::Python, Inline::Perl5 and so on. There is also a way to run java code in Perl 6. Here is an example I found:

use java::util::zip::CRC32:from<java>;

my $crc = CRC32.new();
for 'Hello, Java'.encode('utf-8') {
    $crc.'method/update/(B)V'($_);
}
say $crc.getValue();

Is this a possible way to start with Perl 6 and bind the mass of Java code then to one project? But how to go back from Java to my Perl 6 code? For Perl 5 I can find the module Inline::Java::Callback but not for Perl 6.

How should I do this in a professional way?

Compiling perl6 code to JVM bytecode won't immediately help you, I don't think, but there's an "Eval Server" that the test suite uses so that it doesn't have to start a JVM from scratch for each of the many test files in the spec test suite.

You can find the source code to the eval server here, and probably steal a few things from it: https://github.com/perl6/nqp/blob/master/src/vm/jvm/runtime/org/perl6/nqp/tools/EvalServer.java

I share the results of my own experimentations and observations, in the hope it will be useful, even if my conclusion is not very positive at the moment. My short answer to the OP's question is: as of may 2019, it is not yet possible.

Now the long answer: the JVM backend support of Perl6 is not yet in a stable, ready-to-use state in latest releases of Rakudo Star: https://rakudo.org/post/announce-rakudo-star-release-2019-03

Anyway, if you want to try your luck, here is an example derived from rakudo-star/nqp/examples (with a small patch, for the original code from rakudo-star-2019.03 won't compile out of the box). Improvements to the original example also include the documentation and basic control of the command line arguments:

package examples;
import org.perl6.nqp.runtime.*;
import static org.perl6.nqp.runtime.CallSiteDescriptor.*;
import org.perl6.nqp.sixmodel.*;

public class CallFromJava {
    private GlobalContext g;
    private ThreadContext t;
    private SixModelObject nqpComp;

    private CallFromJava(String bytecode, String hll) {
        g = new GlobalContext();
        t = g.getCurrentThreadContext();

        Ops.loadbytecode(bytecode, t);
        nqpComp = Ops.getcomp(hll, t);
    }

    private SixModelObject eval(String nqp) {
        Ops.invokeDirect(t, Ops.findmethod(nqpComp, "compile", t),
                new CallSiteDescriptor(new byte[] { ARG_OBJ, ARG_STR }, null),
                new Object[] { nqpComp, nqp });

        Ops.invokeDirect(t, Ops.result_o(t.resultFrame()), Ops.emptyCallSite, Ops.emptyArgList);
        return Ops.result_o(t.resultFrame());
    }

    public static void main(String[] args) {
        if (args.length != 3) {
            System.err.printf("usage: java CallFromJava <jarfile> <dialect> <expression>\n");
            System.err.println("<jarfile>: path to nqp.jar or perl6.jar");
            System.err.println("<dialect>: nqp or perl6");
            System.err.println("<expression>: a nqp or perl6 expression");
            System.exit(1);
        }

        String jarFile = args[0];
        String dialect = args[1];
        String expression = args[2];
        CallFromJava nqp = new CallFromJava(jarFile, dialect);

        nqp.eval(expression);
    }
}

If you take the original code from the Rakudo Star package (version 2019-03 at the time of writing), make sure to apply the following correction (already fixed in the above example):

<         Ops.invokeDirect(t, Ops.findmethod(t, nqpComp, "compile"),
---
>         Ops.invokeDirect(t, Ops.findmethod(nqpComp, "compile", t),

To build and test the example:

With NQP (Not Quite Perl):

cd rakudo-star-yyyy-mm/nqp
javac -cp bin/ examples/CallFromJava.java
java -cp nqp-runtime.jar:3rdparty/asm/asm-4.1.jar:3rdparty/asm/asm-tree-4.1.jar:. examples.CallFromJava nqp.jar nqp 'say(2+2)'
4

The problem is that NQP is only a subset of Perl6, not intended for direct use by the Perl6 developer. With complete Perl6, presumably, one would do something like:

export PERL6_PREFIX=/usr/local/perl6 # or whatever your perl6 installation prefix is
cd rakudo-star-yyyy-mm/nqp
javac -cp bin/ examples/CallFromJava.java
java -cp $PERL6_PREFIX/share/nqp/runtime/asm-4.1.jar:$PERL6_PREFIX/share/nqp/runtime/asm-tree-4.1.jar:$PERL6_PREFIX/share/nqp/runtime/nqp-runtime.jar:$PERL6_PREFIX/share/perl6/runtime/rakudo-runtime.jar:$PERL6_PREFIX/share/perl6/runtime/perl6.jar:. examples.CallFromJava $PERL6_PREFIX/share/perl6/runtime/perl6.jar perl6 'say 2 + 2'

but I didn't manage to make it work so far

Unhandled exception: java.nio.file.NoSuchFileException: Perl6/Grammar
  in <anon> (src/vm/jvm/ModuleLoader.nqp:76)
  in load_module (src/vm/jvm/ModuleLoader.nqp:58)
  in <anon> (gen/jvm/main.nqp)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM