Search code examples
crystal-lang

Expanding symbol variable inside a macro


class Controller
  def index
    puts "hello"
  end
end

macro handler(controller, action)
  c = {{controller}}.new
  c.{{action.id}}
end

# this doesn't work
temp = :index
handler Controller, temp

# this works
handler Controller, :index

Somehow on the first case, the macro gets expanded to c.temp instead of c.index

Is it possible to call a function inside a class like in above code snippet.

Edit: I am trying to achieve something like this, https://github.com/Amber-Crystal/amber/blob/master/src/amber/dsl/router.cr#L16


Solution

  • temp is a runtime variable, while macros are interpreted at compile time. That means the Crystal compiler can't actually know the value of temp, as it is only known at runtime. Tracing variables to literal values could be done to some degree, but would be expensive and brittle to use, since a small change may make it impossible.

    When you call a macro, the arguments are actual AST nodes, expressions of parsed source code. So in your example the macro gets a TypeNode as first argument and a Var as second argument.