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 +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
|
[![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
|
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
|