捕获并执行多行代码并将结果合并到 raku 中

Capture and execute multiline code and incorporate result in raku

这是一个降价文档example.md我有:

## New language

Raku is a new language different from Perl.

## what does it offer
+ Object-oriented programming including generics, roles and multiple dispatch
+ Functional programming primitives, lazy and eager list evaluation, junctions, autothreading and hyperoperators (vector operators)
+ Parallelism, concurrency, and asynchrony including multi-core support
+ Definable grammars for pattern matching and generalized string processing
+ Optional and gradual typing



This code will be evaluated.


```{raku evaluate=TRUE}
4/5
```



Rakudo is a compiler for raku programming language. Install it and you're all set to run raku programs!

This code will be evaluated.

```{raku evaluate=TRUE}
say "this is promising";
say $*CWD;
```



This code will **not** be evaluated.


```{raku evaluate=FALSE}
say "Hello world";
```

我想将其转换为 example.md,如下所示,其中包含代码和输出。

## New language

Raku is a new language different from Perl.

## what does it offer
+ Object-oriented programming including generics, roles and multiple dispatch
+ Functional programming primitives, lazy and eager list evaluation, junctions, autothreading and hyperoperators (vector operators)
+ Parallelism, concurrency, and asynchrony including multi-core support
+ Definable grammars for pattern matching and generalized string processing
+ Optional and gradual typing



This code will be evaluated.

Code:
```{raku evaluate=TRUE}
4/5
```

Output:
```
0.8
```

Rakudo is a compiler for raku programming language. Install it and you're all set to run raku programs!

This code will be evaluated.

Code:
```{raku evaluate=TRUE}
say "this is promising";
say $*CWD;
```

Output:
```
this is promising
"C:\Users\suman".IO
```

This code will **not** be evaluated.

Code:
```{raku evaluate=FALSE}
say "Hello world";
```

我想完成的是:


我尝试做的事情:

  1. 捕获多行代码并计算表达式
my $array= 'example.md'.IO.slurp;

#multiline capture code chunk and evaluate separately
if $array~~/\`\`\`\{raku (.*)\}(.*)\`\`\`/ {
    #the first capture [=12=] will be evaluate
    if [=12=]~~"TRUE"{
        #execute second capture which is code chunk which is captured in 
        }else {
       # don't execute code
        };
};
  1. 创建一个 temp.p6 文件并将上面的代码块 $1 写入其中
my $fh="temp.p6".IO.spurt: ;
  1. 如果 $0 为真则执行块
my $output= q:x/raku temp.p6/ if [=14=]==TRUE
  1. 将所有这些整合到最终 example.md 中,同时我们创建中间 example_new.md
my $fh-out = open "example_new.md", :w; # Create a new file

# Print out next file, line by line
for "$file.tex".IO.lines -> $line {

    # write output of code to example_new.md

}
$fh-out.close;

# copy
my $io = IO::Path.new("example_new.md");
$io.copy("example.md");

# clean up
unlink("example.md");

# move
$io.rename("example.md");

我卡在了第一步。有帮助吗?

您可以试试这个正则表达式:

```{perl6 evaluate=(?<evaluate>[^}]+)}\s+(?<code>[^`]+)

您将从示例文本中获得三个结果,每个结果包含两个命名组,第一个是 evaluate,包含标志,第二个 code 是代码。

看看 regex-demo:
https://regex101.com/r/EsERkJ/1

由于我不懂 perl,所以无法帮助您实现:(

有两种方法可以执行代码并捕获输出:

  • 您可以将其写入临时文件并使用 my $result = qqx{perl6 $filename} 生成一个单独的进程
  • 您可以使用 EVAL 在同一解释器中执行代码,并使用 IO::Capture::Simple 捕获 STDOUT:
my $re = regex {
    ^^ # logical newline
    '```{perl6 evaluate=' (TRUE|FALSE) '}'
    $<code>=(.*?)
    '```'
}

for $input.match(:global, $re) -> $match {
    if $match[0] eq 'TRUE' {
        use IO::Capture::Simple;
        my $result = capture_stdout {
            use MONKEY-SEE-NO-EVAL;
            EVAL $match<code>;
        }
        # use $result now
    }
}

现在您只需要从 match 切换到 subst 和 return 您想要替换的块中的值,然后就完成了。

我希望这能给您一些下一步的想法。

完成“我想完成的事情”的代码

你可以run this code against your data with glot.io.

use v6;

constant $ticks = '```';

my regex Search {
  $ticks '{raku evaluate=' $<evaluate>=(TRUE|FALSE) '}'
  $<code>=[<!before $ticks> .]*
  $ticks
}

sub Replace ($/) {
  "Code:\n" ~ $ticks ~ $<code> ~ $ticks ~
    ($<evaluate> eq 'TRUE'
      ?? "\n\n" ~ 'Output:' ~ "\n" ~ $ticks ~ "\n" ~ Evaluate($<code>) ~ $ticks
      !! '');
}

sub Evaluate ($code) {
  my $out; my $*OUT = $*OUT but role { method print (*@args) { $out ~= @args } }
  use MONKEY; my $eval-result = EVAL $code;
  $out // $eval-result ~ "\n"
}

spurt
  'example_new.md',
  slurp('example.md')
    .subst: &Search, &Replace, :g;

说明

从底部开始,然后向上工作:

  • The .subst method substitutes parts of its invocant string that need to be replaced and returns the revised string. .subst's first argument is a matcher; it can be a string, or, as here, a regex -- &Search1. .subst's second argument is a replacement; this can also be a string, or, as here, a Callable -- &Replace. If it's a Callable then .subst passes the match from the matcher as a match object2作为Callable的第一个参数。 :g 副词指示 .subst 重复执行 search/replace 以获得与调用字符串中一样多的匹配项。

  • slurp 从文件中一次性生成一个字符串。不需要 open、使用句柄、close 等。在这种情况下,其结果成为上述 .subst 的调用者。

  • spurt 做相反的事情,从一个字符串一次性生成一个文件,在本例中是 slurp(...).subst... 操作的结果。

  • Evaluate 例程生成一个字符串,该字符串是评估传递给它的代码字符串的输出。为了捕获评估结果,它临时修改 Raku's STDOUT variable $*OUT,将 prints(因此也 says 等)重定向到 EVAL 之前的内部变量 $out编码。如果 EVAL 的结果是 printd 到 $out 则返回;如果不是,则返回 EVAL 的结果(由 ~ 强制转换为字符串)。 (在第二个场景中附加了一个换行符,但不是第一个场景,因为考虑到您如何通过示例“指定”事物,这是获得正确显示结果所需要的。)

  • Replace 例程从 Code 正则表达式的调用中传递了一个匹配对象。它使用 $<code> 捕获重建代码部分(没有评估位)。如果 $<evaluate> 捕获是 'TRUE',那么它还会附加一个新的 Output: 部分,使用上面解释的 Evaluate 例程来生成代码的输出。

  • Code 正则表达式 匹配 代码段。它 捕获 评估指令中的 TRUEFALSE 设置到名为 $<evaluate> 的捕获中,并将代码捕获到名为 $<code> 的捕获中.

脚注

1 要传递一个例程(正则表达式是一个例程)而不是调用它,它必须写成 with 一个印记 ( &foo), 并非没有 (foo).

2 即使匹配器只是一个字符串,它也会这样做!