The Crystal Programming Language Forum

Macro not working anymore

I found this macro on the internet (don’t know the author) which I use
for loops. I could rewrite those statements so it is not that important.

Following macro works with Crystal 0.34 but not with Crystal 0.35

Crystal 0.35 error

syntax error in eval:9
Error: expecting token '%}', not 'in'
macro for(*exp, &block)
  {% if exp[0].is_a?(Assign) %}
    {{exp[0]}}
    while {{exp[1]}}
      {{block.body}}
      {{exp[2]}}
    end
  {% else %}
    {% in = exp.last.args.first;    in2 = in.args.last   %}
    {% variables = exp.stringify.split('(')[0][1..-1].id %}
    {% block = in.block.stringify.empty? ? in2.block : in.block %}
    {% if in2.is_a?(Call) && !in2.block.stringify.empty? %}
      {% enumerable = in2.stringify.split(" do\n")[0].id %}
    {% else %}
      {% enumerable = in2 %}
    {% end %}
    ({{enumerable}}).each { |{{variables}}| {{block.body}} }
  {% end %}
end

# usage
for i in 0..9 do
  puts i
end

Exhaustive case made in a keyword.

A working version where ‘in’ is replaced by ‘witihin’

macro for(*exp, &block)
  {% if exp[0].is_a?(Assign) %}
    {{exp[0]}}
    while {{exp[1]}}
      {{block.body}}
      {{exp[2]}}
    end
  {% else %}
    {% within = exp.last.args.first; in2 = within.args.last   %}
    {% variables = exp.stringify.split('(')[0][1..-1].id %}
    {% block = within.block.stringify.empty? ? in2.block : within.block %}
    {% if in2.is_a?(Call) && !in2.block.stringify.empty? %}
      {% enumerable = in2.stringify.split(" do\n")[0].id %}
    {% else %}
      {% enumerable = in2 %}
    {% end %}
    ({{enumerable}}).each { |{{variables}}| {{block.body}} }
  {% end %}
end

# usage
for i within 0..9 do
  puts i
end

Thanks

And here’s a non-macro version where code is easier to understand and it actually compiles faster:

(0…9).each do |i|
puts i
end

1 Like

Or better yet:

9.times do |i|
  puts i
end
1 Like