riml 0.2.5 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,15 +1,14 @@
1
1
  [![Build Status](https://secure.travis-ci.org/luke-gru/riml.png?branch=master)](https://travis-ci.org/luke-gru/riml)
2
2
 
3
- Riml, a relaxed version of Vimscript
3
+ Riml, a relaxed Vimscript
4
4
  ====================================
5
5
 
6
- Riml aims to be a superset of VimL that includes some nice features that I
7
- enjoy in other scripting languages: classes, string interpolation,
6
+ Riml is a subset of Vimscript with some added features, and it compiles to
7
+ plain Vimscript. Some of the added features include classes, string interpolation,
8
8
  heredocs, default case-sensitive string comparison, default parameters
9
- in functions, and other things programmers tend to take for granted. Also, Riml takes
10
- some liberties and provides some syntactic sugar for lots of VimL constructs.
11
- To see how Riml constructs are compiled to VimL, just take a look at this README.
12
- The left side is Riml, and the right side is the VimL after compilation.
9
+ in functions, and other things programmers tend to take for granted.
10
+ To see how Riml is compiled to VimL, just take a look at this README. The left
11
+ side is Riml, and the right side is the VimL after compilation.
13
12
 
14
13
  Variables
15
14
  ---------
@@ -51,7 +50,7 @@ much easier to just come up with unique variable names across a scope.
51
50
 
52
51
  ###Checking for existence
53
52
 
54
- unless s:callcount? if !exists("s:callcount")
53
+ unless callcount? if !exists("s:callcount")
55
54
  callcount = 0 let s:callcount = 0
56
55
  end endif
57
56
  callcount += 1 let s:callcount += 1
@@ -64,7 +63,7 @@ In Riml, you can choose to end any block with 'end', or with whatever you used
64
63
  to do in Vimscript ('endif', 'endfunction', etc...). Also, 'if' and 'unless' can
65
64
  now be used as statement modifiers:
66
65
 
67
- callcount = 0 unless s:callcount?
66
+ callcount = 0 unless callcount?
68
67
  callcount += 1
69
68
  echo "called #{callcount} times"
70
69
 
@@ -92,9 +91,9 @@ Heredocs
92
91
  Hooray!
93
92
  EOS
94
93
 
95
- Riml heredocs must have the ending pattern start at the beginning
96
- of the line. Interpolating expressions is allowed in heredocs. Compiled
97
- heredocs always end with a newline.
94
+ Riml heredocs must have the ending pattern ('EOS' in this case) start at the
95
+ beginning of the line. Interpolating expressions is allowed in heredocs.
96
+ Compiled heredocs always end with a newline.
98
97
 
99
98
  Functions
100
99
  ---------
@@ -107,10 +106,10 @@ Functions
107
106
  When defining a function with no parameters, the parens after the function name are optional.
108
107
 
109
108
  Functions are by default prepended by 's:' unless explicitly prepended with a
110
- different scope modifier. Of course, you can use the old form ('function! Name()') for defining
111
- functions if you want, as Riml aims to be a superset of VimL. There are a few exceptions
112
- where Riml and VimL aren't compatible, and these differences are explained in
113
- the section 'Incompatibilities with VimL'.
109
+ different scope modifier. Of course, you can use the old form ('function! Name()')
110
+ for defining functions if you want, as Riml aims to be as compatible as possible
111
+ with VimL. There are a few exceptions where Riml and VimL aren't compatible, and
112
+ these differences are explained in the section 'Incompatibilities with VimL'.
114
113
 
115
114
  ###Default Arguments
116
115
 
@@ -163,8 +162,8 @@ inside a class, use 'def'. To create an instance of this class, simply:
163
162
  obj = new MyClass('someData', 'someOtherData')
164
163
 
165
164
  In this basic example of a class, we see a \*splat variable. This is just a
166
- convenient way to refer to 'a:000' in a function. Splat variables are optional
167
- parameters and get compiled to '...'.
165
+ convenient way to refer to 'a:000' in the body of a function. Splat variables
166
+ are optional parameters and get compiled to '...'.
168
167
 
169
168
  ###Class Inheritance
170
169
 
@@ -196,10 +195,10 @@ parameters and get compiled to '...'.
196
195
 
197
196
  Classes that inherit must have their superclass defined before inheritance takes place. In
198
197
  this example, 'Translation' is defined first, which is legal. Since 'Translation'
199
- has an initialize function and 'FrenchToEnglishTranslation' (referred to now as FET)
200
- doesn't, FET instances use the initialize function from 'Translation', and new
201
- instances must be provided with an 'input' argument on creation. Basically, if
202
- a class doesn't provide an initialize function, it uses its superclass's.
198
+ has an initialize function and 'FrenchToEnglishTranslation' doesn't, 'FrenchToEnglishTranslation'
199
+ instances use the initialize function from 'Translation', and new instances must
200
+ be provided with an 'input' argument on creation. Basically, if a class doesn't
201
+ provide an initialize function, it uses its superclass's.
203
202
 
204
203
  If you look at the last line of Riml in the previous example, you'll see that
205
204
  it doesn't use Vimscript's builtin 'call' function for calling the 'translate'
@@ -253,7 +252,7 @@ directory:
253
252
 
254
253
  $ riml -c example.riml
255
254
 
256
- This will create a new VimL file named 'example.vim'.
255
+ This will create a new VimL file named 'example.vim' in the current directory.
257
256
 
258
257
  ###riml\_source
259
258
 
@@ -275,11 +274,22 @@ In 'awesome.riml', that line will be compiled to:
275
274
  This process is recursive, meaning that if 'my\_framework.riml' riml\_source's other
276
275
  files, then those files will be compiled as well.
277
276
 
278
- In 'awesome.riml', all the classes that were available by compiling 'my\_framework.riml'
279
- are now available to it, so we can now subclass classes that were defined either
280
- in 'my\_framework.riml' itself, or any files that it riml\_source'd either directly
281
- or indirecty.
277
+ The previous example would only work if 'my\_framework.riml' were in the
278
+ current working directory where the compilation command 'riml -c' was issued.
279
+ In order to tell the compiler where to look for files that are being
280
+ riml\_source'd, you can provide an environment variable or a command-line
281
+ option of colon-separated paths. For example:
282
282
 
283
+ riml -c awesome.riml -S 'first_dir:second_dir'
284
+
285
+ With this command, the compiler will look for files that are riml\_source'd
286
+ first in ./first\_dir, then in ./second\_dir if not found in first\_dir.
287
+ The same can be achieved by:
288
+
289
+ riml -c awesome.riml RIML_SOURCE_PATH='first_dir:second_dir'
290
+
291
+ Paths can either be relative or absolute. The sourced files that are compiled
292
+ will end up in the same directory in which they were found.
283
293
 
284
294
  ###riml\_include
285
295
 
@@ -296,15 +306,28 @@ Much like riml\_sourcing, the process is recursive. If 'my\_lib.riml' includes f
296
306
  are also compiled and will be part of the inclusion. Note that riml\_include does not create a
297
307
  new file like riml\_source does.
298
308
 
309
+ Like riml\_source, riml\_include looks in a set of ordered paths to find the
310
+ files to include, with the default being the working directory in which the
311
+ compilation command was issued. Here are some examples of commands that set
312
+ the include path:
313
+
314
+ riml -c 'main.riml' -I 'lib:helpers:debug'
315
+
316
+ riml -c 'plugin_name.riml' RIML_INCLUDE_PATH='lib:modules'
317
+
318
+ Since riml\_include acts as a sort of preprocessor, it *cannot* be issued
319
+ inside of a conditional, function, or anything dynamic. It must be at the
320
+ top-level (non-nested).
321
+
299
322
  Incompatibilities with VimL
300
323
  ---------------------------
301
324
 
302
- Riml aims to be a superset of VimL, therefore any legal VimL should be legal
303
- Riml as well. Unfortunately, this is not 100% possible as Vim is an old and
304
- cryptic beast, and trying to create grammar for every possible Vim construct
305
- would be a nightmare. In practice, however, when I've transformed plain old vim plugins
306
- to be Riml-compatible, only a couple of ':' needed to be placed in strategic locations
307
- for it to be valid Riml. This is explained below.
325
+ Riml aims to be as compatible with VimL as possible, therefore any legal VimL
326
+ should be legal Riml as well. Unfortunately, this is not 100% possible as Vim
327
+ is an old and cryptic beast, and trying to create grammar for every possible VimL
328
+ construct would be a nightmare. In practice, however, when I've transformed plain
329
+ old VimL plugins to be Riml-compatible, only a couple of ':' needed to be placed
330
+ in strategic locations for it to be valid Riml. This is explained below.
308
331
 
309
332
  ###Ex-literals
310
333
 
@@ -336,7 +359,7 @@ needs to be an ex-literal in Riml.
336
359
 
337
360
  Note that, like 'echo' which isn't a builtin function (:h functions) but is still legal
338
361
  Riml, 'execute' is also allowed as it takes a string. This is extremely useful, as we can
339
- now use execute with a string that allows interpolation.
362
+ now use execute with a string that allows interpolation!
340
363
 
341
364
  Imagine having to write a grammar rule for the following:
342
365
 
data/Rakefile CHANGED
@@ -11,7 +11,16 @@ end
11
11
 
12
12
  desc 'recreate lib/parser.rb from lib/grammar.y using racc'
13
13
  task :parser do
14
+ sh_in_libdir 'racc -o parser.rb grammar.y'
15
+ end
16
+
17
+ desc 'recreate lib/parser.rb with debug info from lib/grammar.y using racc'
18
+ task :debug_parser do
19
+ sh_in_libdir 'racc --verbose -o parser.rb grammar.y'
20
+ end
21
+
22
+ def sh_in_libdir(cmd)
14
23
  Dir.chdir(File.expand_path("../lib", __FILE__)) do
15
- sh 'racc -o parser.rb grammar.y'
24
+ sh cmd
16
25
  end
17
26
  end
data/bin/riml CHANGED
@@ -84,7 +84,7 @@ module Riml
84
84
  if File.exists?(expanded)
85
85
  list << fname
86
86
  else
87
- raise UserArgumentError, "Couldn't find file #{fname.inspect}."
87
+ abort "Couldn't find file #{fname.inspect}."
88
88
  end
89
89
  end
90
90
  end
@@ -31,7 +31,8 @@ module Riml
31
31
  ClassDefinitionToFunctions.new(ast, classes),
32
32
  ObjectInstantiationToCall.new(ast, classes),
33
33
  CallToExplicitCall.new(ast, classes),
34
- DefaultParamToIfNode.new(ast, classes)
34
+ DefaultParamToIfNode.new(ast, classes),
35
+ DeserializeVarAssignment.new(ast, classes)
35
36
  ]
36
37
  rewriters.each do |rewriter|
37
38
  rewriter.rewrite_on_match
@@ -51,7 +52,7 @@ module Riml
51
52
  end
52
53
 
53
54
  def rewrite_on_match(node = ast)
54
- Walker.walk_node(node, method(:do_rewrite_on_match), lambda {|_| repeatable?})
55
+ Walker.walk_node(node, method(:do_rewrite_on_match), lambda { |_| recursive? })
55
56
  end
56
57
 
57
58
  def do_rewrite_on_match(node)
@@ -88,7 +89,7 @@ module Riml
88
89
  self.ast = old_ast
89
90
  end
90
91
 
91
- def repeatable?
92
+ def recursive?
92
93
  true
93
94
  end
94
95
 
@@ -236,7 +237,7 @@ module Riml
236
237
  classes.superclass(ast.name).constructor.parameters
237
238
  end
238
239
 
239
- def repeatable?
240
+ def recursive?
240
241
  false
241
242
  end
242
243
  end
@@ -287,7 +288,7 @@ module Riml
287
288
  end
288
289
  end
289
290
 
290
- def repeatable?
291
+ def recursive?
291
292
  false
292
293
  end
293
294
  end
@@ -421,5 +422,30 @@ module Riml
421
422
  end
422
423
  end
423
424
 
425
+ class DeserializeVarAssignment < AST_Rewriter
426
+ def match?(node)
427
+ AssignNode === node && AssignNode === node.rhs && node.operator == '='
428
+ end
429
+
430
+ def replace(node)
431
+ orig_assign = node.dup
432
+ assigns = []
433
+ while assign_node = (node.respond_to?(:rhs) && node.rhs)
434
+ assigns.unshift([node.lhs, node.rhs])
435
+ node = assign_node
436
+ end
437
+ assigns = assigns[0..0].concat(assigns[1..-1].map! { |(lhs, rhs)| [lhs, rhs.lhs] })
438
+
439
+ assigns.map! do |(lhs, rhs)|
440
+ AssignNode.new('=', lhs, rhs)
441
+ end
442
+
443
+ new_assigns = Nodes.new(assigns)
444
+ new_assigns.parent = orig_assign.parent
445
+ orig_assign.replace_with(new_assigns)
446
+ establish_parents(new_assigns)
447
+ end
448
+ end
449
+
424
450
  end
425
451
  end
@@ -8,16 +8,15 @@ module Riml
8
8
  # Base abstract visitor
9
9
  class Visitor
10
10
  attr_writer :propagate_up_tree
11
- attr_reader :value
12
11
 
13
12
  def initialize(options={})
14
13
  @propagate_up_tree = options[:propagate_up_tree]
15
14
  end
16
15
 
17
16
  def visit(node)
18
- @value = compile(node)
19
- @value << "\n" if node.force_newline and @value[-1] != "\n"
20
- propagate_up_tree(node, @value)
17
+ output = compile(node)
18
+ output << "\n" if node.force_newline and output[-1] != "\n"
19
+ propagate_up_tree(node, output)
21
20
  end
22
21
 
23
22
  def propagate_up_tree(node, output)
@@ -41,7 +40,7 @@ module Riml
41
40
  node.body.accept(NodesVisitor.new(:propagate_up_tree => false))
42
41
 
43
42
  node.body.compiled_output.each_line do |line|
44
- outdent = line =~ /\A(\s*)(else\s*|elseif .*)$/
43
+ outdent = line =~ /\A(\s*)(else\s*|elseif .+)$/
45
44
  if outdent && node.non_nested?
46
45
  node.compiled_output << node.outdent + line
47
46
  else
@@ -265,22 +264,15 @@ module Riml
265
264
 
266
265
  class AssignNodeVisitor < ScopedVisitor
267
266
  def compile(node)
268
- first_shadow = nil
269
-
267
+ lhs = visit_lhs(node)
268
+ rhs = visit_rhs(node)
270
269
  if GetVariableNode === node.lhs && node.scope && (func = node.scope.function)
271
270
  if func.argument_variable_names.include?(node.lhs.full_name)
272
271
  if !func.shadowed_argument_variable_names.include?(node.lhs.full_name)
273
- first_shadow = true
272
+ func.shadowed_argument_variable_names << node.lhs.full_name
274
273
  end
275
274
  end
276
275
  end
277
-
278
- lhs = visit_lhs(node)
279
- rhs = visit_rhs(node)
280
- if first_shadow
281
- func.shadowed_argument_variable_names << node.lhs.full_name
282
- end
283
-
284
276
  node.compiled_output = "#{lhs}#{rhs}"
285
277
  node.compiled_output = "unlet! #{node.lhs.compiled_output}" if node.rhs.compiled_output == 'nil'
286
278
  node.force_newline = true
@@ -298,6 +290,16 @@ module Riml
298
290
  end
299
291
  end
300
292
 
293
+ class MultiAssignNodeVisitor < Visitor
294
+ def compile(node)
295
+ node.assigns.each do |assign|
296
+ assign.force_newline = true
297
+ assign.accept(visitor_for_node(assign))
298
+ end
299
+ node.compiled_output
300
+ end
301
+ end
302
+
301
303
  # scope_modifier, name
302
304
  class GetVariableNodeVisitor < ScopedVisitor
303
305
  def compile(node)
@@ -530,7 +532,8 @@ module Riml
530
532
  node.descendant_of_operator_node? ||
531
533
  node.descendant_of_wrap_in_parens_node? ||
532
534
  node.descendant_of_sublist_node? ||
533
- node.descendant_of_dict_get_dot_node?
535
+ node.descendant_of_dict_get_dot_node? ||
536
+ node.descendant_of_dictionary_node?
534
537
  node.force_newline = true
535
538
  end
536
539
  end
@@ -37,60 +37,60 @@ preclow
37
37
  rule
38
38
 
39
39
  Root:
40
- /* nothing */ { result = Riml::Nodes.new([]) }
41
- | Expressions { result = val[0] }
40
+ /* nothing */ { result = Riml::Nodes.new([]) }
41
+ | Statements { result = val[0] }
42
42
  ;
43
43
 
44
44
  # any list of expressions
45
- Expressions:
46
- AnyExpression { result = Riml::Nodes.new([ val[0] ]) }
47
- | Expressions Terminator AnyExpression { result = val[0] << val[2] }
48
- | Expressions Terminator { result = val[0] }
49
- | Terminator { result = Riml::Nodes.new([]) }
50
- | Terminator Expressions { result = Riml::Nodes.new(val[1]) }
45
+ Statements:
46
+ Statement { result = Riml::Nodes.new([ val[0] ]) }
47
+ | Statements Terminator Statement { result = val[0] << val[2] }
48
+ | Statements Terminator { result = val[0] }
49
+ | Terminator { result = Riml::Nodes.new([]) }
50
+ | Terminator Statements { result = Riml::Nodes.new(val[1]) }
51
51
  ;
52
52
 
53
53
  # All types of expressions in Riml
54
- AnyExpression:
54
+ Statement:
55
55
  ExplicitCall { result = val[0] }
56
56
  | Def { result = val[0] }
57
57
  | Return { result = val[0] }
58
58
  | UnletVariable { result = val[0] }
59
59
  | ExLiteral { result = val[0] }
60
- | If { result = val[0] }
61
- | Unless { result = val[0] }
62
60
  | For { result = val[0] }
63
61
  | While { result = val[0] }
64
62
  | Until { result = val[0] }
65
63
  | Try { result = val[0] }
66
64
  | ClassDefinition { result = val[0] }
67
- | Super { result = val[0] }
68
65
  | LoopKeyword { result = val[0] }
69
66
  | EndScript { result = val[0] }
70
- | ValueExpression { result = val[0] }
71
67
  | RimlCommand { result = val[0] }
68
+ | MultiAssign { result = val[0] }
69
+ | If { result = val[0] }
70
+ | Unless { result = val[0] }
71
+ | Expression { result = val[0] }
72
72
  ;
73
73
 
74
- # Expressions that evaluate to a value
75
- ValueExpression:
76
- ValueExpressionWithoutDictLiteral { result = val[0] }
74
+ Expression:
75
+ ExpressionWithoutDictLiteral { result = val[0] }
77
76
  | Dictionary { result = val[0] }
78
77
  | Dictionary DictGetWithDotLiteral { result = Riml::DictGetDotNode.new(val[0], val[1]) }
79
78
  | BinaryOperator { result = val[0] }
80
79
  | Ternary { result = val[0] }
81
- | '(' ValueExpression ')' { result = Riml::WrapInParensNode.new(val[1]) }
80
+ | Assign { result = val[0] }
81
+ | Super { result = val[0] }
82
+ | '(' Expression ')' { result = Riml::WrapInParensNode.new(val[1]) }
82
83
  ;
83
84
 
84
- ValueExpressionWithoutDictLiteral:
85
+ ExpressionWithoutDictLiteral:
85
86
  UnaryOperator { result = val[0] }
86
- | Assign { result = val[0] }
87
87
  | DictGet { result = val[0] }
88
88
  | ListOrDictGet { result = val[0] }
89
89
  | AllVariableRetrieval { result = val[0] }
90
90
  | LiteralWithoutDictLiteral { result = val[0] }
91
91
  | Call { result = val[0] }
92
92
  | ObjectInstantiation { result = val[0] }
93
- | '(' ValueExpressionWithoutDictLiteral ')' { result = Riml::WrapInParensNode.new(val[1]) }
93
+ | '(' ExpressionWithoutDictLiteral ')' { result = Riml::WrapInParensNode.new(val[1]) }
94
94
  ;
95
95
 
96
96
  # for inside curly-brace variable names
@@ -144,7 +144,7 @@ rule
144
144
  ;
145
145
 
146
146
  ListUnpack:
147
- '[' ListItems ';' ValueExpression ']' { result = Riml::ListUnpackNode.new(val[1] << val[3]) }
147
+ '[' ListItems ';' Expression ']' { result = Riml::ListUnpackNode.new(val[1] << val[3]) }
148
148
  ;
149
149
 
150
150
  ListLiteral:
@@ -154,8 +154,8 @@ rule
154
154
 
155
155
  ListItems:
156
156
  /* nothing */ { result = [] }
157
- | ValueExpression { result = [val[0]] }
158
- | ListItems ',' ValueExpression { result = val[0] << val[2] }
157
+ | Expression { result = [val[0]] }
158
+ | ListItems ',' Expression { result = val[0] << val[2] }
159
159
  ;
160
160
 
161
161
  Dictionary:
@@ -177,37 +177,41 @@ rule
177
177
 
178
178
  # [key, value]
179
179
  DictItem:
180
- ValueExpression ':' ValueExpression { result = [val[0], val[2]] }
180
+ Expression ':' Expression { result = [val[0], val[2]] }
181
181
  ;
182
182
 
183
183
  DictGet:
184
184
  AllVariableRetrieval DictGetWithDot { result = Riml::DictGetDotNode.new(val[0], val[1]) }
185
185
  | ListOrDictGet DictGetWithDot { result = Riml::DictGetDotNode.new(val[0], val[1]) }
186
186
  | Call DictGetWithDot { result = Riml::DictGetDotNode.new(val[0], val[1]) }
187
- | '(' ValueExpression ')' DictGetWithDot { result = Riml::DictGetDotNode.new(Riml::WrapInParensNode.new(val[1]), val[3]) }
187
+ | '(' Expression ')' DictGetWithDot { result = Riml::DictGetDotNode.new(Riml::WrapInParensNode.new(val[1]), val[3]) }
188
188
  ;
189
189
 
190
190
  ListOrDictGet:
191
- ValueExpressionWithoutDictLiteral ListOrDictGetWithBrackets { result = Riml::ListOrDictGetNode.new(val[0], val[1]) }
192
- | '(' ValueExpression ')' ListOrDictGetWithBrackets { result = Riml::ListOrDictGetNode.new(Riml::WrapInParensNode.new(val[1]), val[3]) }
191
+ ExpressionWithoutDictLiteral ListOrDictGetWithBrackets { result = Riml::ListOrDictGetNode.new(val[0], val[1]) }
192
+ | '(' Expression ')' ListOrDictGetWithBrackets { result = Riml::ListOrDictGetNode.new(Riml::WrapInParensNode.new(val[1]), val[3]) }
193
+ ;
194
+
195
+ ListOrDictGetAssign:
196
+ ExpressionWithoutDictLiteral ListOrDictGetWithBrackets { result = Riml::ListOrDictGetNode.new(val[0], val[1]) }
193
197
  ;
194
198
 
195
199
  ListOrDictGetWithBrackets:
196
- '[' ValueExpression ']' { result = [val[1]] }
197
- | '[' SubList ']' { result = [val[1]] }
198
- | ListOrDictGetWithBrackets '[' ValueExpression ']' { result = val[0] << val[2] }
199
- | ListOrDictGetWithBrackets '[' SubList ']' { result = val[0] << val[2] }
200
+ '[' Expression ']' { result = [val[1]] }
201
+ | '[' SubList ']' { result = [val[1]] }
202
+ | ListOrDictGetWithBrackets '[' Expression ']' { result = val[0] << val[2] }
203
+ | ListOrDictGetWithBrackets '[' SubList ']' { result = val[0] << val[2] }
200
204
  ;
201
205
 
202
206
  SubList:
203
- ValueExpression ':' ValueExpression { result = Riml::SublistNode.new([val[0], Riml::LiteralNode.new(' : '), val[2]]) }
204
- | ValueExpression ':' { result = Riml::SublistNode.new([val[0], Riml::LiteralNode.new(' :')]) }
205
- | ':' ValueExpression { result = Riml::SublistNode.new([Riml::LiteralNode.new(': '), val[1]]) }
206
- | ':' { result = Riml::SublistNode.new([Riml::LiteralNode.new(':')]) }
207
+ Expression ':' Expression { result = Riml::SublistNode.new([val[0], Riml::LiteralNode.new(' : '), val[2]]) }
208
+ | Expression ':' { result = Riml::SublistNode.new([val[0], Riml::LiteralNode.new(' :')]) }
209
+ | ':' Expression { result = Riml::SublistNode.new([Riml::LiteralNode.new(': '), val[1]]) }
210
+ | ':' { result = Riml::SublistNode.new([Riml::LiteralNode.new(':')]) }
207
211
  ;
208
212
 
209
213
  DictGetWithDot:
210
- DICT_VAL { result = [val[0]]}
214
+ DICT_VAL { result = [val[0]] }
211
215
  | DictGetWithDot DICT_VAL { result = val[0] << val[1] }
212
216
  ;
213
217
 
@@ -220,10 +224,15 @@ rule
220
224
  Scope DefCallIdentifier '(' ArgList ')' { result = Riml::CallNode.new(val[0], val[1], val[3]) }
221
225
  | DictGet '(' ArgList ')' { result = Riml::CallNode.new(nil, val[0], val[2]) }
222
226
  | BUILTIN_COMMAND '(' ArgList ')' { result = Riml::CallNode.new(nil, val[0], val[2]) }
223
- | BUILTIN_COMMAND ArgList { result = Riml::CallNode.new(nil, val[0], val[1]) }
227
+ | BUILTIN_COMMAND ArgListWithoutNothing { result = Riml::CallNode.new(nil, val[0], val[1]) }
228
+ | BUILTIN_COMMAND NEWLINE { result = Riml::CallNode.new(nil, val[0], []) }
224
229
  | CALL '(' ArgList ')' { result = Riml::ExplicitCallNode.new(nil, nil, val[2]) }
225
230
  ;
226
231
 
232
+ ObjectInstantiationCall:
233
+ Scope DefCallIdentifier '(' ArgList ')' { result = Riml::CallNode.new(val[0], val[1], val[3]) }
234
+ ;
235
+
227
236
  RimlCommand:
228
237
  RIML_COMMAND '(' ArgList ')' { result = Riml::RimlCommandNode.new(nil, val[0], val[2]) }
229
238
  | RIML_COMMAND ArgList { result = Riml::RimlCommandNode.new(nil, val[0], val[1]) }
@@ -241,64 +250,68 @@ rule
241
250
 
242
251
  ArgList:
243
252
  /* nothing */ { result = [] }
244
- | ValueExpression { result = val }
245
- | ArgList "," ValueExpression { result = val[0] << val[2] }
253
+ | ArgListWithoutNothing { result = val[0] }
254
+ ;
255
+
256
+ ArgListWithoutNothing:
257
+ Expression { result = val }
258
+ | ArgListWithoutNothing "," Expression { result = val[0] << val[2] }
246
259
  ;
247
260
 
248
261
  BinaryOperator:
249
- ValueExpression '||' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
250
- | ValueExpression '&&' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
262
+ Expression '||' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
263
+ | Expression '&&' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
251
264
 
252
- | ValueExpression '==' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
253
- | ValueExpression '==#' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
254
- | ValueExpression '==?' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
265
+ | Expression '==' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
266
+ | Expression '==#' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
267
+ | Expression '==?' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
255
268
 
256
269
  # added by riml
257
- | ValueExpression '===' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
270
+ | Expression '===' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
258
271
 
259
- | ValueExpression '!=' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
260
- | ValueExpression '!=#' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
261
- | ValueExpression '!=?' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
272
+ | Expression '!=' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
273
+ | Expression '!=#' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
274
+ | Expression '!=?' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
262
275
 
263
- | ValueExpression '=~' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
264
- | ValueExpression '=~#' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
265
- | ValueExpression '=~?' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
276
+ | Expression '=~' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
277
+ | Expression '=~#' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
278
+ | Expression '=~?' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
266
279
 
267
- | ValueExpression '!~' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
268
- | ValueExpression '!~#' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
269
- | ValueExpression '!~?' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
280
+ | Expression '!~' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
281
+ | Expression '!~#' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
282
+ | Expression '!~?' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
270
283
 
271
- | ValueExpression '>' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
272
- | ValueExpression '>#' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
273
- | ValueExpression '>?' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
284
+ | Expression '>' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
285
+ | Expression '>#' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
286
+ | Expression '>?' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
274
287
 
275
- | ValueExpression '>=' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
276
- | ValueExpression '>=#' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
277
- | ValueExpression '>=?' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
288
+ | Expression '>=' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
289
+ | Expression '>=#' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
290
+ | Expression '>=?' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
278
291
 
279
- | ValueExpression '<' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
280
- | ValueExpression '<#' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
281
- | ValueExpression '<?' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
292
+ | Expression '<' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
293
+ | Expression '<#' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
294
+ | Expression '<?' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
282
295
 
283
- | ValueExpression '<=' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
284
- | ValueExpression '<=#' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
285
- | ValueExpression '<=?' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
296
+ | Expression '<=' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
297
+ | Expression '<=#' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
298
+ | Expression '<=?' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
286
299
 
287
- | ValueExpression '+' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
288
- | ValueExpression '-' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
289
- | ValueExpression '*' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
290
- | ValueExpression '/' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
291
- | ValueExpression '.' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
292
- | ValueExpression '%' ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
300
+ | Expression '+' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
301
+ | Expression '-' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
302
+ | Expression '*' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
303
+ | Expression '/' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
304
+ | Expression '.' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
305
+ | Expression '%' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
293
306
 
294
- | ValueExpression IS ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
295
- | ValueExpression ISNOT ValueExpression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
307
+ | Expression IS Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
308
+ | Expression ISNOT Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
296
309
  ;
297
310
 
298
311
  UnaryOperator:
299
- '!' ValueExpression { result = Riml::UnaryOperatorNode.new(val[0], val[1]) }
300
- | '+' ValueExpression { result = Riml::UnaryOperatorNode.new(val[0], val[1]) }
301
- | '-' ValueExpression { result = Riml::UnaryOperatorNode.new(val[0], val[1]) }
312
+ '!' Expression { result = Riml::UnaryOperatorNode.new(val[0], [val[1]]) }
313
+ | '+' Expression { result = Riml::UnaryOperatorNode.new(val[0], [val[1]]) }
314
+ | '-' Expression { result = Riml::UnaryOperatorNode.new(val[0], [val[1]]) }
302
315
  ;
303
316
 
304
317
  # ['=', LHS, RHS]
@@ -307,12 +320,17 @@ rule
307
320
  | AssignExpression { result = Riml::AssignNode.new(val[0][0], val[0][1], val[0][2]) }
308
321
  ;
309
322
 
323
+ MultiAssign:
324
+ Assign ',' Assign { result = Riml::MultiAssignNode.new([val[0], val[2]]) }
325
+ | MultiAssign ',' Assign { val[0].assigns << val[2]; result = val[0] }
326
+ ;
327
+
310
328
  # ['=', AssignLHS, Expression]
311
329
  AssignExpression:
312
- AssignLHS '=' ValueExpression { result = [val[1], val[0], val[2]] }
313
- | AssignLHS '+=' ValueExpression { result = [val[1], val[0], val[2]] }
314
- | AssignLHS '-=' ValueExpression { result = [val[1], val[0], val[2]] }
315
- | AssignLHS '.=' ValueExpression { result = [val[1], val[0], val[2]] }
330
+ AssignLHS '=' Expression { result = [val[1], val[0], val[2]] }
331
+ | AssignLHS '+=' Expression { result = [val[1], val[0], val[2]] }
332
+ | AssignLHS '-=' Expression { result = [val[1], val[0], val[2]] }
333
+ | AssignLHS '.=' Expression { result = [val[1], val[0], val[2]] }
316
334
  ;
317
335
 
318
336
  AssignLHS:
@@ -320,13 +338,13 @@ rule
320
338
  | List { result = val[0] }
321
339
  | ListUnpack { result = val[0] }
322
340
  | DictGet { result = val[0] }
323
- | ListOrDictGet { result = val[0] }
341
+ | ListOrDictGetAssign { result = val[0] }
324
342
  ;
325
343
 
326
344
  # retrieving the value of a variable
327
345
  VariableRetrieval:
328
- Scope IDENTIFIER { result = Riml::GetVariableNode.new(val[0], val[1]) }
329
- | SPECIAL_VAR_PREFIX IDENTIFIER { result = Riml::GetSpecialVariableNode.new(val[0], val[1]) }
346
+ Scope IDENTIFIER { result = Riml::GetVariableNode.new(val[0], val[1]) }
347
+ | SPECIAL_VAR_PREFIX IDENTIFIER { result = Riml::GetSpecialVariableNode.new(val[0], val[1]) }
330
348
  | ScopeModifierLiteral ListOrDictGetWithBrackets { result = Riml::GetVariableByScopeAndDictNameNode.new(val[0], val[1]) }
331
349
  ;
332
350
 
@@ -391,12 +409,18 @@ rule
391
409
  ;
392
410
 
393
411
  DefaultParam:
394
- IDENTIFIER '=' ValueExpression { result = Riml::DefaultParamNode.new(val[0], val[2]) }
412
+ IDENTIFIER '=' Expression { result = Riml::DefaultParamNode.new(val[0], val[2]) }
395
413
  ;
396
414
 
397
415
  Return:
398
- RETURN ValueExpression { result = Riml::ReturnNode.new(val[1]) }
399
- | RETURN { result = Riml::ReturnNode.new(nil) }
416
+ RETURN Returnable { result = Riml::ReturnNode.new(val[1]) }
417
+ | RETURN Returnable IF Expression { result = Riml::IfNode.new(val[3], Nodes.new([ReturnNode.new(val[1])])) }
418
+ | RETURN Returnable UNLESS Expression { result = Riml::UnlessNode.new(val[3], Nodes.new([ReturnNode.new(val[1])])) }
419
+ ;
420
+
421
+ Returnable:
422
+ /* nothing */ { result = nil }
423
+ | Expression { result = val[0] }
400
424
  ;
401
425
 
402
426
  EndScript:
@@ -405,23 +429,23 @@ rule
405
429
 
406
430
  # [expression, expressions]
407
431
  If:
408
- IF ValueExpression IfBlock END { result = Riml::IfNode.new(val[1], val[2]) }
409
- | IF ValueExpression THEN ValueExpression END { result = Riml::IfNode.new(val[1], Riml::Nodes.new([val[3]])) }
410
- | AnyExpression IF ValueExpression { result = Riml::IfNode.new(val[2], Riml::Nodes.new([val[0]])) }
432
+ IF Expression IfBlock END { result = Riml::IfNode.new(val[1], val[2]) }
433
+ | IF Expression THEN Expression END { result = Riml::IfNode.new(val[1], Riml::Nodes.new([val[3]])) }
434
+ | Expression IF Expression { result = Riml::IfNode.new(val[2], Riml::Nodes.new([val[0]])) }
411
435
  ;
412
436
 
413
437
  Unless:
414
- UNLESS ValueExpression IfBlock END { result = Riml::UnlessNode.new(val[1], val[2]) }
415
- | UNLESS ValueExpression THEN ValueExpression END { result = Riml::UnlessNode.new(val[1], Riml::Nodes.new([val[3]])) }
416
- | ValueExpression UNLESS ValueExpression { result = Riml::UnlessNode.new(val[2], Riml::Nodes.new([val[0]])) }
438
+ UNLESS Expression IfBlock END { result = Riml::UnlessNode.new(val[1], val[2]) }
439
+ | UNLESS Expression THEN Expression END { result = Riml::UnlessNode.new(val[1], Riml::Nodes.new([val[3]])) }
440
+ | Expression UNLESS Expression { result = Riml::UnlessNode.new(val[2], Riml::Nodes.new([val[0]])) }
417
441
  ;
418
442
 
419
443
  Ternary:
420
- ValueExpression '?' ValueExpression ':' ValueExpression { result = Riml::TernaryOperatorNode.new([val[0], val[2], val[4]]) }
444
+ Expression '?' Expression ':' Expression { result = Riml::TernaryOperatorNode.new([val[0], val[2], val[4]]) }
421
445
  ;
422
446
 
423
447
  While:
424
- WHILE ValueExpression Block END { result = Riml::WhileNode.new(val[1], val[2]) }
448
+ WHILE Expression Block END { result = Riml::WhileNode.new(val[1], val[2]) }
425
449
  ;
426
450
 
427
451
  LoopKeyword:
@@ -430,13 +454,13 @@ rule
430
454
  ;
431
455
 
432
456
  Until:
433
- UNTIL ValueExpression Block END { result = Riml::UntilNode.new(val[1], val[2]) }
457
+ UNTIL Expression Block END { result = Riml::UntilNode.new(val[1], val[2]) }
434
458
  ;
435
459
 
436
460
  For:
437
- FOR IDENTIFIER IN ValueExpression Block END { result = Riml::ForNode.new(val[1], val[3], val[4]) }
438
- | FOR List IN ValueExpression Block END { result = Riml::ForNode.new(val[1], val[3], val[4]) }
439
- | FOR ListUnpack IN ValueExpression Block END { result = Riml::ForNode.new(val[1], val[3], val[4]) }
461
+ FOR IDENTIFIER IN Expression Block END { result = Riml::ForNode.new(val[1], val[3], val[4]) }
462
+ | FOR List IN Expression Block END { result = Riml::ForNode.new(val[1], val[3], val[4]) }
463
+ | FOR ListUnpack IN Expression Block END { result = Riml::ForNode.new(val[1], val[3], val[4]) }
440
464
  ;
441
465
 
442
466
  Try:
@@ -457,24 +481,24 @@ rule
457
481
  # expressions list could contain an ElseNode, which contains expressions
458
482
  # itself
459
483
  Block:
460
- NEWLINE Expressions { result = val[1] }
461
- | NEWLINE { result = Riml::Nodes.new([]) }
484
+ NEWLINE Statements { result = val[1] }
485
+ | NEWLINE { result = Riml::Nodes.new([]) }
462
486
  ;
463
487
 
464
488
  IfBlock:
465
- Block { result = val[0] }
466
- | NEWLINE Expressions ElseBlock { result = val[1] << val[2] }
467
- | NEWLINE Expressions ElseifBlock { result = val[1] << val[2] }
468
- | NEWLINE Expressions ElseifBlock ElseBlock { result = val[1] << val[2] << val[3] }
489
+ Block { result = val[0] }
490
+ | NEWLINE Statements ElseBlock { result = val[1] << val[2] }
491
+ | NEWLINE Statements ElseifBlock { result = val[1] << val[2] }
492
+ | NEWLINE Statements ElseifBlock ElseBlock { result = val[1] << val[2] << val[3] }
469
493
  ;
470
494
 
471
495
  ElseBlock:
472
- ELSE NEWLINE Expressions { result = Riml::ElseNode.new(val[2]) }
496
+ ELSE NEWLINE Statements { result = Riml::ElseNode.new(val[2]) }
473
497
  ;
474
498
 
475
499
  ElseifBlock:
476
- ELSEIF ValueExpression NEWLINE Expressions { result = Riml::Nodes.new([Riml::ElseifNode.new(val[1], val[3])]) }
477
- | ElseifBlock ELSEIF ValueExpression NEWLINE Expressions { result = val[0] << Riml::ElseifNode.new(val[2], val[4]) }
500
+ ELSEIF Expression NEWLINE Statements { result = Riml::Nodes.new([Riml::ElseifNode.new(val[1], val[3])]) }
501
+ | ElseifBlock ELSEIF Expression NEWLINE Statements { result = val[0] << Riml::ElseifNode.new(val[2], val[4]) }
478
502
  ;
479
503
 
480
504
  ClassDefinition:
@@ -483,7 +507,7 @@ rule
483
507
  ;
484
508
 
485
509
  ObjectInstantiation:
486
- NEW Call { result = Riml::ObjectInstantiationNode.new(val[1]) }
510
+ NEW ObjectInstantiationCall { result = Riml::ObjectInstantiationNode.new(val[1]) }
487
511
  ;
488
512
 
489
513
  Super:
@@ -518,7 +542,7 @@ end
518
542
  ast = do_parse
519
543
  rescue Racc::ParseError => e
520
544
  raise unless @lexer
521
- raise Riml::ParseError, "on line #{@lexer.lineno}: #{e.message}"
545
+ raise Riml::ParseError, "on line #{@lexer.lineno}: #{e.message}"
522
546
  end
523
547
 
524
548
  @ast_rewriter ||= ast_rewriter