luke-gru / riml

Riml is a subset of VimL with some nice added features. It compiles to plain VimL.
MIT License
224 stars 6 forks source link

exception when calling method on a list item in one statement #31

Closed tek closed 10 years ago

tek commented 10 years ago

items[0].method() gives:

/home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/ast_rewriter.rb:498:in `match?': undefined method `scope_modifier' for #<Riml::ListOrDictGetNode:0x000000020b7c08> (NoMethodError)
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/ast_rewriter.rb:90:in `do_rewrite_on_match'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/walker.rb:20:in `call'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/walker.rb:20:in `walk_node'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/ast_rewriter.rb:86:in `rewrite_on_match'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/ast_rewriter.rb:419:in `replace'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/ast_rewriter.rb:90:in `do_rewrite_on_match'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/walker.rb:20:in `call'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/walker.rb:20:in `walk_node'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/ast_rewriter.rb:86:in `rewrite_on_match'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/ast_rewriter.rb:69:in `block in rewrite'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/ast_rewriter.rb:68:in `each'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml/ast_rewriter.rb:68:in `rewrite'
        from grammar.y:610:in `parse'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml.rb:71:in `do_compile'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/lib/riml.rb:61:in `compile'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/bin/riml:141:in `start'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/bin/riml:161:in `<module:Riml>'
        from /home/tek/.rvm/gems/ruby-2.1.0/gems/riml-0.3.9/bin/riml:6:in `<top (required)>'
        from /home/tek/.rvm/gems/ruby-2.1.0/bin/riml:23:in `load'
        from /home/tek/.rvm/gems/ruby-2.1.0/bin/riml:23:in `<main>'
        from /home/tek/.rvm/gems/ruby-2.1.0/bin/ruby_executable_hooks:15:in `eval'
        from /home/tek/.rvm/gems/ruby-2.1.0/bin/ruby_executable_hooks:15:in `<main>'
luke-gru commented 10 years ago

Thanks for the report! I'll have a fix for this very soon, it's surprising this one got through for so long :smile:

tek commented 10 years ago

yeah :) I encountered several other rather trivial bugs, I'll just put them here:

class MyClass
  def initialize(foo={})
  end
end

compiles to

function! s:MyClassConstructor(#<struct Riml::DefaultParamNode parameter="foo", expression=#<struct Riml::DictionaryNode value=[]>>)
  let myClassObj = {}
  return myClassObj
endfunction

Then

def foo#boo(args={})
end

becomes

function! foo#boo(...)
  if get(a:000, 0, 'rimldefault') !=# 'rimldefault'
    let args = remove(a:000, 0)
  else
    let args = {}
  endif
endfunction

which will fail with a type error in the comparison when the argument is a dict or list. So there needs to be a != type('foo') || ... before the actual string comparison.

When assigning a new class instance to a variable while passing splat args to the constructor, the syntax gets mixed up:

class Foo
end

def foo#boo(*args)
  let foo = new Foo(*args)
end

becomes

function! foo#boo(...)
  let foo = let __riml_splat_list = a:000
  let __riml_splat_size = len(__riml_splat_list)
  let __riml_splat_str_vars = []
  let __riml_splat_idx = 1
  while __riml_splat_idx <=# __riml_splat_size
    let __riml_splat_var_{__riml_splat_idx} = get(__riml_splat_list, __riml_splat_idx - 1)
    call add(__riml_splat_str_vars, '__riml_splat_var_' . __riml_splat_idx)
    let __riml_splat_idx += 1
  endwhile
endfunction

The let is being placed inside of the assignment of the varargs and the actual constructor call is omitted completely.

That's about it for now, maybe I'll try patching some myself!

luke-gru commented 10 years ago

Hey @tek, I just fixed all the bugs in this thread except for the original, which I can't seem to reproduce. Could you give me a standalone example where it fails?

Also, @dsawardekar had a much better idea when it came to calling functions with *splat variables. I basically didn't know how to go about it, and just brute forced it :-1:

With his idea, your example compiles to:

function! foo#boo(...)
  let foo = call('s:FooConstructor', a:000)
end

Thanks,

tek commented 10 years ago

Here you go:

class Foo
  def foo
    foo = [1,2,3]
    foo[0].foo()
  end
end

It doesn't fail in a free function.

tek commented 10 years ago

I just tried the fixes, looks great! Although the second bug from my follow-up post isn't fixed – a dict argument still gets directly compared to the string 'rimldefault'.

luke-gru commented 10 years ago

Yes I'm still thinking what the best way to compile the default arguments would be. I don't really want to resort to type-checking. Any ideas?

For now, I could use type-checking if we don't come up with other ideas, and merge that in. It'll get done either tonight or tomorrow.

Thanks!

tek commented 10 years ago
class Foo
  def initialize
    extend(self, {})
  end
end

Here, self will not be rewritten as fooObj

Please tell me if my bug reports are getting obnoxious ;)

luke-gru commented 10 years ago

Keep them coming! :+1: :+1:

tek commented 10 years ago

maybe I'm missing something here, but wouldn't

let args = copy(a:000)
if !empty(args)
  arg1 = remove(args, 0)
else
  arg1 = 'mydefaultvalue'
end

do it? First of all, you cannot call remove on a:000, as it is immutable. And the existence of an element in a:000 should be enough, don't you think?

luke-gru commented 10 years ago

Ah okay, I didn't know that the arguments var was immutable, but that makes perfect sense. Yes, in that case I'm going with your suggestion :smile:

tek commented 10 years ago

great :)

luke-gru commented 10 years ago

All these bugs are now taken care of in the latest release I pushed just now, 0.4.0. Thanks for helping out!

tek commented 10 years ago

awesome, works great!