string-each-char example simply doesn't work #167

Closed
RobertFischer opened this Issue Jan 31, 2012 · 5 comments

Projects

None yet

4 participants

@RobertFischer
Collaborator

https://github.com/mirah/mirah/blob/master/examples/macros/string-each-char.mirah

When I execute this code on Mirah v0.0.10:

macro def eachChar(value, &block)

    quote { 
        `value`.toCharArray.each do | my_char |
            `block.body`
        end 
    }
end

eachChar('laat de leeeuw niet in zijn hempie staan') do | my_char |
    puts my_char
end

I get this error:

wl-10-180-107-72:tmp robert$ mirah foo.mirah 
file:/Users/robert/bin/mirah/lib/mirah-complete.jar!/builtin/javasupport/core_ext/object.rb:99 warning: already initialized constant Exception
Warning: No ClassDefinition for Foo. Macros can't be loaded from disk.
Inference Error:
Cannot find static method my_char() on Foo
foo.mirah:12: Cannot find static method my_char() on Foo
    puts my_char
        ^^^^^^^^
Exception in thread "main" org.jruby.exceptions.RaiseException: (SystemExit) exit
    at org.jruby.RubyKernel.exit(org/jruby/RubyKernel.java:867)
    at org.jruby.RubyKernel.exit(org/jruby/RubyKernel.java:836)
    at Mirah::Commands::Base.execute_base(file:/Users/robert/bin/mirah/lib/mirah-complete.jar!/mirah/commands/base.rb:53)
    at Mirah::Commands::Run.execute(file:/Users/robert/bin/mirah/lib/mirah-complete.jar!/mirah/commands/run.rb:23)
    at #<Class:0x11e448bf7>.run(file:/Users/robert/bin/mirah/lib/mirah-complete.jar!/mirah.rb:36)
    at #<Class:0x15629507c>.run(src/org/mirah/mirah_command.rb:55)
    at #<Class:0x15629507c>.main(src/org/mirah/mirah_command.rb:40)

What's the syntax for developing macros like this?

@abscondment
Collaborator

I had to do two things to make this work:

First, explicitly pass my_char to the block:

  macro def eachChar(value, &block)
    quote { 
      `value`.toCharArray.each do |my_char|
        `block.body` my_char
      end
    }
  end

That gave me a second error:

Parsing...
  Foo.mirah
Inferring types...
Inference Error:
Cannot find instance method println(char) on Foo
Foo.mirah:6: Cannot find instance method println(char) on Foo
        `block.body` my_char
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

From what I can tell, the call println is losing its surrounding context; i.e. the macro assumes its a method that lives on Foo. Same thing happens when I call System.out.println directly instead of via puts.

So, my hacky workaround:

  def foo(s:String)
    eachChar(s) do |c|
      display c
    end
  end

  def display(c:char)
    puts c
  end
@ribrdb
Collaborator
ribrdb commented Jan 31, 2012

What you need is:

quote {
    `value`.toCharArray.each do | `block.parameters` |
        `block.body`
    end
}

But I don't think that's supported with the old AST api. It looks
like I will soon have time to work on finishing up the newast branch
so that these types of macros will work properly.

On Tue, Jan 31, 2012 at 6:59 AM, Robert Fischer
reply@reply.github.com
wrote:

   quote {
       value.toCharArray.each do | my_char |
           block.body
       end
   }

@RobertFischer
Collaborator

If the block contains two expressions, both of which take the
argument, how are we supposed to pass an argument into the argument?

@ribrdb
Collaborator
ribrdb commented Jan 31, 2012

If I understand your question, you'd need to do something like this:

macro def eachModifiedChar(value, &block)
  quote { 
    `value`.toCharArray.each do |my_char|
      `block.arguments.required(0)` = my_char + 1
      `block.body`
    end
  }
end

This does seem awkward, maybe we'll need to work on an api for working with block parameters inside macros.

@baroquebobcat
Member

I updated the example to get it running again. It seems that the &block syntax doesn't work anymore, you have to say block:Block.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment