Как распечатать объект, введите nqp
Как распечатать объект в NQP? (Для отладки)
В Раку легко:
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, '}');
}