Casting an instance of derived class

Hi all !

I’ve this function

def parse_keyword(parent : AST::Node)
# ...
end

When called and outputing the parent class

puts typeof(parent), parent.class

I get
AST::NodeFunctionBody AST::NodeFunctionBody
So far, so good

AST::NodeFunctionBody derives from AST::Node,

class NodeFunctionBody < Node
    getter ident : Ident # function name

    def initialize(token, @ident)
      super(token)
    end
  end

But at some point I need to access a member of this AST::NodeFunctionBody pointer/reference
As in

parent.ident

So I do

puts parent.as(AST::NodeFunctionBody).ident

But it won’t compile
Error: can't cast AST::NodeBlock to AST::NodeFunctionBody

I tried to change the function’s signature

def parse_keyword(parent : AST::NodeFunctionBody)
end

But I get the same exact problem at an upper level

So, why can’t I force the “node” parameter to be an AST::NodeFunctionBody ?

Edit : Just after posting I tried

if parent.is_a?(AST::NodeFunctionBody)
        pp parent.as(AST::NodeFunctionBody).
end

And it works… But I don’t understand why

Edit 2
Ok, I think I figured it out - parent is not always a NodeFunctionBody, but can also be a derived of NodeKeyword, so it won’t cast, which makes sense, sorry for the noise ;-)

2 Likes

You can also use some of Crystal’s compiler code as a library.

require "compiler/crystal/syntax"

str = ARGF.gets_to_end
a = Crystal::Lexer.new(str)
b = Crystal::Parser.parse(str)

Defined classes can be modified by a technique called open classes.
You may already know this, but for your information…

I’m not parsing Crystal source, but my own toy language ;-) A difficult personal project, but a very rewarding one… At least if I can go 'til the backend

3 Likes