In one of my projects, I needed the ability to generate an AST from valid Crystal code. I couldn't find any documentation about using the Crystal compiler API's, only gathered information here and there from random GitHub issues–thought I'd write things down here for the next person. Hope it's helpful for you:
As of v0.32.1
You can parse Crystal code into an AST tree by using Crystal::Parser
from the syntax
module:
require "compiler/crystal/syntax"
parser = Crystal::Parser.new("class HelloWorld\nend")
# This will give you a Crystal::ASTNode
ast = parser.parse
Crystal::ASTNode
is the parent class for all AST nodes. You can find the different AST node types here: https://github.com/crystal-lang/crystal/blob/0.32.1/src/compiler/crystal/syntax/ast.cr. You'll need to use the .class
, .is_a?
, ... API's to work with the specific types.
A small gotcha: beware that
class Path < ASTNode
collides withstruct Path
. You'll have to use the fully qualified::Crystal::Path
when referring to it.
Another thing that comes with the syntax module is Crystal::Transformer
. This lets you inspect/transform different node types. For example:
# ... continue from above
class MyTransformer < Crystal::Transformer
def transform(node : Crystal::ClassDef) : Crystal::ASTNode
puts "Class definition for #{node.name} at #{node.location}"
super(node)
end
end
tx = MyTransformer.new
transformed_node = ast.transform(tx)
Older versions
According to this GitHub issue, seems like the modules were in a different place in older versions:
require "compiler/crystal/parser"
require "compiler/crystal/transformer"