Crystal 解析器创建一个 ASTNode,它在运行时应该是 Crystal::Expressions 但不知何故是 Crystal::Nop

Crystal parser creates an ASTNode that should be Crystal::Expressions at runtime but is somehow a Crystal::Nop

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? 是运行时检查,因此编译时类型为 ASTNodenodes 应该是 Crystal::Expressions,而不是 Crystal::Nop .

crystal 版本 0.25.0、0.25.1、0.26.0、0.26.1 和当前 git 存储库主分支上的版本的行为相同。

编译时会出现错误,因为 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

或者,您可以使用 .as:

强制编译器假定它是 Crystal::Expressions
nodes.as(Crystal::Expressions).expressions

此答案归功于 straight-shoota on this Github issue