如何制作上下文感知代码评估器

con*_*ext 6 raku

我正在从这里这里查看类似于 REPL 的代码评估,并尝试为其制作一个非常小的版本,但它失败了:

\n
use nqp;\n\nclass E {\n\n    has Mu $.compiler;\n    has $!save_ctx;\n\n    method evaluate(@fragments) {\n        for @fragments -> $code {\n            my $*MAIN_CTX;\n            my $*CTXSAVE := self;\n\n            $!compiler.eval($code,\n                            outer_ctx => nqp::ctxcaller(nqp::ctx()));\n\n            if nqp::defined($*MAIN_CTX) {\n                $!save_ctx := $*MAIN_CTX;\n            }\n        }\n    }\n\n    method ctxsave(--> Nil) {\n        say "*in ctxsave*";\n        $*MAIN_CTX := nqp::ctxcaller(nqp::ctx());\n        $*CTXSAVE := 0;\n    }\n\n}\n\nmy $e := E.new(compiler => nqp::getcomp("Raku"));\nnqp::bindattr($e, E, \'$!save_ctx\', nqp::ctx());\n$e.evaluate: (\'say my @vals = 12, 3, 4;\', \'say @vals.head\');\n
Run Code Online (Sandbox Code Playgroud)\n

我从上面的链接中拼凑而成,但不太知道我在做什么:)运行时,会发生这种情况:

\n
*in ctxsave*\n[12 3 4]\n===SORRY!=== Error while compiling file.raku\nVariable \'@vals\' is not declared.  Did you mean \'&val\'?\nfile.raku:1\n------> say \xe2\x8f\x8f@vals.head\n
Run Code Online (Sandbox Code Playgroud)\n

与 Rakudo v2022.04 一起使用。第一个片段应该声明它(并打印它)。是否有可能做这样的事情,所以它承认@vals声明?

\n

Jon*_*ton 6

context您可以使用纯 Raku 代码来完成此操作,尽管这取决于EVAL.

# Let us use EVAL with user input
use MONKEY;

loop {
    # The context starts out with a fresh environment
    state $*REPL-CONTEXT = UNIT::;
    
    # Get the next line of code to run.
    my $next-code = prompt '> ';

    # Evaluate it; note that exceptions with line numbers will be
    # off by one, so may need fixups.
    EVAL "\q'$*REPL-CONTEXT = ::;'\n$next-code", context => $*REPL-CONTEXT;
}
Run Code Online (Sandbox Code Playgroud)

尝试一下:

$ raku simple-repl.raku
> my $x = 35;
> say $x;
35
> my $y = 7;
> say $x + $y;
42
Run Code Online (Sandbox Code Playgroud)

  • `::` 本身给出了一个对应于当前词法范围的 `PseudoStash`。在 Raku 中编译后,词法作用域中的变量集是不可变的,因此实际上每个新的“EVAL”行都位于新的词法作用域中。我们安排下一个“EVAL”发生,使其外部范围是前一个“EVAL”的范围。这也是为什么你可以声明一个新的 `$a`:这不是冲突,因为新行是一个新的作用域。内置的 REPL 必然具有相同的语义! (2认同)
  • 我相信它是当前编译器实现的产物(它使用“UNIT”之外的额外框架作为实现细节)。 (2认同)