riml 0.2.5 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +57 -34
- data/Rakefile +10 -1
- data/bin/riml +1 -1
- data/lib/ast_rewriter.rb +31 -5
- data/lib/compiler.rb +19 -16
- data/lib/grammar.y +134 -110
- data/lib/lexer.rb +7 -5
- data/lib/nodes.rb +20 -2
- data/lib/parser.output +13950 -0
- data/lib/parser.rb +1309 -1185
- data/lib/riml.rb +23 -9
- data/version.rb +2 -2
- metadata +8 -6
data/README.md
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
[](https://travis-ci.org/luke-gru/riml)
|
2
2
|
|
3
|
-
Riml, a relaxed
|
3
|
+
Riml, a relaxed Vimscript
|
4
4
|
====================================
|
5
5
|
|
6
|
-
Riml
|
7
|
-
|
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.
|
10
|
-
|
11
|
-
|
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
|
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
|
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
|
96
|
-
of the line. Interpolating expressions is allowed in heredocs.
|
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()')
|
111
|
-
functions if you want, as Riml aims to be
|
112
|
-
where Riml and VimL aren't compatible, and
|
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
|
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'
|
200
|
-
|
201
|
-
|
202
|
-
|
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
|
-
|
279
|
-
|
280
|
-
|
281
|
-
or
|
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
|
303
|
-
Riml as well. Unfortunately, this is not 100% possible as Vim
|
304
|
-
cryptic beast, and trying to create grammar for every possible
|
305
|
-
would be a nightmare. In practice, however, when I've transformed plain
|
306
|
-
to be Riml-compatible, only a couple of ':' needed to be placed
|
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
|
24
|
+
sh cmd
|
16
25
|
end
|
17
26
|
end
|
data/bin/riml
CHANGED
data/lib/ast_rewriter.rb
CHANGED
@@ -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 {|_|
|
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
|
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
|
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
|
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
|
data/lib/compiler.rb
CHANGED
@@ -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
|
-
|
19
|
-
|
20
|
-
propagate_up_tree(node,
|
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
|
-
|
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
|
-
|
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
|
data/lib/grammar.y
CHANGED
@@ -37,60 +37,60 @@ preclow
|
|
37
37
|
rule
|
38
38
|
|
39
39
|
Root:
|
40
|
-
/* nothing */
|
41
|
-
|
|
40
|
+
/* nothing */ { result = Riml::Nodes.new([]) }
|
41
|
+
| Statements { result = val[0] }
|
42
42
|
;
|
43
43
|
|
44
44
|
# any list of expressions
|
45
|
-
|
46
|
-
|
47
|
-
|
|
48
|
-
|
|
49
|
-
| Terminator
|
50
|
-
| Terminator
|
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
|
-
|
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
|
-
|
75
|
-
|
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
|
-
|
|
80
|
+
| Assign { result = val[0] }
|
81
|
+
| Super { result = val[0] }
|
82
|
+
| '(' Expression ')' { result = Riml::WrapInParensNode.new(val[1]) }
|
82
83
|
;
|
83
84
|
|
84
|
-
|
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
|
-
| '('
|
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 ';'
|
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
|
-
|
|
158
|
-
| ListItems ','
|
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
|
-
|
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
|
-
| '('
|
187
|
+
| '(' Expression ')' DictGetWithDot { result = Riml::DictGetDotNode.new(Riml::WrapInParensNode.new(val[1]), val[3]) }
|
188
188
|
;
|
189
189
|
|
190
190
|
ListOrDictGet:
|
191
|
-
|
192
|
-
| '('
|
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
|
-
'['
|
197
|
-
| '[' SubList ']'
|
198
|
-
| ListOrDictGetWithBrackets '['
|
199
|
-
| ListOrDictGetWithBrackets '[' SubList ']'
|
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
|
-
|
204
|
-
|
|
205
|
-
| ':'
|
206
|
-
| ':'
|
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
|
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
|
-
|
|
245
|
-
|
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
|
-
|
250
|
-
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
-
|
|
270
|
+
| Expression '===' Expression { result = Riml::BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
258
271
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
295
|
-
|
|
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
|
-
'!'
|
300
|
-
| '+'
|
301
|
-
| '-'
|
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 '='
|
313
|
-
| AssignLHS '+='
|
314
|
-
| AssignLHS '-='
|
315
|
-
| AssignLHS '.='
|
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
|
-
|
|
341
|
+
| ListOrDictGetAssign { result = val[0] }
|
324
342
|
;
|
325
343
|
|
326
344
|
# retrieving the value of a variable
|
327
345
|
VariableRetrieval:
|
328
|
-
Scope IDENTIFIER
|
329
|
-
| SPECIAL_VAR_PREFIX IDENTIFIER
|
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 '='
|
412
|
+
IDENTIFIER '=' Expression { result = Riml::DefaultParamNode.new(val[0], val[2]) }
|
395
413
|
;
|
396
414
|
|
397
415
|
Return:
|
398
|
-
RETURN
|
399
|
-
| RETURN
|
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
|
409
|
-
| IF
|
410
|
-
|
|
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
|
415
|
-
| UNLESS
|
416
|
-
|
|
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
|
-
|
444
|
+
Expression '?' Expression ':' Expression { result = Riml::TernaryOperatorNode.new([val[0], val[2], val[4]]) }
|
421
445
|
;
|
422
446
|
|
423
447
|
While:
|
424
|
-
WHILE
|
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
|
457
|
+
UNTIL Expression Block END { result = Riml::UntilNode.new(val[1], val[2]) }
|
434
458
|
;
|
435
459
|
|
436
460
|
For:
|
437
|
-
FOR IDENTIFIER IN
|
438
|
-
| FOR List IN
|
439
|
-
| FOR ListUnpack IN
|
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
|
461
|
-
| NEWLINE
|
484
|
+
NEWLINE Statements { result = val[1] }
|
485
|
+
| NEWLINE { result = Riml::Nodes.new([]) }
|
462
486
|
;
|
463
487
|
|
464
488
|
IfBlock:
|
465
|
-
Block
|
466
|
-
| NEWLINE
|
467
|
-
| NEWLINE
|
468
|
-
| NEWLINE
|
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
|
496
|
+
ELSE NEWLINE Statements { result = Riml::ElseNode.new(val[2]) }
|
473
497
|
;
|
474
498
|
|
475
499
|
ElseifBlock:
|
476
|
-
ELSEIF
|
477
|
-
| ElseifBlock ELSEIF
|
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
|
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,
|
545
|
+
raise Riml::ParseError, "on line #{@lexer.lineno}: #{e.message}"
|
522
546
|
end
|
523
547
|
|
524
548
|
@ast_rewriter ||= ast_rewriter
|