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

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

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

    1. say that is calling gist in its short loop code
    2. dd Крошечный дампер данных, как показано на этом post
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 метода,


person Tinmarino    schedule 19.03.2020    source источник


Ответы (2)


Сведение проблемы к MRE:

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

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

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

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

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

nqp против раку

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

В этом случае NQP NQPMu, который является более простым чем Mu raku по умолчанию, Str метод. Итак, решение - добавить его вручную.

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

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

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

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

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

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

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

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

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

person raiph    schedule 19.03.2020
comment
Это прекрасно отвечает на вопрос. Посмотрю IRC: я не привык к этому каналу. Но да, я нахожу НАСТОЛЬКО более легким для более поздних людей найти ответ: он прокручивается ботом, симпатично ... - person Tinmarino; 20.03.2020

В настоящее время у меня есть дискриминатор 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, '}');
}
person Tinmarino    schedule 19.03.2020