Как распечатать объект, введите nqp

Как распечатать объект в NQP? (Для отладки)

  • В Раку легко:

    1. скажем, что вызывает суть в своем коротком коде цикла
    2. dd Крошечный Data Dumper, как показано в этом посте
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метод, код вызываетnqp::encode который, наконец, ожидает строку.

2 ответа

Решение

Сведение проблемы к ИМО:

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

Упрощение решения:

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

Таким образом, добавьте Str метод.

Звучит просто, но нужно учесть / объяснить множество закулисных вещей.

nqp против раку

Вышеупомянутое решение является той же техникой, которую использует Раку; когда подпрограмма / операция ожидает, что значение будет строкой, но не является, поведение языка заключается в попытке принуждения к строке. В частности, посмотрите, есть лиStr метод, который может быть вызван для значения, и если да, вызовите его.

В этом случае NQPNQPMu, который намного более прост, чем у rakuMu, не предоставляет никаких значений по умолчанию Strметод. Поэтому решение - добавить его вручную.

В более общем плане, NQP - довольно враждебный язык, если вы не знаете раку достаточно хорошо и не прошли курс по внутреннему устройству Rakudo и NQP.

И как только вы освоите материал этого курса, я рекомендую вам рассматривать IRC-каналы # raku-dev и / или #moarvm в качестве вашего первого порта захода, а не SO (если ваша цель не заключается конкретно в увеличении покрытия SO. из nqp/moarvm).

Отладка кода компилятора

Как вы увидите, код NQP, с которым вы связали вызовы .say на файловой ручке.

Затем вызывается этот метод.

Тело этого метода $str ~ "\n". Этот код попытается принудить$strна строку (так же, как и в раку). Вот что приведет к ошибке "Невозможно преобразовать в строку".

Поиск по запросу "Невозможно преобразовать в строку" в репозитории NQP совпал только с некоторым кодом Java. Бьюсь об заклад, вы не используете Rakudo на JVM. Это означает, что сообщение об ошибке должно исходить от MoarVM.

Тот же поиск в репо MoarVM дает эту строку вcoerce.cв MoarVM.

Оглядываясь назад на процедуру, содержащую эту строку, мы видим этот бит:

/* 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. (Он полагается на внутренний API (модель 6), которому соответствуют все три уровня компилятора (raku, nqp и backends).)

Настройка 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рутина не ожидает ракуStrа скорее нативная строка nqp (которая в конечном итоге становится нативной строкой MoarVM на бэкэнде MoarVM). Следовательно, необходимость вnqp::coerce_is(который я нашел, просматривая документацию nqp ops).

self.HOW.name(self)это еще один пример того, как в nqp нет таких тонкостей, как у raku. Вы можете написать тот же код на raku, но идиоматический способ написать его на rakuself.^name.

В настоящее время у меня есть list а также hashдискриминатор. Не работает на объекте.

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, '}');
}
Другие вопросы по тегам