riml 0.1.3 → 0.1.5
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/bin/riml +22 -15
- data/lib/ast_rewriter.rb +6 -5
- data/lib/compiler.rb +85 -39
- data/lib/constants.rb +4 -0
- data/{config → lib}/environment.rb +3 -2
- data/lib/errors.rb +7 -2
- data/lib/grammar.y +143 -125
- data/lib/header.vim +4 -0
- data/lib/lexer.rb +6 -3
- data/lib/nodes.rb +49 -9
- data/lib/parser.rb +1269 -1349
- data/lib/riml.rb +84 -0
- data/version.rb +2 -2
- metadata +7 -6
- data/lib/helper.rb +0 -45
data/bin/riml
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# vim: syntax=ruby
|
3
3
|
|
4
|
-
require File.expand_path("../../
|
4
|
+
require File.expand_path("../../lib/environment", __FILE__)
|
5
5
|
|
6
6
|
module Riml
|
7
7
|
include Environment
|
8
|
-
require
|
9
|
-
require File.join(LIBDIR, "helper")
|
8
|
+
require 'riml'
|
10
9
|
|
11
10
|
require 'optparse'
|
12
11
|
require 'ostruct'
|
@@ -16,32 +15,41 @@ module Riml
|
|
16
15
|
|
17
16
|
# defaults
|
18
17
|
options = OpenStruct.new
|
19
|
-
options.
|
20
|
-
options.riml_source_path = Dir.getwd
|
18
|
+
options.compile_files = []
|
21
19
|
|
22
20
|
OptionParser.new do |opts|
|
23
21
|
opts.banner = "Usage: riml [options]"
|
24
22
|
opts.separator ""
|
25
23
|
opts.separator "Specific options:"
|
26
24
|
|
27
|
-
opts.on("-c", "--compile FILE", "Compile riml file to VimL") do |file|
|
25
|
+
opts.on("-c", "--compile FILE", "Compile riml file to VimL.") do |file|
|
28
26
|
if File.exists?(file)
|
29
|
-
options.
|
27
|
+
options.compile_files << file
|
30
28
|
else
|
31
|
-
warn "Couldn't find file #{file.inspect}"
|
29
|
+
warn "Couldn't find file #{file.inspect}."
|
30
|
+
exit 1
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
35
|
-
opts.on("-
|
34
|
+
opts.on("-t", "--source-path PATH", "Path riml uses for `riml_source` to find files. Defaults to pwd.") do |path|
|
35
|
+
if Dir.exists?(path)
|
36
|
+
Riml.source_path = path
|
37
|
+
else
|
38
|
+
warn "Couldn't find directory #{path.inspect}."
|
39
|
+
exit 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on("-s", "--stdio", "Pipe in riml to STDIN and get back VimL on STDOUT.") do
|
36
44
|
options.stdio = true
|
37
45
|
end
|
38
46
|
|
39
|
-
opts.on_tail("-v", "--version", "Show riml version") do
|
47
|
+
opts.on_tail("-v", "--version", "Show riml version.") do
|
40
48
|
puts VERSION.join('.')
|
41
49
|
exit
|
42
50
|
end
|
43
51
|
|
44
|
-
opts.on_tail("-h", "--help", "Show this message") do
|
52
|
+
opts.on_tail("-h", "--help", "Show this message.") do
|
45
53
|
puts opts
|
46
54
|
exit
|
47
55
|
end
|
@@ -55,12 +63,11 @@ module Riml
|
|
55
63
|
class << self
|
56
64
|
def start
|
57
65
|
options = Options.parse(ARGV)
|
66
|
+
|
58
67
|
if options.stdio
|
59
68
|
puts Riml.compile($stdin.gets)
|
60
|
-
elsif options.
|
61
|
-
options.
|
62
|
-
Riml.compile_file(file)
|
63
|
-
end
|
69
|
+
elsif options.compile_files.any?
|
70
|
+
Riml.compile_files(*options.compile_files)
|
64
71
|
end
|
65
72
|
end
|
66
73
|
end
|
data/lib/ast_rewriter.rb
CHANGED
@@ -6,8 +6,8 @@ module Riml
|
|
6
6
|
class AST_Rewriter
|
7
7
|
include Riml::Constants
|
8
8
|
|
9
|
-
|
10
|
-
def initialize(ast)
|
9
|
+
attr_accessor :ast
|
10
|
+
def initialize(ast = nil)
|
11
11
|
@ast = ast
|
12
12
|
end
|
13
13
|
|
@@ -134,11 +134,12 @@ module Riml
|
|
134
134
|
def replace(node)
|
135
135
|
def_node = node.to_def_node
|
136
136
|
node.parent_node = ast.expressions
|
137
|
+
def_node.parent_node = ast.expressions
|
137
138
|
node.remove
|
138
139
|
def_node.name.insert(0, "#{dict_name}.")
|
139
140
|
def_node.parent_node = constructor.expressions
|
140
141
|
constructor.expressions << def_node
|
141
|
-
reestablish_parents(
|
142
|
+
reestablish_parents(def_node)
|
142
143
|
end
|
143
144
|
end
|
144
145
|
|
@@ -259,8 +260,8 @@ module Riml
|
|
259
260
|
end
|
260
261
|
|
261
262
|
def replace(node)
|
262
|
-
node.replace_with(ExplicitCallNode.new(node[0], node[1], node[2]))
|
263
|
-
reestablish_parents(
|
263
|
+
explicit = node.replace_with(ExplicitCallNode.new(node[0], node[1], node[2]))
|
264
|
+
reestablish_parents(explicit)
|
264
265
|
end
|
265
266
|
end
|
266
267
|
|
data/lib/compiler.rb
CHANGED
@@ -14,7 +14,6 @@ module Riml
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def visit(node)
|
17
|
-
node.compiled_output.clear
|
18
17
|
@value = compile(node)
|
19
18
|
@value << "\n" if node.force_newline and @value[-1] != "\n"
|
20
19
|
propagate_up_tree(node, @value)
|
@@ -33,12 +32,11 @@ module Riml
|
|
33
32
|
def compile(node)
|
34
33
|
condition_visitor = visitor_for_node(node.condition)
|
35
34
|
node.condition.parent_node = node
|
36
|
-
node.
|
37
|
-
node.compiled_output = "if
|
35
|
+
node.condition.force_newline = true
|
36
|
+
node.compiled_output = "if "
|
38
37
|
node.compiled_output << "!" if UnlessNode === node
|
39
38
|
|
40
39
|
node.condition.accept(condition_visitor)
|
41
|
-
node.compiled_output << ")\n"
|
42
40
|
node.body.accept(NodesVisitor.new(:propagate_up_tree => false))
|
43
41
|
|
44
42
|
node.body.compiled_output.each_line do |line|
|
@@ -69,12 +67,10 @@ module Riml
|
|
69
67
|
|
70
68
|
class WhileNodeVisitor < Visitor
|
71
69
|
def compile(node)
|
72
|
-
node.condition.
|
73
|
-
node.compiled_output = "while
|
70
|
+
node.condition.force_newline = true
|
71
|
+
node.compiled_output = "while "
|
74
72
|
node.compiled_output << "!" if UntilNode === node
|
75
|
-
|
76
73
|
node.condition.accept visitor_for_node(node.condition)
|
77
|
-
node.compiled_output << ")\n"
|
78
74
|
|
79
75
|
node.body.accept NodesVisitor.new(:propagate_up_tree => false)
|
80
76
|
|
@@ -92,19 +88,18 @@ module Riml
|
|
92
88
|
class ElseNodeVisitor < Visitor
|
93
89
|
def compile(node)
|
94
90
|
node.compiled_output = "else\n"
|
95
|
-
|
96
|
-
node.expressions.
|
97
|
-
node.expressions.accept(expressions_visitor)
|
91
|
+
node.expressions.parent = node
|
92
|
+
node.expressions.accept(visitor_for_node(node.expressions))
|
98
93
|
node.compiled_output
|
99
94
|
end
|
100
95
|
end
|
101
96
|
|
102
97
|
class ElseifNodeVisitor < Visitor
|
103
98
|
def compile(node)
|
104
|
-
node.compiled_output = "elseif
|
99
|
+
node.compiled_output = "elseif "
|
105
100
|
node.condition.parent_node = node
|
101
|
+
node.condition.force_newline = true
|
106
102
|
node.condition.accept(visitor_for_node(node.condition))
|
107
|
-
node.compiled_output << ")\n"
|
108
103
|
node.expressions.parent_node = node
|
109
104
|
node.expressions.accept(visitor_for_node(node.expressions))
|
110
105
|
node.force_newline = true
|
@@ -127,6 +122,8 @@ module Riml
|
|
127
122
|
end
|
128
123
|
end
|
129
124
|
|
125
|
+
SublistNodeVisitor = NodesVisitor
|
126
|
+
|
130
127
|
class LiteralNodeVisitor < Visitor
|
131
128
|
def compile(node)
|
132
129
|
value = case node.value
|
@@ -208,6 +205,15 @@ module Riml
|
|
208
205
|
end
|
209
206
|
end
|
210
207
|
|
208
|
+
class WrapInParensNodeVisitor < Visitor
|
209
|
+
def compile(node)
|
210
|
+
node.compiled_output << "("
|
211
|
+
node.expression.parent_node = node
|
212
|
+
node.expression.accept(visitor_for_node(node.expression))
|
213
|
+
node.compiled_output << ")"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
211
217
|
# common visiting methods for nodes that are scope modified with variable
|
212
218
|
# name prefixes
|
213
219
|
class ScopedVisitor < Visitor
|
@@ -305,19 +311,15 @@ module Riml
|
|
305
311
|
class BinaryOperatorNodeVisitor < Visitor
|
306
312
|
def compile(node)
|
307
313
|
op1, op2 = node.operand1, node.operand2
|
308
|
-
|
309
|
-
|
310
|
-
op1.accept(op1_visitor)
|
311
|
-
op2_visitor.propagate_up_tree = false
|
312
|
-
op2.accept(op2_visitor)
|
314
|
+
[op1, op2].each {|n| n.parent = node}
|
315
|
+
op1.accept(visitor_for_node(op1))
|
313
316
|
if node.ignorecase_capable_operator?(node.operator)
|
314
317
|
operator_suffix = "# "
|
315
318
|
else
|
316
319
|
operator_suffix = " "
|
317
320
|
end
|
318
321
|
node.compiled_output << " #{node.operator}#{operator_suffix}"
|
319
|
-
|
320
|
-
op2.accept(op2_visitor)
|
322
|
+
op2.accept(visitor_for_node(op2))
|
321
323
|
node.compiled_output
|
322
324
|
end
|
323
325
|
end
|
@@ -405,34 +407,40 @@ module Riml
|
|
405
407
|
|
406
408
|
class CallNodeVisitor < ScopedVisitor
|
407
409
|
def compile(node)
|
408
|
-
set_modifier(node)
|
410
|
+
set_modifier(node) if node.name && !node.builtin_function?
|
409
411
|
node.compiled_output =
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
412
|
+
if node.name.respond_to?(:variable)
|
413
|
+
node.name.accept(visitor_for_node(node.name))
|
414
|
+
node.scope_modifier + node.name.compiled_output
|
415
|
+
elsif DictGetDotNode === node.name
|
416
|
+
node.name.accept(visitor_for_node(node.name))
|
417
|
+
node.name.compiled_output
|
418
|
+
else
|
419
|
+
"#{node.full_name}"
|
420
|
+
end
|
421
|
+
compile_arguments(node)
|
422
|
+
node.compiled_output
|
423
|
+
end
|
424
|
+
|
425
|
+
def compile_arguments(node)
|
426
|
+
node.compiled_output << (node.builtin_command? ? " " : "(")
|
420
427
|
node.arguments.each_with_index do |arg, i|
|
421
428
|
arg.parent_node = node
|
422
429
|
arg_visitor = visitor_for_node(arg)
|
423
430
|
arg.accept(arg_visitor)
|
424
431
|
node.compiled_output << ", " unless last_arg?(node.arguments, i)
|
425
432
|
end
|
426
|
-
node.compiled_output << ")" unless node.
|
433
|
+
node.compiled_output << ")" unless node.builtin_command?
|
427
434
|
|
428
435
|
unless node.descendant_of_control_structure? ||
|
429
436
|
node.descendant_of_call_node? ||
|
430
437
|
node.descendant_of_list_node? ||
|
431
438
|
node.descendant_of_list_or_dict_get_node? ||
|
432
|
-
node.descendant_of_operator_node?
|
439
|
+
node.descendant_of_operator_node? ||
|
440
|
+
node.descendant_of_wrap_in_parens_node? ||
|
441
|
+
node.descendant_of_sublist_node?
|
433
442
|
node.force_newline = true
|
434
443
|
end
|
435
|
-
node.compiled_output
|
436
444
|
end
|
437
445
|
|
438
446
|
private
|
@@ -443,9 +451,36 @@ module Riml
|
|
443
451
|
|
444
452
|
class ExplicitCallNodeVisitor < CallNodeVisitor
|
445
453
|
def compile(node)
|
446
|
-
|
447
|
-
|
448
|
-
|
454
|
+
if node.scope_modifier || node.name
|
455
|
+
node.compiled_output = "call " << super
|
456
|
+
else
|
457
|
+
node.compiled_output = "call"
|
458
|
+
compile_arguments(node)
|
459
|
+
end
|
460
|
+
node.compiled_output
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
class RimlCommandNodeVisitor < CallNodeVisitor
|
465
|
+
def compile(node)
|
466
|
+
if node.name == 'riml_source'
|
467
|
+
node.arguments.map(&:value).each do |file|
|
468
|
+
unless File.exists?(File.join(Riml.source_path, file))
|
469
|
+
raise Riml::FileNotFound, "#{file.inspect} could not be found in " \
|
470
|
+
"source path (#{Riml.source_path.inspect})"
|
471
|
+
end
|
472
|
+
|
473
|
+
root_node(node).current_compiler.compile_queue << file
|
474
|
+
end
|
475
|
+
node.compiled_output << 'source'
|
476
|
+
compile_arguments(node)
|
477
|
+
node.compiled_output.gsub(/['"]/, '').gsub('.riml', '.vim')
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
def root_node(node)
|
482
|
+
node = node.parent until node.parent.nil?
|
483
|
+
node
|
449
484
|
end
|
450
485
|
end
|
451
486
|
|
@@ -568,10 +603,21 @@ module Riml
|
|
568
603
|
end
|
569
604
|
end
|
570
605
|
|
606
|
+
module CompilerAccessible
|
607
|
+
attr_accessor :current_compiler
|
608
|
+
end
|
609
|
+
|
610
|
+
def compile_queue
|
611
|
+
@compile_queue ||= []
|
612
|
+
end
|
613
|
+
|
571
614
|
# compiles nodes into output code
|
572
615
|
def compile(root_node)
|
573
|
-
|
574
|
-
|
616
|
+
# so we can compile concurrently, as some nodes have access to the
|
617
|
+
# compiler instance itself
|
618
|
+
root_node.extend CompilerAccessible
|
619
|
+
root_node.current_compiler = self
|
620
|
+
root_node.accept(NodesVisitor.new)
|
575
621
|
root_node.compiled_output
|
576
622
|
end
|
577
623
|
|
data/lib/constants.rb
CHANGED
@@ -11,10 +11,14 @@ module Riml
|
|
11
11
|
class new)
|
12
12
|
DEFINE_KEYWORDS = %w(def def! defm defm! function function!)
|
13
13
|
KEYWORDS = VIML_KEYWORDS + VIML_END_KEYWORDS + RIML_KEYWORDS
|
14
|
+
|
14
15
|
SPECIAL_VARIABLE_PREFIXES =
|
15
16
|
%w(& @ $)
|
16
17
|
BUILTIN_COMMANDS =
|
17
18
|
%w(echo echon echohl execute sleep)
|
19
|
+
RIML_COMMANDS =
|
20
|
+
%w(riml_source)
|
21
|
+
|
18
22
|
IGNORECASE_CAPABLE_OPERATORS =
|
19
23
|
%w(== != >= > <= < =~ !~)
|
20
24
|
COMPARISON_OPERATORS = IGNORECASE_CAPABLE_OPERATORS.map do |o|
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module Riml
|
2
2
|
module Environment
|
3
3
|
ROOTDIR = File.expand_path('../../', __FILE__)
|
4
|
+
require File.join(ROOTDIR, 'version')
|
4
5
|
|
5
|
-
LIBDIR = File.join(ROOTDIR,
|
6
|
-
BINDIR = File.join(ROOTDIR,
|
6
|
+
LIBDIR = File.join(ROOTDIR, 'lib')
|
7
|
+
BINDIR = File.join(ROOTDIR, 'bin')
|
7
8
|
|
8
9
|
$:.unshift(LIBDIR) unless $:.include? LIBDIR
|
9
10
|
end
|
data/lib/errors.rb
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
module Riml
|
2
|
-
|
3
|
-
|
2
|
+
RimlError = Class.new(StandardError)
|
3
|
+
|
4
|
+
SyntaxError = Class.new(RimlError)
|
5
|
+
ParseError = Class.new(RimlError)
|
6
|
+
CompileError = Class.new(RimlError)
|
7
|
+
|
8
|
+
FileNotFound = Class.new(RimlError)
|
4
9
|
end
|
data/lib/grammar.y
CHANGED
@@ -5,7 +5,7 @@ token WHILE UNTIL BREAK CONTINUE
|
|
5
5
|
token TRY CATCH ENSURE
|
6
6
|
token FOR IN
|
7
7
|
token DEF DEF_BANG SPLAT CALL BUILTIN_COMMAND # such as echo "hi"
|
8
|
-
token CLASS NEW DEFM DEFM_BANG SUPER
|
8
|
+
token CLASS NEW DEFM DEFM_BANG SUPER RIML_COMMAND
|
9
9
|
token RETURN
|
10
10
|
token NEWLINE
|
11
11
|
token NUMBER
|
@@ -21,14 +21,14 @@ token FINISH
|
|
21
21
|
prechigh
|
22
22
|
right '!'
|
23
23
|
left '*' '/' '%'
|
24
|
-
left '+' '
|
24
|
+
left '+' '-' '.'
|
25
25
|
left '>' '>#' '>?' '<' '<#' '<?' '>=' '>=#' '>=?' '<=' '<=#' '<=?'
|
26
26
|
left '==' '==?' '==#' '=~' '=~?' '=~#' '!~' '!~?' '!~#' '!=' '!=?' '!=#'
|
27
27
|
left IS ISNOT
|
28
28
|
left '&&'
|
29
29
|
left '||'
|
30
30
|
right '?'
|
31
|
-
right '='
|
31
|
+
right '=' '+=' '-=' '.='
|
32
32
|
left ','
|
33
33
|
left IF UNLESS
|
34
34
|
preclow
|
@@ -43,40 +43,47 @@ rule
|
|
43
43
|
|
44
44
|
# any list of expressions
|
45
45
|
Expressions:
|
46
|
-
|
47
|
-
| Expressions Terminator
|
46
|
+
AnyExpression { result = Nodes.new([ val[0] ]) }
|
47
|
+
| Expressions Terminator AnyExpression { result = val[0] << val[2] }
|
48
48
|
| Expressions Terminator { result = val[0] }
|
49
49
|
| Terminator { result = Nodes.new([]) }
|
50
50
|
;
|
51
51
|
|
52
52
|
# All types of expressions in Riml
|
53
|
-
|
54
|
-
|
55
|
-
| UnaryOperator { result = val[0] }
|
56
|
-
| Call { result = val[0] }
|
57
|
-
| Assign { result = val[0] }
|
58
|
-
| DictGet { result = val[0] }
|
59
|
-
| ListOrDictGet { result = val[0] }
|
53
|
+
AnyExpression:
|
54
|
+
ExplicitCall { result = val[0] }
|
60
55
|
| Def { result = val[0] }
|
61
56
|
| Return { result = val[0] }
|
62
|
-
| VariableRetrieval { result = val[0] }
|
63
57
|
| UnletVariable { result = val[0] }
|
64
|
-
| Literal { result = val[0] }
|
65
58
|
| ExLiteral { result = val[0] }
|
66
|
-
| Heredoc { result = val[0] }
|
67
59
|
| If { result = val[0] }
|
68
60
|
| Unless { result = val[0] }
|
69
|
-
|
|
61
|
+
| For { result = val[0] }
|
70
62
|
| While { result = val[0] }
|
71
63
|
| Until { result = val[0] }
|
72
|
-
| For { result = val[0] }
|
73
64
|
| Try { result = val[0] }
|
74
65
|
| ClassDefinition { result = val[0] }
|
75
|
-
| ObjectInstantiation { result = val[0] }
|
76
66
|
| Super { result = val[0] }
|
77
67
|
| LoopKeyword { result = val[0] }
|
78
68
|
| EndScript { result = val[0] }
|
79
|
-
|
|
69
|
+
| ValueExpression { result = val[0] }
|
70
|
+
| RimlCommand { result = val[0] }
|
71
|
+
;
|
72
|
+
|
73
|
+
# Expressions that evaluate to a value
|
74
|
+
ValueExpression:
|
75
|
+
UnaryOperator { result = val[0] }
|
76
|
+
| Assign { result = val[0] }
|
77
|
+
| DictGet { result = val[0] }
|
78
|
+
| ListOrDictGet { result = val[0] }
|
79
|
+
| VariableRetrieval { result = val[0] }
|
80
|
+
| Literal { result = val[0] }
|
81
|
+
| Call { result = val[0] }
|
82
|
+
| Heredoc { result = val[0] }
|
83
|
+
| Ternary { result = val[0] }
|
84
|
+
| ObjectInstantiation { result = val[0] }
|
85
|
+
| BinaryOperator { result = val[0] }
|
86
|
+
| '(' ValueExpression ')' { result = WrapInParensNode.new(val[1]) }
|
80
87
|
;
|
81
88
|
|
82
89
|
Terminator:
|
@@ -100,8 +107,6 @@ rule
|
|
100
107
|
|
101
108
|
Number:
|
102
109
|
NUMBER { result = NumberNode.new(val[0]) }
|
103
|
-
| '-' NUMBER { result = NumberNode.new(val[1].insert(0, val[0])) }
|
104
|
-
| '+' NUMBER { result = NumberNode.new(val[1].insert(0, val[0])) }
|
105
110
|
;
|
106
111
|
|
107
112
|
String:
|
@@ -132,8 +137,8 @@ rule
|
|
132
137
|
|
133
138
|
ListItems:
|
134
139
|
/* nothing */ { result = [] }
|
135
|
-
|
|
136
|
-
| ListItems ','
|
140
|
+
| ValueExpression { result = [val[0]] }
|
141
|
+
| ListItems ',' ValueExpression { result = val[0] << val[2] }
|
137
142
|
;
|
138
143
|
|
139
144
|
Dictionary:
|
@@ -159,30 +164,27 @@ rule
|
|
159
164
|
;
|
160
165
|
|
161
166
|
DictGet:
|
162
|
-
Dictionary
|
163
|
-
| Dictionary DictGetWithDotLiteral { result = DictGetDotNode.new(val[0], val[1]) }
|
167
|
+
Dictionary DictGetWithDotLiteral { result = DictGetDotNode.new(val[0], val[1]) }
|
164
168
|
| VariableRetrieval DictGetWithDot { result = DictGetDotNode.new(val[0], val[1]) }
|
165
169
|
| ListOrDictGet DictGetWithDot { result = DictGetDotNode.new(val[0], val[1]) }
|
166
170
|
;
|
167
171
|
|
168
172
|
ListOrDictGet:
|
169
|
-
|
170
|
-
| DictGet ListOrDictGetWithBrackets { result = ListOrDictGetNode.new(val[0], val[1]) }
|
171
|
-
| Call ListOrDictGetWithBrackets { result = ListOrDictGetNode.new(val[0], val[1]) }
|
173
|
+
ValueExpression ListOrDictGetWithBrackets { result = ListOrDictGetNode.new(val[0], val[1]) }
|
172
174
|
;
|
173
175
|
|
174
176
|
ListOrDictGetWithBrackets:
|
175
|
-
'['
|
176
|
-
| '[' SubList ']'
|
177
|
-
| ListOrDictGetWithBrackets '['
|
178
|
-
| ListOrDictGetWithBrackets '[' SubList ']'
|
177
|
+
'[' ValueExpression ']' { result = [val[1]] }
|
178
|
+
| '[' SubList ']' { result = [val[1]] }
|
179
|
+
| ListOrDictGetWithBrackets '[' ValueExpression ']' { result = val[0] << val[2] }
|
180
|
+
| ListOrDictGetWithBrackets '[' SubList ']' { result = val[0] << val[2] }
|
179
181
|
;
|
180
182
|
|
181
183
|
SubList:
|
182
|
-
|
183
|
-
|
|
184
|
-
| ':'
|
185
|
-
| ':' { result =
|
184
|
+
ValueExpression ':' ValueExpression { result = SublistNode.new([val[0], LiteralNode.new(' : '), val[2]]) }
|
185
|
+
| ValueExpression ':' { result = SublistNode.new([val[0], LiteralNode.new(' :')]) }
|
186
|
+
| ':' ValueExpression { result = SublistNode.new([LiteralNode.new(': '), val[1]]) }
|
187
|
+
| ':' { result = SublistNode.new([LiteralNode.new(':')]) }
|
186
188
|
;
|
187
189
|
|
188
190
|
DictGetWithDot:
|
@@ -198,10 +200,19 @@ rule
|
|
198
200
|
Call:
|
199
201
|
Scope DefCallIdentifier '(' ArgList ')' { result = CallNode.new(val[0], val[1], val[3]) }
|
200
202
|
| DictGet '(' ArgList ')' { result = CallNode.new(nil, val[0], val[2]) }
|
201
|
-
| CALL Scope DefCallIdentifier '(' ArgList ')' { result = ExplicitCallNode.new(val[1], val[2], val[4]) }
|
202
|
-
| CALL DictGet '(' ArgList ')' { result = ExplicitCallNode.new(nil, val[1], val[3]) }
|
203
203
|
| BUILTIN_COMMAND '(' ArgList ')' { result = CallNode.new(nil, val[0], val[2]) }
|
204
204
|
| BUILTIN_COMMAND ArgList { result = CallNode.new(nil, val[0], val[1]) }
|
205
|
+
| CALL '(' ArgList ')' { result = ExplicitCallNode.new(nil, nil, val[2]) }
|
206
|
+
;
|
207
|
+
|
208
|
+
RimlCommand:
|
209
|
+
RIML_COMMAND '(' ArgList ')' { result = RimlCommandNode.new(nil, val[0], val[2]) }
|
210
|
+
| RIML_COMMAND ArgList { result = RimlCommandNode.new(nil, val[0], val[1]) }
|
211
|
+
;
|
212
|
+
|
213
|
+
ExplicitCall:
|
214
|
+
CALL Scope DefCallIdentifier '(' ArgList ')' { result = ExplicitCallNode.new(val[1], val[2], val[4]) }
|
215
|
+
| CALL DictGet '(' ArgList ')' { result = ExplicitCallNode.new(nil, val[1], val[3]) }
|
205
216
|
;
|
206
217
|
|
207
218
|
Scope:
|
@@ -211,101 +222,103 @@ rule
|
|
211
222
|
|
212
223
|
ArgList:
|
213
224
|
/* nothing */ { result = [] }
|
214
|
-
|
|
215
|
-
| ArgList ","
|
225
|
+
| ValueExpression { result = val }
|
226
|
+
| ArgList "," ValueExpression { result = val[0] << val[2] }
|
216
227
|
;
|
217
228
|
|
218
229
|
BinaryOperator:
|
219
|
-
|
220
|
-
|
|
230
|
+
ValueExpression '||' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
231
|
+
| ValueExpression '&&' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
221
232
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
233
|
+
| ValueExpression '==' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
234
|
+
| ValueExpression '==#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
235
|
+
| ValueExpression '==?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
225
236
|
|
226
237
|
# added by riml
|
227
|
-
|
|
238
|
+
| ValueExpression '===' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
228
239
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
240
|
+
| ValueExpression '!=' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
241
|
+
| ValueExpression '!=#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
242
|
+
| ValueExpression '!=?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
232
243
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
244
|
+
| ValueExpression '=~' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
245
|
+
| ValueExpression '=~#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
246
|
+
| ValueExpression '=~?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
236
247
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
248
|
+
| ValueExpression '!~' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
249
|
+
| ValueExpression '!~#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
250
|
+
| ValueExpression '!~?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
240
251
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
252
|
+
| ValueExpression '>' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
253
|
+
| ValueExpression '>#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
254
|
+
| ValueExpression '>?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
244
255
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
256
|
+
| ValueExpression '>=' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
257
|
+
| ValueExpression '>=#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
258
|
+
| ValueExpression '>=?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
248
259
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
260
|
+
| ValueExpression '<' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
261
|
+
| ValueExpression '<#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
262
|
+
| ValueExpression '<?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
252
263
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
264
|
+
| ValueExpression '<=' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
265
|
+
| ValueExpression '<=#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
266
|
+
| ValueExpression '<=?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
256
267
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
268
|
+
| ValueExpression '+' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
269
|
+
| ValueExpression '-' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
270
|
+
| ValueExpression '*' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
271
|
+
| ValueExpression '/' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
272
|
+
| ValueExpression '.' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
262
273
|
|
263
|
-
|
|
264
|
-
|
|
274
|
+
| ValueExpression IS ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
275
|
+
| ValueExpression ISNOT ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
265
276
|
;
|
266
277
|
|
267
278
|
UnaryOperator:
|
268
|
-
'!'
|
279
|
+
'!' ValueExpression { result = UnaryOperatorNode.new(val[0], val[1]) }
|
280
|
+
| '+' ValueExpression { result = UnaryOperatorNode.new(val[0], val[1]) }
|
281
|
+
| '-' ValueExpression { result = UnaryOperatorNode.new(val[0], val[1]) }
|
269
282
|
;
|
270
283
|
|
271
284
|
# ['=', LHS, RHS]
|
272
285
|
Assign:
|
273
|
-
LET AssignExpression
|
274
|
-
| AssignExpression
|
286
|
+
LET AssignExpression { result = AssignNode.new(val[1][0], val[1][1], val[1][2]) }
|
287
|
+
| AssignExpression { result = AssignNode.new(val[0][0], val[0][1], val[0][2]) }
|
275
288
|
;
|
276
289
|
|
277
290
|
# ['=', AssignLHS, Expression]
|
278
291
|
AssignExpression:
|
279
|
-
AssignLHS '='
|
280
|
-
| AssignLHS '+='
|
281
|
-
| AssignLHS '-='
|
282
|
-
| AssignLHS '.='
|
292
|
+
AssignLHS '=' ValueExpression { result = [val[1], val[0], val[2]] }
|
293
|
+
| AssignLHS '+=' ValueExpression { result = [val[1], val[0], val[2]] }
|
294
|
+
| AssignLHS '-=' ValueExpression { result = [val[1], val[0], val[2]] }
|
295
|
+
| AssignLHS '.=' ValueExpression { result = [val[1], val[0], val[2]] }
|
283
296
|
;
|
284
297
|
|
285
298
|
AssignLHS:
|
286
|
-
VariableRetrieval
|
287
|
-
| DictGet
|
288
|
-
| List
|
289
|
-
| ListOrDictGet
|
299
|
+
VariableRetrieval { result = val[0] }
|
300
|
+
| DictGet { result = val[0] }
|
301
|
+
| List { result = val[0] }
|
302
|
+
| ListOrDictGet { result = val[0] }
|
290
303
|
;
|
291
304
|
|
292
305
|
# retrieving the value of a variable
|
293
306
|
VariableRetrieval:
|
294
|
-
Scope IDENTIFIER
|
295
|
-
| SPECIAL_VAR_PREFIX IDENTIFIER
|
296
|
-
| Scope CurlyBraceName
|
307
|
+
Scope IDENTIFIER { result = GetVariableNode.new(val[0], val[1]) }
|
308
|
+
| SPECIAL_VAR_PREFIX IDENTIFIER { result = GetSpecialVariableNode.new(val[0], val[1]) }
|
309
|
+
| Scope CurlyBraceName { result = GetCurlyBraceNameNode.new(val[0], val[1]) }
|
297
310
|
;
|
298
311
|
|
299
312
|
UnletVariable:
|
300
|
-
UNLET VariableRetrieval
|
301
|
-
| UNLET_BANG VariableRetrieval
|
302
|
-
| UnletVariable VariableRetrieval
|
313
|
+
UNLET VariableRetrieval { result = UnletVariableNode.new('!', [ val[1] ]) }
|
314
|
+
| UNLET_BANG VariableRetrieval { result = UnletVariableNode.new('!', [ val[1] ]) }
|
315
|
+
| UnletVariable VariableRetrieval { result = val[0] << val[1] }
|
303
316
|
;
|
304
317
|
|
305
318
|
CurlyBraceName:
|
306
|
-
IDENTIFIER '{' VariableRetrieval '}'
|
307
|
-
| '{' VariableRetrieval '}' IDENTIFIER
|
308
|
-
| CurlyBraceName IDENTIFIER
|
319
|
+
IDENTIFIER '{' VariableRetrieval '}' { result = CurlyBraceVariable.new([ CurlyBracePart.new(val[0]), CurlyBracePart.new(val[2]) ]) }
|
320
|
+
| '{' VariableRetrieval '}' IDENTIFIER { result = CurlyBraceVariable.new([ CurlyBracePart.new(val[1]), CurlyBracePart.new(val[3]) ]) }
|
321
|
+
| CurlyBraceName IDENTIFIER { result = val[0] << CurlyBracePart.new(val[1]) }
|
309
322
|
;
|
310
323
|
|
311
324
|
# Method definition
|
@@ -325,11 +338,11 @@ rule
|
|
325
338
|
|
326
339
|
DefCallIdentifier:
|
327
340
|
# use '' for first argument instead of nil in order to avoid a double scope-modifier
|
328
|
-
CurlyBraceName { result = GetCurlyBraceNameNode.new('', val[0])}
|
341
|
+
CurlyBraceName { result = GetCurlyBraceNameNode.new('', val[0]) }
|
329
342
|
| IDENTIFIER { result = val[0] }
|
330
343
|
;
|
331
344
|
|
332
|
-
# Example: 'range' or '
|
345
|
+
# Example: 'range', 'dict' or 'abort' after function definition
|
333
346
|
Keyword:
|
334
347
|
IDENTIFIER { result = val[0] }
|
335
348
|
| /* nothing */ { result = nil }
|
@@ -342,7 +355,7 @@ rule
|
|
342
355
|
;
|
343
356
|
|
344
357
|
Return:
|
345
|
-
RETURN
|
358
|
+
RETURN ValueExpression { result = ReturnNode.new(val[1]) }
|
346
359
|
| RETURN Terminator { result = ReturnNode.new(nil) }
|
347
360
|
;
|
348
361
|
|
@@ -352,23 +365,23 @@ rule
|
|
352
365
|
|
353
366
|
# [expression, expressions]
|
354
367
|
If:
|
355
|
-
IF
|
356
|
-
| IF
|
357
|
-
|
|
368
|
+
IF ValueExpression IfBlock END { result = IfNode.new(val[1], val[2]) }
|
369
|
+
| IF ValueExpression THEN ValueExpression END { result = IfNode.new(val[1], Nodes.new([val[3]])) }
|
370
|
+
| ValueExpression IF ValueExpression { result = IfNode.new(val[2], Nodes.new([val[0]])) }
|
358
371
|
;
|
359
372
|
|
360
373
|
Unless:
|
361
|
-
UNLESS
|
362
|
-
| UNLESS
|
363
|
-
|
|
374
|
+
UNLESS ValueExpression IfBlock END { result = UnlessNode.new(val[1], val[2]) }
|
375
|
+
| UNLESS ValueExpression THEN ValueExpression END { result = UnlessNode.new(val[1], Nodes.new([val[3]])) }
|
376
|
+
| ValueExpression UNLESS ValueExpression { result = UnlessNode.new(val[2], Nodes.new([val[0]])) }
|
364
377
|
;
|
365
378
|
|
366
379
|
Ternary:
|
367
|
-
|
380
|
+
ValueExpression '?' ValueExpression ':' ValueExpression { result = TernaryOperatorNode.new([val[0], val[2], val[4]]) }
|
368
381
|
;
|
369
382
|
|
370
383
|
While:
|
371
|
-
WHILE
|
384
|
+
WHILE ValueExpression Block END { result = WhileNode.new(val[1], val[2]) }
|
372
385
|
;
|
373
386
|
|
374
387
|
LoopKeyword:
|
@@ -377,12 +390,12 @@ rule
|
|
377
390
|
;
|
378
391
|
|
379
392
|
Until:
|
380
|
-
UNTIL
|
393
|
+
UNTIL ValueExpression Block END { result = UntilNode.new(val[1], val[2]) }
|
381
394
|
;
|
382
395
|
|
383
396
|
For:
|
384
|
-
FOR IDENTIFIER IN
|
385
|
-
| FOR List IN
|
397
|
+
FOR IDENTIFIER IN ValueExpression Block END { result = ForNode.new(val[1], val[3], val[4]) }
|
398
|
+
| FOR List IN ValueExpression Block END { result = ForNode.new(val[1], val[3], val[4]) }
|
386
399
|
;
|
387
400
|
|
388
401
|
Try:
|
@@ -409,17 +422,18 @@ rule
|
|
409
422
|
|
410
423
|
IfBlock:
|
411
424
|
Block { result = val[0] }
|
412
|
-
| NEWLINE Expressions ElseBlock { result = val[1]
|
425
|
+
| NEWLINE Expressions ElseBlock { result = val[1] << val[2] }
|
426
|
+
| NEWLINE Expressions ElseifBlock { result = val[1] << val[2] }
|
427
|
+
| NEWLINE Expressions ElseifBlock ElseBlock { result = val[1] << val[2] << val[3] }
|
413
428
|
;
|
414
429
|
|
415
430
|
ElseBlock:
|
416
|
-
|
431
|
+
ELSE NEWLINE Expressions { result = ElseNode.new(val[2]) }
|
417
432
|
;
|
418
433
|
|
419
434
|
ElseifBlock:
|
420
|
-
ELSEIF
|
421
|
-
| ElseifBlock ELSEIF
|
422
|
-
| /* nothing */ { result = nil }
|
435
|
+
ELSEIF ValueExpression NEWLINE Expressions { result = Nodes.new([ElseifNode.new(val[1], val[3])]) }
|
436
|
+
| ElseifBlock ELSEIF ValueExpression NEWLINE Expressions { result = val[0] << ElseifNode.new(val[2], val[4]) }
|
423
437
|
;
|
424
438
|
|
425
439
|
ClassDefinition:
|
@@ -449,27 +463,31 @@ end
|
|
449
463
|
---- inner
|
450
464
|
# This code will be put as-is in the parser class
|
451
465
|
|
466
|
+
attr_accessor :ast_rewriter
|
467
|
+
|
452
468
|
# parses tokens or code into output nodes
|
453
|
-
def parse(object,
|
469
|
+
def parse(object, ast_rewriter = AST_Rewriter.new)
|
454
470
|
if tokens?(object)
|
455
471
|
@tokens = object
|
456
472
|
elsif code?(object)
|
457
473
|
@lexer = Riml::Lexer.new(object)
|
458
474
|
end
|
459
|
-
ast = do_parse
|
460
|
-
return ast if rewrite_ast == false
|
461
|
-
AST_Rewriter.new(ast).rewrite
|
462
|
-
end
|
463
475
|
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
476
|
+
begin
|
477
|
+
ast = do_parse
|
478
|
+
rescue Racc::ParseError => e
|
479
|
+
raise unless @lexer
|
480
|
+
raise Riml::ParseError, "line #{@lexer.lineno}: #{e.message}"
|
481
|
+
end
|
482
|
+
|
483
|
+
@ast_rewriter = ast_rewriter
|
484
|
+
return ast unless @ast_rewriter
|
485
|
+
@ast_rewriter.ast = ast
|
486
|
+
@ast_rewriter.rewrite
|
470
487
|
end
|
471
|
-
alias do_parse do_parse_with_error_handling
|
472
488
|
|
489
|
+
# get the next token from either the list of tokens provided, or
|
490
|
+
# the lexer getting the next token
|
473
491
|
def next_token
|
474
492
|
return @tokens.shift unless @lexer
|
475
493
|
@lexer.next_token
|