Closed tek closed 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:
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!
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,
Here you go:
class Foo
def foo
foo = [1,2,3]
foo[0].foo()
end
end
It doesn't fail in a free function.
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'.
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!
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 ;)
Keep them coming! :+1: :+1:
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?
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:
great :)
All these bugs are now taken care of in the latest release I pushed just now, 0.4.0
. Thanks for helping out!
awesome, works great!
items[0].method()
gives: