Crystal parser создает ASTNode, который должен быть Crystal :: Expressions во время выполнения, но каким-то образом Crystal :: Nop - PullRequest
0 голосов
/ 01 ноября 2018
require "compiler/crystal/syntax"

s = "a = 5; puts a + 3"

nodes = Crystal::Parser.parse(s)
puts nodes.class                      # => Crystal::Expressions
puts nodes.is_a? Crystal::Expressions # => true
puts nodes.is_a? Crystal::Nop         # => false

puts nodes.expressions

Итак, я бы предположил, что последнее выражение даст массив (или узел ArrayLiteral). Тем не менее, я получаю

undefined method 'expressions' for Crystal::Nop (compile-time type is Crystal::ASTNode+)

Что не имеет смысла. .class и .is_a? - проверки во время выполнения, поэтому nodes, который имеет тип времени компиляции ASTNode, должен быть Crystal::Expressions, а не Crystal::Nop.

Поведение аналогично в версиях Crystal 0.25.0, 0.25.1, 0.26.0, 0.26.1 и в настоящее время в основной ветке git repo.

1 Ответ

0 голосов
/ 01 ноября 2018

Ошибка возникает во время компиляции, потому что не у всех подклассов Crystal::ASTNode есть метод #expressions. Crystal::Nop как раз оказывается первым таким подклассом, который проверяет компилятор и впоследствии решает выдать ошибку. Способ исправить код:

require "compiler/crystal/syntax"

s = "a = 5; puts a + 3"

nodes = Crystal::Parser.parse(s)
case nodes
when Crystal::Expressions
    puts nodes.expressions
when Crystal::Nop
    puts "It's a nop"
else
    puts "Unhandles case for #{nodes.class}"
end

Кроме того, вы можете заставить компилятор предположить, что он Crystal::Expressions, используя .as:

nodes.as(Crystal::Expressions).expressions

Кредит за этот ответ идет на прямой удар в этом выпуске Github

...