【问题标题】:How to print an object, type in nqp如何打印一个对象,输入 nqp
【发布时间】:2020-06-30 21:18:13
【问题描述】:

如何在 NQP 中打印对象? (用于调试目的)

  • 在 Raku 中很容易:

    1. say 在其短循环中调用 gist code
    2. ddpost 所示的微型数据转储器
class Toto { has $.member = 42; }
class Titi { has $.member = 41; has $.toto = Toto.new }
my $ti = Titi.new;
say $ti;
# Titi.new(member => 41, toto => Toto.new(member => 42))
dd $ti;
# Titi $ti = Titi.new(member => 41, toto => Toto.new(member => 42))
  • 在 NQP 中似乎更复杂
class Toto { has $!member; sub create() {$!member := 42}};
class Titi { has $!member; has $!toto; sub create() {$!member := 41; $!toto := Toto.new; $!toto.create; }}
my $ti := Titi.new;
say($ti);
Cannot stringify this object of type P6opaque (Titi)

当然,没有 .gist 方法,code 调用 nqp::encode 最终需要一个字符串。

【问题讨论】:

    标签: raku nqp


    【解决方案1】:

    目前,我拥有的是 listhash 鉴别器。它不适用于对象。

    sub print_something ($value, :$indent = 0, :$no-indent=0) {
        if nqp::ishash($value) {
            print_hash($value, :$indent);
        } elsif nqp::islist($value) {
            print_array($value, :$indent);
        } else {
            if $no-indent {
                say($value);
            } else {
                say_indent($indent, $value);
            }
        }
    }
    

    在哪里

    sub print_indent ($int, $string) {
        my $res := '';
        my $i := 0;
        while $i < $int {
            $res := $res ~ '  ';
            $i := $i + 1;
        }
        $res := $res ~ $string;
        print($res);
    }
    
    sub print_array (@array, :$indent = 0) {
        my $iter := nqp::iterator(@array);
        say_indent($indent, '[');
        while $iter {
            print_value(nqp::shift($iter), :indent($indent+1));
        }
        say_indent($indent, ']');
    }
    
    sub print_hash (%hash, :$indent = 0) {
        my $iter := nqp::iterator(%hash);
        say_indent($indent, '{');
        while $iter {
            my $pair := nqp::shift($iter);
            my $key := nqp::iterkey_s($pair);
            my $value := nqp::iterval($pair);
            print_indent($indent + 1, $key ~ ' => ');
            print_value($value, :indent($indent+1), :no-indent(1));
        }
        say_indent($indent, '}');
    }
    

    【讨论】:

      【解决方案2】:

      将问题简化为MRE

      class foo {}
      say(foo.new); # Cannot stringify ...
      

      简化解决方案:

      class foo { method Str () { 'foo' } }
      say(foo.new); # foo
      

      总之,添加一个Str 方法。

      这听起来很简单,但有很多幕后的东西需要考虑/解释。

      nqp 与 raku

      上述解决方案与 raku 使用的技术相同;当例程/操作期望值是字符串,但不是,语言行为是尝试强制转换为字符串。具体看是否有Str方法可以对值调用,如果有,调用。

      在这种情况下,NQP's NQPMuraku's Mu 更准系统,不提供任何默认的Str 方法。所以一个解决方案是手动添加一个。

      更一般地说,NQP 是一种非常有敌意的语言,除非您非常了解 raku 并且已经通过 A course on Rakudo and NQP internals

      一旦您掌握了该课程中的材料,我建议您将 IRC 频道 #raku-dev 和/或 #moarvm 视为您的第一个停靠港,而不是 SO(除非您的目标是专门增加 nqp/moarvm 的 SO 覆盖)。

      调试编译器代码

      如您所见,您链接的 NQP 代码在文件句柄上调用 .say

      然后调用this method

      该方法的主体是$str ~ "\n"。该代码将尝试将$str 强制转换为字符串(就像在 raku 中一样)。这就是生成“无法字符串化”错误的原因。

      在 NQP 存储库中搜索“无法字符串化”仅匹配一些 Java 代码。而且我敢打赌你没有在 JVM 上运行 Rakudo。这意味着错误消息必须来自 MoarVM。

      在 MoarVM 存储库中进行相同的搜索会产生 this line in coerce.c in MoarVM

      在包含该行的例程中向后看,我们看到this bit

      /* Check if there is a Str method. */
          MVMROOT(tc, obj, {
              strmeth = MVM_6model_find_method_cache_only(tc, obj,
                  tc->instance->str_consts.Str);
      });
      

      这显示了用 C 语言编写的后端,它正在寻找并调用一个名为 Str 的“方法”。 (它依赖于编译器的所有三层(raku、nqp 和后端)都遵循的内部 API (6model)。)

      自定义Str 方法

      您需要根据需要自定义Str 方法。例如,如果是类型对象,则打印类的名称,否则打印其$!bar 属性的值:

      class foo {
        has $!bar;
        method Str () { self ?? nqp::coerce_is($!bar) !! self.HOW.name(self) }
      }
      say(foo.new(bar=>42)); # 42
      

      尽管有方法名称,但 nqp say 例程期望 raku Str 而是 nqp 本机字符串(最终成为 MoarVM 后端上的 MoarVM 本机字符串)。因此需要nqp::coerce_is(我通过浏览the nqp ops doc 发现)。

      self.HOW.name(self) 是 nqp 没有 raku 所具有的细节的另一个例子。您可以在 raku 中编写相同的代码,但在 raku 中编写代码的惯用方式是 self.^name

      【讨论】:

      • 完美地回答了这个问题。我会看看 IRC :我不习惯这个频道。但是是的,我发现以后的人更容易找到答案:它是由机器人滚动的,漂亮...
      猜你喜欢
      • 2017-09-30
      • 2023-01-07
      • 2012-01-02
      • 2012-01-11
      • 1970-01-01
      • 1970-01-01
      • 2020-10-01
      • 1970-01-01
      • 2021-10-19
      相关资源
      最近更新 更多