luke-gru / riml Goto Github PK
View Code? Open in Web Editor NEWRiml is a subset of VimL with some nice added features. It compiles to plain VimL.
License: MIT License
Riml is a subset of VimL with some nice added features. It compiles to plain VimL.
License: MIT License
@luke-gru Is there a way to create riml
function equivalent to Vim's uppercased function. I'm not sure there is a scope name for it. Basically the equivalent of the following function,
function! MyFunction()
endfunction
The generated code if I try to compile this with riml
has the default scope specifier like s:MyFunction
.
I was doing some preliminary work on a Syntastic plugin for riml. The Syntastic api relies on these type of functions which appear to work like global scoped functions.
function! SyntaxCheckers_riml_riml_IsAvailable()
endfunction
They are used like callbacks by Syntastic. Is there a way of writing this without resorting to a :function
workaround?
Thanks.
First of all I love what you're doing, and hope to get at least one plugin done in Riml soon to get a feel for the compiling workflow. Regarding the syntax, I presume the 'end' statements are necessary? It would be great if they were optional, but if they aren't I have to say I prefer Vimscript's native blocks, because they are self-documenting what they are closing, whereas in the current Riml syntax we end up with the sort of confusing "what is this closing?" doubts you get in languages like Python and HTML4, for instance.
I upgraded from 0.2.9 today and it broke class generation. when trying to instantiate a class, I get the error
E117: Unknown function: s:SID
E116: Invalid arguments for function function('<SNR>' . s:SID() . '_s:MyClass_method_name')
E15: Invalid expression: function('<SNR>' . s:SID() . '_s:MyClass_method_name')
I put a debug output statement into ast_rewriter.rb and a SID node is excluded in the rewritten syntax tree, though it's not present in the generated viml file.
If I just paste it on top of the riml file (in VimL), everything's fine.
Also, the generated methods look like
function! <SID>s:MyClass_method_name()
Isn't the s:
superfluous?
Given the following Riml,
bar = "one"
foo = "\"#{bar}\""
echo foo
results in the output,
let s:bar = "one"
let s:foo = "\"#{bar}\""
echo s:foo
The bar
variable is present as is. It should result in string concatanation.
I recently had an issue with compatibility of generated viml
run with different versions of Vim. The issue was causing a Trailing Characters error. I narrowed the error itself to to patch 97 of Vim 7.3.
I'm wondering if you've run across similar issues with Riml
. For instance in the above case, unless
blocks that return early might cause problems. What would be a minimum version of Vim required to use most of the features of Riml
? I'm trying to determine what bare minimum and recommended versions to use with Portkey
.
Also, I've been meaning to ask you, whether you've written any plugins in Riml. I've been sort of winging it as I go along, so I'd love to see your work!
And If possible could you do a code review of Portkey? I'm sure there are things to improve. As the Inventeur
of the language I'm sure you'll spot many silly errors in there. 😄
The viml
code generated by riml
is quite readable. But there are a few issues with polluting the global function scope.
For instance,
class Foo
end
produces,
function! g:FooConstructor()
endfunction
And the methods of Foo become FooConstructor_method_name
. These are also on the global scope. I have a couple of ideas to avoid conflicts with methods defined in other plugins.
First change the scope of functions to be scriptlocal instead, ie:- s:FooConstructor
. This needs to a command line option, because it is sometimes beneficial to have the global scoped constructors as well. Eg:- http://github.com/dsawardekar/speckle uses global constructors to dynamically load specs.
My second suggestion is to additionally add a namespace
keyword.
namespace 'plugin.utils'
This could compile down to,
function! g:PluginUtilsFooConstructor
endfunction
The plugin
is the top level namespace and dots are replaced to use CamelCase.
When the compiler finds another namespace declaration that becomes the current namespace, ie:- compiling classes with that prefix instead. Thus avoid any nesting blocks.
This would mitigate any clashes with viml
generated code between plugins.
@luke-gru What do you think of just having riml_include 'foo'
, without the extension. Then detect that if the extension is not present and add it in. This reduces the verbosity in the includes, just a tad. :)
riml_include 'lorem.riml'
vs
riml_include 'lorem'
What do you think about having variables inside a function compile to local to function scope? Lookup :h local-variable
in Vim. The main reason I would like this is, as the help explains:
without prepending "l:" you may run into reserved variable names.
This is exactly the type of thing riml would be great for. I would love to not have to write l:my_var
inside all my functions and still know it won't refer to other variables outside the function scope.
What are your thoughts on this?
I just updated to 0.3.2, and it helped me figure out a bunch of dups I had been using without realizing. Thanks for that!
I also made an improvement to Speckle
to use Riml.compile_files
directly instead of bundle exec riml
. This speeds up compilation quite a bit, and leads me to this feature request.
I have quite a few tests that do a lot of riml_include 'foo'
style includes. For instance I have a couple of classes in files, log_helpers.riml
and delegate.riml
and dsl.riml
. These get include in nearly every spec at the top like so,
riml_include 'dsl.riml'
riml_include 'log_helpers.riml'
riml_include 'delegate.riml'
For simpler files this is not a big issue but for E2E tests the whole plugin is included which makes compile times quite slow.
Would it be possible to cache the result of a riml_include
for the duration of a riml compile session?
To clarify further, say I have E2E tests to run with includes like,
In controller_a_spec.riml
riml_include 'a.riml'
riml_include 'b.riml'
riml_include 'c.riml'
In controller_b_spec.riml
riml_include 'a.riml'
riml_include 'b.riml'
riml_include 'c.riml'
Now say when I run,
riml -c controller_a_spec.riml controller_b_spec.riml
The compiler should compile controller_a_spec.riml
and it's includes a, b and c
. But for controller_b_spec.riml
, it should just return the previously compiled a, b, and c includes, from in-memory cache.
Thus compiling controller_b_spec.riml
does not incur the cost of compiling a, b and c
. It only has to assemble the rest of the contents of controller_b_spec.riml
This feature would speed up compilation by an order of magnitude for Speckle
, by at least a factor of 5!
Using the viml native pyeval
function results in a script local function call s:pyeval
. This gives a runtime error, s:pyeval
not found when running the generated viml
.
Given the Riml,
result = pyeval('{ "foo": 1 }')
Gives the output Viml,
let s:result = s:pyeval('{ "foo": 1 }')
It should be just pyeval
.
Hey Luke,
I've been working a new Vim plugin, WordPress.vim and have a bunch of new bugs for you. :p
Calling super
in a child class without extending a parent class gives an undefined method
error. The code in question,
class Foo
def initialize
super()
end
end
The error is,
/home/dms/.rbenv/versions/1.9.3-p429/lib/ruby/gems/1.9.1/gems/riml-0.4.0/lib/riml/ast_rewriter.rb:676:in `replace': undefined method `error_msg' for #<Riml::AST_Rewriter::ClassDefinitionToFunctions::InitializeSuperToObjectExtension:0x00000002e67e20> (NoMethodError)
@luke-gru Another idea that may require a grammar change. :)
Add support for multiline comments like /* */
. This is a very useful feature when experimenting or debugging.
implement dependency graph and automatic dependency management for riml_include
.
The unless
block doesn't support nesting if statements. Consider this,
unless 'a' == 'b'
if 1 == 2
echo 'nope'
else
echo 'yup'
end
end
This code doesn't compile, instead produces the following error.
/home/dms/.rbenv/versions/1.9.3-p429/lib/ruby/gems/1.9.1/gems/riml-0.3.1/lib/nodes.rb:31:in `method_missing': undefined method `non_nested?' for #<Riml::UnlessNode:0x00000001e0afa0> (NoMethodError)
This is not a major bug since such unless blocks are usually at the top of a function to return
early. I needed to do some additional checks in one particular scenario when I came across this bug. Switching to an if
with a negative equality works.
I have been having this issue with both Portkey and WordPress.vim. I initially thought this was a regression in Vim in patch 260 that would get fixed in future patches. However it hasn't been reverted even upto patch 345.
I have now learnt that this is by design. Prefixing functions with <SNR>
and subsequent linking of functions to methods in the Constructor completely breaks in Vim p260+.
The issue was discussed in detail here. The conclusion appears to be that the old style was actually a bug, and this patch is a bugfix.
Any ideas how to resolve this?
I made a temporary attempt by replacing,
function! <SID>
with just function!
- in the function definitionsfunction('<SNR> . s:SID() . '_Foo_func')
with just function('s:Foo_func')
in the Constructor function linking functions to methods.I remember sometime back Riml used to compile without the SNRs. Would it be possible to revert back to that.
Alternately, that discussion thread might give you other ideas. I'm open to any at this point.
@luke-gru Without a resolution for this, any plugin developed in Riml won't work in any newer Vim version. :(
This code is a little more involved. It's part of a plugin I'm working on. Consider a class TemplateContext
with the code.
class TemplateContext
def initialize(data)
self.data = data
end
defm lookup(key)
if has_key(self, key)
return self[key]
elseif has_key(self.data, key)
return self.data[key]
elseif key == 'context'
return self.data
elseif has_key(self.data, 'lookup')
return self.data.lookup(key)
else
return ''
end
end
end
I am including this class in another file. Which includes another and so on. I've narrowed down the issue is to do with duplicate include like below.
riml_include 'template_context.riml'
riml_include 'template_context.riml'
With such a duplicate riml_include
the compiler get's very confused. See the output below. Further this output viml
does not run, giving a endfunction missing
error.
function! s:SID()
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
endfunction
" included: 'template_context.riml'
function! s:TemplateContextConstructor(data)
let templateContextObj = {}
let templateContextObj.data = a:data
let templateContextObj.lookup = function('<SNR>' . s:SID() . '_s:TemplateContext_lookup')
return templateContextObj
endfunction
function! <SID>s:TemplateContext_lookup(key) dict
if has_key(self, a:key)
return self[a:key]
elseif has_key(self.data, a:key)
return self.data[a:key]
elseif a:key ==# 'context'
return self.data
elseif has_key(self.data, 'lookup')
return self.data.lookup(a:key)
else
return ''
endif
endfunction
" included: 'template_context.riml'
function! s:TemplateContextConstructor(data)
let templateContextObj = {}
let templateContextObj.data = a:data
let templateContextObj.lookup = function('<SNR>' . s:SID() . '_s:TemplateContext_lookup')
return templateContextObj
endfunction
function! <SID>s:TemplateContext_lookup(key) dict
if has_key(self, a:key)
return self[a:key]
elseif has_key(self.data, a:key)
return self.data[a:key]
elseif a:key ==# 'context'
return self.data
elseif has_key(self.data, 'lookup')
return self.data.lookup(a:key)
else
return ''
endif
endfunction
function! s:TemplateContextConstructor(data)
let templateContextObj = {}
let templateContextObj.data = a:data
let templateContextObj.lookup = function('<SNR>' . s:SID() . '_s:TemplateContext_lookup')
return templateContextObj
endfunction
function! <SID>s:TemplateContext_lookup(key) dict
if has_key(self, a:key)
return self[a:key]
elseif has_key(self.data, a:key)
return self.data[a:key]
elseif a:key ==# 'context'
return self.data
elseif has_key(self.data, 'lookup')
return self.data.lookup(a:key)
else
return ''
endif
endfunction
function! s:TemplateContextConstructor(data)
let templateContextObj = {}
let templateContextObj.data = a:data
let templateContextObj.lookup = function('<SNR>' . s:SID() . '_s:TemplateContext_lookup')
return templateContextObj
endfunction
function! <SID>s:TemplateContext_lookup(key) dict
if has_key(self, a:key)
return self[a:key]
elseif has_key(self.data, a:key)
return self.data[a:key]
elseif a:key ==# 'context'
return self.data
elseif has_key(self.data, 'lookup')
return self.data.lookup(a:key)
else
return ''
endif
endfunction
function! s:TemplateContextConstructor(data)
let templateContextObj = {}
let templateContextObj.data = a:data
let templateContextObj.lookup = function('<SNR>' . s:SID() . '_s:TemplateContext_lookup')
return templateContextObj
let templateContextObj = {}
let templateContextObj.datatemplateContextObj.data = a:data
let templateContextObj.lookuptemplateContextObj.lookup = function('<SNR>' . s:SID() . '_s:TemplateContext_lookup''<SNR>' . s:SID()'<SNR>' . s:SID() . '_s:TemplateContext_lookup')
return templateContextObj
endfunction
function! <SID>s:TemplateContext_lookup(key) dict
if has_key(self, a:key)
return self[a:key]
elseif has_key(self.data, a:key)
return self.data[a:key]
elseif a:key ==# 'context'
return self.data
elseif has_key(self.data, 'lookup')
return self.data.lookup(a:key)
else
return ''
endif
if has_key(self, a:key)
return self[a:key]
elseif has_key(self.data, a:key)
return self.data[a:key]
elseif a:key ==# 'context'
return self.data
elseif has_key(self.data, 'lookup')
return self.data.lookup(a:key)
else
return ''
return self[a:key]self[a:key]
elseif has_key(self.data, a:key)
return self.data[a:key]
elseif a:key ==# 'context'
return self.data
elseif has_key(self.data, 'lookup')
return self.data.lookup(a:key)
elseif has_key(self.dataself.data, a:key)
return self.data[a:key]
return self.data[a:key]self.dataself.data[a:key]
elseif a:key ==# 'context'
a:key ==# 'context'
return self.data
return self.dataself.data
elseif has_key(self.dataself.data, 'lookup')
return self.data.lookup(a:key)
return self.data.lookup(a:key)
self.data.lookupself.data.lookup(a:key)
self.data.lookup(a:key)
else
return ''
return ''
endif
endfunction
The compiler appears to be stuck inside an internal loop. The output is concatenated in places, blocks are misaligned, etc.
I think the easiest way to deal with this is to not output anything for the second riml_include
.
Or if you are going to include the second time then memoize/cache the result of a riml_include
. So any secondary includes use the cached output instead.
The #11 issue got me thinking about error messages. In it's current state the compiler works quite well. But as I've started to explore a bit more I am seeing syntax errors that don't quite reflect the cause correctly.
One low hanging fruit I can think of is, reporting the file and line number that the error originated in. A good example of this is the Clang compiler. Here's a sample error message with an invalid printf
.
format-strings.c:91:13: warning: '.*' specified field precision is missing a matching 'int' argument
printf("%.*d")
^
To start with, the error shown in #11 could be reported as something like,
hello.riml:2:4: error: parse error on value "end" (END)
Another small improvement would be to hide the stacktrace by default. The ruby stacktrace doesn't convey anything meaningful to the user, and will give new users a wrong initial impression, One that doesn't really reflect the actual state of the compiler. A stacktrace like that suggests something broke in the compiler even when that isn't the case.
A --verbose
or --debug
flag could enable the stacktrace for debugging purposes.
For further reading, Clang Expressive Diagnostics
@luke-gru I'm having an issue with creating and passing an object to a function as an argument.
The following code compiles without errors.
class Person
end
def add_person(person)
echo 'add_person'
end
add_person(new Person())
The compiled code contains an extra newline in the add_person
call.
function! g:PersonConstructor()
let personObj = {}
return personObj
endfunction
function! s:add_person(person)
echo 'add_person'
endfunction
call s:add_person(g:PersonConstructor()
)
This extra newline makes this code invalid.
@luke-gru Does the word append
have any special meaning within Riml
? Here's an odd bug that reports a syntax error.
def change_destination(lines, range, opts)
if opts.append
append(line('$'), lines)
else
setline(1, lines)
end
end
This code doesn't compile, the error suggests too many END
statements, which is incorrect.
../riml-0.3.2/lib/lexer.rb:288:in `check_indentation': 1 too many END identifiers (Riml::SyntaxError)
Switching to an array access operator like opts['append']
works fine.
This isn't a bug/issue. I have created a syntax highlighting file for riml. It's adapted from the coffeescript syntax file. It's pretty basic, but it looks ok with the Solarized theme.
https://github.com/dsawardekar/riml.vim
If you have any suggestions please let me know.
@luke-gru I recently added Profiling support to Speckle. While profiling my extensions I noticed that the SID
function that Riml generates is executed a very large number of times. In Portkey this is most apparent with something like 30,000+ calls. The function itself is quite fast. Since the SID
doesn't change I'd like to cache this out if possible.
I'm thinking something like a SID_VALUE
that holds the result with a function like below,
function! s:SID()
if exists('s:SID_VALUE')
return s:SID_VALUE
endif
let s:SID_VALUE = matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
return s:SID_VALUE
endfunction
I have a function that filters lines based on the current range. The range typically corresponds to a visual mode selection but could be a manual one. To create such a filter function I need a viml
function such as below,
function! MyFilter() range
endfunction
Is there a riml
equivalent of the same?
I'm trying to upgrade to 0.3.7 from 0.3.5 in Portkey. The entire test suite runs fine, but the main include file portkey.riml
has an include that riml 0.3.7 is failing to pickup. 0.3.5 works correctly. The error is,
Riml::ClassNotFound
location: <unknown>
message: class "s:PythonFileWriter" not found.
You can replicate this by running, rake dist
on the develop branch of portkey. The class in question is in the lib/logger
directory. I've checked that the path
given to riml
with the -I
flag does contain lib/logger
.
Any ideas?
@luke-gru This one is a bit tricky!
Consider the following code,
def get_foo(arg)
if arg == 'a'
return 'A'
elseif arg == 'b'
return 'B'
else
return 'Unknown'
end
end
This compiled to the following viml
.
function! s:get_foo(arg)
if a:arg ==# 'a'
return 'A'
elseif s:arg ==# 'b'
return 'B'
else
return 'Unknown'
endif
endfunction
Here arg is an argument, but in the elseif
condition it becomes scriptlocal, s:arg
, it should be a:arg
. Further this also happens with local variables.
def get_bar()
my_var = 'foo'
if my_var == 'a'
return 'A'
elseif my_var == 'b'
return 'B'
else
return 'Unknown'
end
end
Compiles to,
function! s:get_bar()
let my_var = 'foo'
if my_var ==# 'a'
return 'A'
elseif s:my_var ==# 'b'
return 'B'
else
return 'Unknown'
endif
endfunction
Here s:my_var
should be just my_var
.
Both these functions result in undefined variable
errors when the functions are called. This bug only appears in the elseif
, just if-else
is fine.
My current workaround is to explicitly scope all variables used inside elseif with their scope. Eg:- l:my_var
and a:args
@luke-gru Is it possible to add newlines after function blocks in the generated vim files. I am finding I needed drop into the generated files occasionally. It would be lot easier to read with the newlines.
Thanks.
self.foo(1, *args)
translates to
call call('foo', [1] + a:000, self)
which fails with "unknown function 'foo'" (args being the calling method's varargs), while it should resemble something like this:
call call(self.foo, [1] + a:000, self)
I am trying to override/augment a parent class's method. I'm able to call super(...)
itself, but unable to assign that result to a variable. Which prevents augmenting the returned value.
Consider this scenario. RedBox
extends Box
, like so.
class Box
defm get_color(a, b)
return 'white'
end
end
class RedBox < Box
defm get_color(a, b, c)
color = super(a, b)
return color . ' red'
end
end
red_box = new RedBox()
echo red_box.get_color(1, 2, 3)
This code doesn't compile, instead gives the following error.
compiler.rb:27:in `const_get': uninitialized constant Riml::Compiler::SuperNodeVisitor (NameError) ...
If I remove the variable assignment to super
. I get the following code for the get_color
function.
function! <SID>s:RedBox_get_color(a, b, c) dict
call self.Box_get_color(a:a, a:b)
endfunction
This looks almost right. An extra return statement should do the trick. I hacked this ugly workaround that works for now.
defm get_color(a, b, c)
color = call('<SID>s:Box_get_color', [a, b], self)
return color . ' red'
end
something like:
riml_import g:VimTestCase
for importing 1 class and also supports multiple arguments:
riml_import g:VimTestCase, g:VimTestHelper
@luke-gru I've narrowed down a weird issue I was seeing, while refactoring code. It was occurring mostly when doing things like adding new conditions to if
, statements, when extracting code to a method. I think this is related to how riml handles whitespace at the end of lines.
Consider this code,
def hello()
end
This looks like valid riml
code but it has an extra whitespace at the end of the line after the hello()
function. Without the whitespace the code compiles fine. But with the whitespace you get the following error,
grammar.y:557:in `rescue in parse': on line 1: (Riml::ParseError)
parse error on value "end" (END)
"end" is a keyword, and cannot be used as a variable name
from grammar.y:547:in `parse'
... stacktrace
On further exploration I found this happens for nearly all statements. If you happen to accidentally add whitespace to code that was working earlier, it stops, with an error message very similar to the above.
Riml
is awesome!!! I don't understand why this isn't more well known? I stumbled upon it by pure accident, looking at some completely unrelated stuff. Maybe you should have a github website?
I think this is going to bring about a renaissance in vim plugin development!
Enough gushing, to my question. :)
How do I specify an output path to the compiled vim file. Something like,
riml -c foo.riml -o foo.vim
Currently it seems to output everything into the current working directory. I am working on an RSpec
clone for Riml
. I have a bunch of *.riml
files that are tests organized in sub directories that I want to compile into a different directory, or into the same directory. ie:- I want preserve their folder structure.
Thanks again, for this awesome project!
When I compiled below riml code,
for i in range(1, 3)
echo i
end
I got below Vim script code.
for i in range(1, 3)
echo i
endfor
There is a problem in this Vim script code. i
for items in for
statement is global scope. It pollutes global variables if for
is used in global scope.
let g:i = 42
for i in range(1, 3)
echo i
endfor
" oops
echo g:i
However, local variable cannot be used in global scope. So, at least, script local variable should be used like below if for
is used in global scope.
let g:i = 42
for s:i in range(1, 3)
echo s:i
endfor
" yey!
echo g:i
Just a few negative-lookbehind Regexps in the lexer are keeping riml from being 1.8.7 compatible. Also need to change a few require_relatives.
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>'
When using this assigment syntax:
foo = bar != 0
riml creates
if bar !=# 0
let foo = 1
else
let foo = 0
endif
First of all, let foo = bar != 0
is valid VimL and seems to work fine.
The real problem I encountered is that in a (defm) method definition, the complete rest of the method body is being ignored…the next line becomes an "endfunction".
Putting parentheses around the bar != 0
fixes things (though by preventing the expansion to the above).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.