riml 0.3.4 → 0.3.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 +27 -27
- data/lib/riml.rb +32 -13
- data/lib/riml/ast_rewriter.rb +67 -26
- data/lib/riml/compiler.rb +12 -14
- data/lib/riml/file_rollback.rb +75 -0
- data/lib/riml/get_sid_function.vim +5 -1
- data/lib/riml/grammar.y +13 -1
- data/lib/riml/lexer.rb +11 -5
- data/lib/riml/nodes.rb +15 -41
- data/lib/riml/parser.rb +13 -1
- data/lib/riml/path_cache.rb +2 -2
- data/lib/riml/rewritten_ast_cache.rb +2 -2
- data/lib/riml/walker.rb +9 -2
- data/version.rb +2 -2
- metadata +4 -3
data/bin/riml
CHANGED
@@ -8,21 +8,20 @@ module Riml
|
|
8
8
|
require 'riml'
|
9
9
|
|
10
10
|
require 'optparse'
|
11
|
-
require 'ostruct'
|
12
11
|
|
13
12
|
class Options
|
14
13
|
def self.parse(argv)
|
15
14
|
argv << '--help' if argv.size.zero?
|
16
15
|
|
17
16
|
# defaults
|
18
|
-
options =
|
19
|
-
options
|
20
|
-
options
|
21
|
-
options
|
22
|
-
options
|
23
|
-
options
|
24
|
-
options
|
25
|
-
options
|
17
|
+
options = {}
|
18
|
+
options[:compile_files] = []
|
19
|
+
options[:check_syntax_files] = []
|
20
|
+
options[:repl] = false
|
21
|
+
options[:vi_readline] = false
|
22
|
+
options[:allow_undefined_global_classes] = DEFAULT_PARSE_OPTIONS[:allow_undefined_global_classes]
|
23
|
+
options[:readable] = DEFAULT_COMPILE_OPTIONS[:readable]
|
24
|
+
options[:output_dir] = DEFAULT_COMPILE_FILES_OPTIONS[:output_dir]
|
26
25
|
|
27
26
|
OptionParser.new do |opts|
|
28
27
|
opts.banner = "Usage: riml [options] [file1][,file2]..."
|
@@ -30,15 +29,15 @@ module Riml
|
|
30
29
|
opts.separator "Specific options:"
|
31
30
|
|
32
31
|
opts.on("-c", "--compile FILES", Array, "Compiles riml file(s) to VimL.") do |filenames|
|
33
|
-
append_filenames_to_list_if_valid(options
|
32
|
+
append_filenames_to_list_if_valid(options[:compile_files], *filenames)
|
34
33
|
end
|
35
34
|
|
36
35
|
opts.on("-s", "--stdio", "Takes riml from stdin and outputs VimL to stdout.") do
|
37
|
-
options
|
36
|
+
options[:stdio] = true
|
38
37
|
end
|
39
38
|
|
40
39
|
opts.on("-k", "--check FILES", Array, "Checks syntax of file(s). Because Riml is (mostly) compatible with VimL, this can also be used to check VimL syntax.") do |filenames|
|
41
|
-
append_filenames_to_list_if_valid(options
|
40
|
+
append_filenames_to_list_if_valid(options[:check_syntax_files], *filenames)
|
42
41
|
end
|
43
42
|
|
44
43
|
opts.on("-S", "--source-path PATH", "Colon-separated path riml uses to find files for `riml_source`. Defaults to pwd.") do |path|
|
@@ -58,23 +57,23 @@ module Riml
|
|
58
57
|
end
|
59
58
|
|
60
59
|
opts.on("-a", "--allow-undef-global-classes", "Continue compilation when encountering undefined global class(es).") do
|
61
|
-
options
|
60
|
+
options[:allow_undefined_global_classes] = true
|
62
61
|
end
|
63
62
|
|
64
63
|
opts.on("-o", "--output-dir DIR", "Output all .vim files in specified directory.") do |dir|
|
65
|
-
options
|
64
|
+
options[:output_dir] = dir
|
66
65
|
end
|
67
66
|
|
68
67
|
opts.on("-d", "--condensed", "Omit readability improvements such as blank lines.") do
|
69
|
-
options
|
68
|
+
options[:readable] = false
|
70
69
|
end
|
71
70
|
|
72
71
|
opts.on("-i", "--interactive", "Start an interactive riml session (REPL).") do
|
73
|
-
options
|
72
|
+
options[:repl] = true
|
74
73
|
end
|
75
74
|
|
76
75
|
opts.on("--vi", "Use vi readline settings during interactive session.") do
|
77
|
-
options
|
76
|
+
options[:vi_readline] = options[:repl] = true
|
78
77
|
end
|
79
78
|
|
80
79
|
opts.on_tail("-v", "--version", "Show riml version.") do
|
@@ -113,25 +112,26 @@ module Riml
|
|
113
112
|
def start
|
114
113
|
options = Options.parse(ARGV)
|
115
114
|
compile_options = {
|
116
|
-
:readable => options
|
117
|
-
:allow_undefined_global_classes => options
|
115
|
+
:readable => options[:readable],
|
116
|
+
:allow_undefined_global_classes => options[:allow_undefined_global_classes]
|
118
117
|
}
|
119
118
|
compile_files_options = compile_options.merge(
|
120
|
-
:output_dir => options
|
119
|
+
:output_dir => options[:output_dir]
|
121
120
|
)
|
122
|
-
if options
|
121
|
+
if options[:stdio]
|
123
122
|
puts Riml.compile($stdin.read, compile_options)
|
124
|
-
elsif options
|
125
|
-
|
126
|
-
|
127
|
-
|
123
|
+
elsif options[:compile_files].any?
|
124
|
+
FileRollback.trap(:INT, :QUIT, :KILL) { print("\n"); exit 1 }
|
125
|
+
Riml.compile_files(*options[:compile_files], compile_files_options)
|
126
|
+
elsif options[:check_syntax_files].any?
|
127
|
+
files = options[:check_syntax_files].uniq
|
128
128
|
Riml.check_syntax_files(*files)
|
129
129
|
size = files.size
|
130
130
|
# "ok (1 file)" OR "ok (2 files)"
|
131
131
|
puts "ok (#{size} file#{'s' if size > 1})"
|
132
|
-
elsif options
|
132
|
+
elsif options[:repl]
|
133
133
|
require 'riml/repl'
|
134
|
-
Riml::Repl.new(options
|
134
|
+
Riml::Repl.new(options[:vi_readline], compile_options).run
|
135
135
|
else
|
136
136
|
ARGV.replace ['--help']
|
137
137
|
start
|
data/lib/riml.rb
CHANGED
@@ -10,6 +10,7 @@ require 'riml/warning_buffer'
|
|
10
10
|
require 'riml/include_cache'
|
11
11
|
require 'riml/path_cache'
|
12
12
|
require 'riml/rewritten_ast_cache'
|
13
|
+
require 'riml/file_rollback'
|
13
14
|
|
14
15
|
module Riml
|
15
16
|
|
@@ -106,26 +107,28 @@ module Riml
|
|
106
107
|
# compile files using one thread per file, max 4 threads at once
|
107
108
|
if filenames.size > 1
|
108
109
|
threads = []
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
110
|
+
with_file_rollback do
|
111
|
+
while filenames.any?
|
112
|
+
to_compile = filenames.shift(4)
|
113
|
+
to_compile.each do |fname|
|
114
|
+
_parser, _compiler = Parser.new, Compiler.new
|
115
|
+
_compiler.options = compiler.options.dup
|
116
|
+
_parser.options = parser.options.dup
|
117
|
+
threads << Thread.new do
|
118
|
+
f = File.open(fname)
|
119
|
+
# `do_compile` will close file handle
|
120
|
+
do_compile(f, _parser, _compiler)
|
121
|
+
end
|
119
122
|
end
|
123
|
+
threads.each(&:join)
|
124
|
+
threads.clear
|
120
125
|
end
|
121
|
-
threads.each(&:join)
|
122
|
-
threads.clear
|
123
126
|
end
|
124
127
|
elsif filenames.size == 1
|
125
128
|
fname = filenames.first
|
126
129
|
f = File.open(fname)
|
127
130
|
# `do_compile` will close file handle
|
128
|
-
do_compile(f, parser, compiler)
|
131
|
+
with_file_rollback { do_compile(f, parser, compiler) }
|
129
132
|
else
|
130
133
|
raise ArgumentError, "need filenames to compile"
|
131
134
|
end
|
@@ -184,6 +187,21 @@ module Riml
|
|
184
187
|
end
|
185
188
|
@rewritten_ast_cache = RewrittenASTCache.new
|
186
189
|
|
190
|
+
def self.clear_caches
|
191
|
+
@include_cache.clear
|
192
|
+
@path_cache.clear
|
193
|
+
@rewritten_ast_cache.clear
|
194
|
+
end
|
195
|
+
|
196
|
+
# if error is thrown, all files that were created will be rolled back
|
197
|
+
# to their previous state. If the file existed previously, it will be
|
198
|
+
# the same as it was. If the file didn't exist, it will be removed if
|
199
|
+
# it was created.
|
200
|
+
def self.with_file_rollback(&block)
|
201
|
+
FileRollback.guard(&block)
|
202
|
+
end
|
203
|
+
|
204
|
+
# turn warnings on/off
|
187
205
|
class << self
|
188
206
|
attr_accessor :warnings
|
189
207
|
end
|
@@ -276,6 +294,7 @@ module Riml
|
|
276
294
|
if output[-2..-1] == "\n\n"
|
277
295
|
output.chomp!
|
278
296
|
end
|
297
|
+
FileRollback.creating_file(full_path)
|
279
298
|
File.open(full_path, 'w') do |f|
|
280
299
|
f.write FILE_HEADER + output
|
281
300
|
end
|
data/lib/riml/ast_rewriter.rb
CHANGED
@@ -28,7 +28,7 @@ module Riml
|
|
28
28
|
def rewrite(filename = nil, included = false)
|
29
29
|
if filename && (rewritten_ast = Riml.rewritten_ast_cache[filename])
|
30
30
|
rewrite_included_and_sourced_files!(filename)
|
31
|
-
rewritten_ast
|
31
|
+
return rewritten_ast
|
32
32
|
end
|
33
33
|
if @options && @options[:allow_undefined_global_classes] && !@classes.has_global_import?
|
34
34
|
@classes.globbed_imports.unshift(ImportedClass.new('*'))
|
@@ -70,7 +70,7 @@ module Riml
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def rewrite_on_match(node = ast)
|
73
|
-
Walker.walk_node(node, method(:do_rewrite_on_match),
|
73
|
+
Walker.walk_node(node, method(:do_rewrite_on_match), max_recursion_lvl)
|
74
74
|
end
|
75
75
|
|
76
76
|
def do_rewrite_on_match(node)
|
@@ -85,8 +85,7 @@ module Riml
|
|
85
85
|
# node in order to compile it on the spot.
|
86
86
|
def rewrite_included_and_sourced_files!(filename)
|
87
87
|
old_ast = ast
|
88
|
-
ast.children.each do |node|
|
89
|
-
next unless RimlFileCommandNode === node
|
88
|
+
ast.children.grep(RimlFileCommandNode).each do |node|
|
90
89
|
action = node.name == 'riml_include' ? 'include' : 'source'
|
91
90
|
|
92
91
|
node.each_existing_file! do |file, fullpath|
|
@@ -117,21 +116,20 @@ module Riml
|
|
117
116
|
end
|
118
117
|
|
119
118
|
def watch_for_class_pickup
|
120
|
-
before_class_names = classes.class_names
|
119
|
+
before_class_names = @classes.class_names
|
121
120
|
ast = yield
|
122
|
-
after_class_names = classes.class_names
|
121
|
+
after_class_names = @classes.class_names
|
123
122
|
diff_class_names = after_class_names - before_class_names
|
124
123
|
class_diff = diff_class_names.inject({}) do |hash, class_name|
|
125
|
-
hash[class_name] = classes[class_name]
|
124
|
+
hash[class_name] = @classes[class_name]
|
126
125
|
hash
|
127
126
|
end
|
128
127
|
# no classes were picked up, it could be that the cache was hit. Let's
|
129
128
|
# register the cached classes for this ast, if there are any
|
130
129
|
if class_diff.empty?
|
131
130
|
real_diff = Riml.rewritten_ast_cache.fetch_classes_registered(ast)
|
132
|
-
return if real_diff.empty?
|
133
131
|
real_diff.each do |k,v|
|
134
|
-
classes[k] = v unless classes.safe_fetch(k)
|
132
|
+
@classes[k] = v unless @classes.safe_fetch(k)
|
135
133
|
end
|
136
134
|
# new classes were picked up, let's save them with this ast as the key
|
137
135
|
else
|
@@ -139,8 +137,9 @@ module Riml
|
|
139
137
|
end
|
140
138
|
end
|
141
139
|
|
142
|
-
|
143
|
-
|
140
|
+
# recurse until no more children
|
141
|
+
def max_recursion_lvl
|
142
|
+
-1
|
144
143
|
end
|
145
144
|
|
146
145
|
# Add SID function if this is the main file and it has defined classes, or
|
@@ -166,11 +165,21 @@ module Riml
|
|
166
165
|
fchild = ast.nodes.first
|
167
166
|
return false if DefNode === fchild && fchild.name == 'SID' && fchild.scope_modifier == 's:'
|
168
167
|
fn = DefNode.new('!', nil, 's:', 'SID', [], nil, Nodes.new([
|
169
|
-
|
168
|
+
IfNode.new(
|
169
|
+
CallNode.new(nil, 'exists', [StringNode.new('s:SID_VALUE', :s)]),
|
170
|
+
Nodes.new([
|
171
|
+
ReturnNode.new(GetVariableNode.new('s:', 'SID_VALUE'))
|
172
|
+
])
|
173
|
+
),
|
174
|
+
AssignNode.new(
|
175
|
+
'=',
|
176
|
+
GetVariableNode.new('s:', 'SID_VALUE'),
|
177
|
+
CallNode.new(nil, 'matchstr', [
|
170
178
|
CallNode.new(nil, 'expand', [StringNode.new('<sfile>', :s)]),
|
171
179
|
StringNode.new('<SNR>\zs\d\+\ze_SID$', :s)
|
172
180
|
]
|
173
|
-
))
|
181
|
+
)),
|
182
|
+
ReturnNode.new(GetVariableNode.new('s:', 'SID_VALUE'))
|
174
183
|
])
|
175
184
|
)
|
176
185
|
fn.parent = ast.nodes
|
@@ -196,6 +205,10 @@ module Riml
|
|
196
205
|
end
|
197
206
|
node.remove
|
198
207
|
end
|
208
|
+
|
209
|
+
def max_recursion_lvl
|
210
|
+
1
|
211
|
+
end
|
199
212
|
end
|
200
213
|
|
201
214
|
class RegisterDefinedClasses < AST_Rewriter
|
@@ -208,6 +221,10 @@ module Riml
|
|
208
221
|
n.instance_variable_set("@registered_state", true)
|
209
222
|
classes[node.full_name] = n
|
210
223
|
end
|
224
|
+
|
225
|
+
def max_recursion_lvl
|
226
|
+
1
|
227
|
+
end
|
211
228
|
end
|
212
229
|
|
213
230
|
class StrictEqualsComparisonOperator < AST_Rewriter
|
@@ -257,8 +274,8 @@ module Riml
|
|
257
274
|
def replace(node)
|
258
275
|
classes[node.full_name] = node
|
259
276
|
|
260
|
-
RegisterPrivateFunctions.new(node, classes).rewrite_on_match
|
261
|
-
DefNodeToPrivateFunction.new(node, classes).rewrite_on_match
|
277
|
+
RegisterPrivateFunctions.new(node.expressions, classes).rewrite_on_match
|
278
|
+
DefNodeToPrivateFunction.new(node.expressions, classes).rewrite_on_match
|
262
279
|
InsertInitializeMethod.new(node, classes).rewrite_on_match
|
263
280
|
constructor = node.constructor
|
264
281
|
constructor.name = node.constructor_name
|
@@ -266,7 +283,7 @@ module Riml
|
|
266
283
|
constructor.scope_modifier = node.scope_modifier
|
267
284
|
# set up dictionary variable at top of function
|
268
285
|
dict_name = node.constructor_obj_name
|
269
|
-
constructor.expressions.unshift(
|
286
|
+
constructor.expressions.nodes.unshift(
|
270
287
|
AssignNode.new('=', GetVariableNode.new(nil, dict_name), DictionaryNode.new({}))
|
271
288
|
)
|
272
289
|
|
@@ -277,19 +294,27 @@ module Riml
|
|
277
294
|
PrivateFunctionCallToPassObjExplicitly.new(node, classes).rewrite_on_match
|
278
295
|
SplatsToExecuteInCallingContext.new(node, classes).rewrite_on_match
|
279
296
|
|
280
|
-
constructor.expressions.push(
|
297
|
+
constructor.expressions.nodes.push(
|
281
298
|
ReturnNode.new(GetVariableNode.new(nil, dict_name))
|
282
299
|
)
|
283
300
|
reestablish_parents(constructor)
|
284
301
|
end
|
285
302
|
|
303
|
+
def max_recursion_lvl
|
304
|
+
1
|
305
|
+
end
|
306
|
+
|
286
307
|
class RegisterPrivateFunctions < AST_Rewriter
|
287
308
|
def match?(node)
|
288
309
|
node.instance_of?(DefNode) && node.name != 'initialize'
|
289
310
|
end
|
290
311
|
|
291
312
|
def replace(node)
|
292
|
-
ast.private_function_names << node.name
|
313
|
+
ast.parent.private_function_names << node.name
|
314
|
+
end
|
315
|
+
|
316
|
+
def max_recursion_lvl
|
317
|
+
1
|
293
318
|
end
|
294
319
|
end
|
295
320
|
|
@@ -468,7 +493,7 @@ module Riml
|
|
468
493
|
end
|
469
494
|
|
470
495
|
def replace(node)
|
471
|
-
class_node = ast
|
496
|
+
class_node = ast.parent
|
472
497
|
class_name = class_node.name
|
473
498
|
node.scope_modifier = 's:'
|
474
499
|
node.original_name = node.name
|
@@ -481,6 +506,10 @@ module Riml
|
|
481
506
|
self_to_obj_argument.rewrite_on_match
|
482
507
|
reestablish_parents(node)
|
483
508
|
end
|
509
|
+
|
510
|
+
def max_recursion_lvl
|
511
|
+
1
|
512
|
+
end
|
484
513
|
end
|
485
514
|
|
486
515
|
class PrivateFunctionCallToPassObjExplicitly < AST_Rewriter
|
@@ -517,7 +546,7 @@ module Riml
|
|
517
546
|
def replace(node)
|
518
547
|
def_node = node.to_def_node
|
519
548
|
class_expressions = ast.expressions
|
520
|
-
class_expressions.insert_after(class_expressions.last, def_node)
|
549
|
+
class_expressions.insert_after(class_expressions.nodes.last, def_node)
|
521
550
|
def_node.parent = class_expressions
|
522
551
|
# to remove it
|
523
552
|
node.parent = class_expressions
|
@@ -559,6 +588,10 @@ module Riml
|
|
559
588
|
constructor.expressions << extension
|
560
589
|
extension.parent = constructor.expressions
|
561
590
|
end
|
591
|
+
|
592
|
+
def max_recursion_lvl
|
593
|
+
2
|
594
|
+
end
|
562
595
|
end
|
563
596
|
|
564
597
|
class SelfToDictName < AST_Rewriter
|
@@ -599,7 +632,7 @@ module Riml
|
|
599
632
|
'!', nil, nil, "initialize", [], nil, Nodes.new([])
|
600
633
|
)
|
601
634
|
end
|
602
|
-
class_node.expressions.unshift(def_node)
|
635
|
+
class_node.expressions.nodes.unshift(def_node)
|
603
636
|
reestablish_parents(class_node)
|
604
637
|
end
|
605
638
|
|
@@ -611,8 +644,8 @@ module Riml
|
|
611
644
|
classes.superclass(ast.full_name).imported?
|
612
645
|
end
|
613
646
|
|
614
|
-
def
|
615
|
-
|
647
|
+
def max_recursion_lvl
|
648
|
+
1
|
616
649
|
end
|
617
650
|
end
|
618
651
|
|
@@ -668,8 +701,8 @@ module Riml
|
|
668
701
|
end
|
669
702
|
end
|
670
703
|
|
671
|
-
def
|
672
|
-
|
704
|
+
def max_recursion_lvl
|
705
|
+
1
|
673
706
|
end
|
674
707
|
end
|
675
708
|
|
@@ -824,7 +857,7 @@ module Riml
|
|
824
857
|
def_node.parameters.delete_if(&DefNode::DEFAULT_PARAMS)
|
825
858
|
def_node.parameters << SPLAT_LITERAL unless def_node.splat
|
826
859
|
end
|
827
|
-
def_node.expressions.insert(insert_idx, if_expression)
|
860
|
+
def_node.expressions.nodes.insert(insert_idx, if_expression)
|
828
861
|
reestablish_parents(def_node)
|
829
862
|
end
|
830
863
|
|
@@ -841,6 +874,10 @@ module Riml
|
|
841
874
|
])
|
842
875
|
)
|
843
876
|
end
|
877
|
+
|
878
|
+
def max_recursion_lvl
|
879
|
+
3
|
880
|
+
end
|
844
881
|
end
|
845
882
|
|
846
883
|
class DeserializeVarAssignment < AST_Rewriter
|
@@ -883,6 +920,10 @@ module Riml
|
|
883
920
|
new_node.keywords = keywords
|
884
921
|
node.replace_with(new_node)
|
885
922
|
end
|
923
|
+
|
924
|
+
def max_recursion_lvl
|
925
|
+
1
|
926
|
+
end
|
886
927
|
end
|
887
928
|
|
888
929
|
end
|
data/lib/riml/compiler.rb
CHANGED
@@ -79,8 +79,7 @@ module Riml
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
node.compiled_output << "\n" unless node.compiled_output[-1] == "\n"
|
82
|
-
node.
|
83
|
-
node.compiled_output << "endif"
|
82
|
+
node.compiled_output << "endif\n"
|
84
83
|
end
|
85
84
|
end
|
86
85
|
|
@@ -113,8 +112,7 @@ module Riml
|
|
113
112
|
node.body.compiled_output.each_line do |line|
|
114
113
|
node.compiled_output << node.indent + line
|
115
114
|
end
|
116
|
-
node.
|
117
|
-
node.compiled_output << "endwhile"
|
115
|
+
node.compiled_output << "endwhile\n"
|
118
116
|
end
|
119
117
|
end
|
120
118
|
|
@@ -479,7 +477,7 @@ module Riml
|
|
479
477
|
body = ""
|
480
478
|
unless node.expressions.compiled_output.empty?
|
481
479
|
node.expressions.compiled_output.each_line do |line|
|
482
|
-
body << node.indent
|
480
|
+
body << node.indent << line
|
483
481
|
end
|
484
482
|
end
|
485
483
|
node.compiled_output = declaration << body << "endfunction\n"
|
@@ -565,14 +563,14 @@ module Riml
|
|
565
563
|
node.compiled_output << ")" unless node.builtin_command?
|
566
564
|
unless node.descendant_of_control_structure? ||
|
567
565
|
node.descendant_of_call_node? ||
|
568
|
-
node.
|
566
|
+
node.descendant_of_dict_get_dot_node? ||
|
567
|
+
node.descendant_of_dictionary_node? ||
|
569
568
|
node.descendant_of_list_node? ||
|
570
569
|
node.descendant_of_list_or_dict_get_node? ||
|
571
570
|
node.descendant_of_operator_node? ||
|
572
571
|
node.descendant_of_wrap_in_parens_node? ||
|
573
572
|
node.descendant_of_sublist_node? ||
|
574
|
-
node.
|
575
|
-
node.descendant_of_dictionary_node? ||
|
573
|
+
node.descendant_of_object_instantiation_node? ||
|
576
574
|
node.descendant_of_curly_brace_part?
|
577
575
|
node.force_newline = true
|
578
576
|
end
|
@@ -646,7 +644,7 @@ module Riml
|
|
646
644
|
node.expressions.accept(NodesVisitor.new :propagate_up_tree => false)
|
647
645
|
body = node.expressions.compiled_output
|
648
646
|
body.each_line do |line|
|
649
|
-
node.compiled_output << node.indent
|
647
|
+
node.compiled_output << node.indent << line
|
650
648
|
end
|
651
649
|
node.compiled_output << "endfor\n"
|
652
650
|
end
|
@@ -659,7 +657,7 @@ module Riml
|
|
659
657
|
node.compiled_output = "try\n"
|
660
658
|
try.accept(visitor_for_node(try, :propagate_up_tree => false))
|
661
659
|
try.compiled_output.each_line do |line|
|
662
|
-
node.compiled_output << node.indent
|
660
|
+
node.compiled_output << node.indent << line
|
663
661
|
end
|
664
662
|
|
665
663
|
catches.each do |c|
|
@@ -667,9 +665,9 @@ module Riml
|
|
667
665
|
c.compiled_output.each_line do |line|
|
668
666
|
outdent = line =~ /\A\s*catch/
|
669
667
|
if outdent && c.non_nested?
|
670
|
-
node.compiled_output << node.outdent
|
668
|
+
node.compiled_output << node.outdent << line
|
671
669
|
else
|
672
|
-
node.compiled_output << node.indent
|
670
|
+
node.compiled_output << node.indent << line
|
673
671
|
end
|
674
672
|
end
|
675
673
|
end if catches
|
@@ -678,7 +676,7 @@ module Riml
|
|
678
676
|
node.compiled_output << "finally\n"
|
679
677
|
finally.accept(visitor_for_node(finally, :propagate_up_tree => false))
|
680
678
|
finally.compiled_output.each_line do |line|
|
681
|
-
node.compiled_output << node.indent
|
679
|
+
node.compiled_output << node.indent << line
|
682
680
|
end
|
683
681
|
end
|
684
682
|
node.compiled_output << "endtry\n"
|
@@ -787,7 +785,7 @@ module Riml
|
|
787
785
|
root_node = parser.parse(source, parser.ast_rewriter, file_basepath, true)
|
788
786
|
included_files_compiled << file_basepath
|
789
787
|
output = compile(root_node)
|
790
|
-
(Riml::INCLUDE_COMMENT_FMT % file_basepath)
|
788
|
+
(Riml::INCLUDE_COMMENT_FMT % file_basepath) << output
|
791
789
|
end
|
792
790
|
end
|
793
791
|
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Riml
|
4
|
+
class FileRollback
|
5
|
+
@files_created = Set.new
|
6
|
+
# { 'main.vim' => nil, 'existed.vim' => "\nsource code..." }
|
7
|
+
@previous_file_states = {}
|
8
|
+
@guarding = 0
|
9
|
+
@m = Mutex.new
|
10
|
+
|
11
|
+
# NOTE: Used only in main thread.
|
12
|
+
# Only call this method in one thread at a time. It's okay if
|
13
|
+
# `&block` launches threads, and they compile files though.
|
14
|
+
def self.guard(&block)
|
15
|
+
@guarding += 1
|
16
|
+
block.call
|
17
|
+
rescue
|
18
|
+
rollback!
|
19
|
+
raise
|
20
|
+
ensure
|
21
|
+
@guarding -= 1
|
22
|
+
if @guarding == 0
|
23
|
+
clear
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.trap(*signals, &block)
|
28
|
+
signals.each do |sig|
|
29
|
+
Signal.trap(sig) do
|
30
|
+
rollback! if @guarding > 0
|
31
|
+
block.call if block
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.creating_file(full_path)
|
37
|
+
@m.synchronize do
|
38
|
+
return unless @guarding > 0
|
39
|
+
previous_state = File.file?(full_path) ? File.read(full_path) : nil
|
40
|
+
@previous_file_states[full_path] ||= previous_state
|
41
|
+
@files_created << full_path
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.clear
|
46
|
+
@m.synchronize do
|
47
|
+
@files_created = Set.new
|
48
|
+
@previous_file_states.clear
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.rollback!
|
53
|
+
@m.synchronize do
|
54
|
+
@files_created.each do |path|
|
55
|
+
rollback_file!(path)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def self.rollback_file!(file_path)
|
63
|
+
if !@previous_file_states.key?(file_path)
|
64
|
+
return false
|
65
|
+
end
|
66
|
+
prev_state = @previous_file_states[file_path]
|
67
|
+
if prev_state.nil?
|
68
|
+
File.delete(file_path) if File.exists?(file_path)
|
69
|
+
else
|
70
|
+
File.open(file_path, 'w') { |f| f.write(prev_state) }
|
71
|
+
end
|
72
|
+
prev_state
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/riml/grammar.y
CHANGED
@@ -567,8 +567,14 @@ end
|
|
567
567
|
@options ||= {}
|
568
568
|
end
|
569
569
|
|
570
|
+
@@ast_cache = {}
|
571
|
+
|
570
572
|
# parses tokens or code into output nodes
|
571
573
|
def parse(object, ast_rewriter = Riml::AST_Rewriter.new, filename = nil, included = false)
|
574
|
+
#if @@ast_cache[filename]
|
575
|
+
#return @@ast_cache[filename]
|
576
|
+
#end
|
577
|
+
|
572
578
|
if tokens?(object)
|
573
579
|
@tokens = object
|
574
580
|
elsif code?(object)
|
@@ -588,11 +594,17 @@ end
|
|
588
594
|
raise Riml::ParseError, error_msg
|
589
595
|
end
|
590
596
|
|
597
|
+
|
591
598
|
@ast_rewriter ||= ast_rewriter
|
592
|
-
|
599
|
+
unless @ast_rewriter
|
600
|
+
#@@ast_cache[filename] = ast if filename
|
601
|
+
return ast
|
602
|
+
end
|
593
603
|
@ast_rewriter.ast = ast
|
594
604
|
@ast_rewriter.options ||= options
|
595
605
|
@ast_rewriter.rewrite(filename, included)
|
606
|
+
#@@ast_cache[filename] = @ast_rewriter.ast if filename
|
607
|
+
#@ast_rewriter.ast
|
596
608
|
end
|
597
609
|
|
598
610
|
# get the next token from either the list of tokens provided, or
|
data/lib/riml/lexer.rb
CHANGED
@@ -11,9 +11,9 @@ module Riml
|
|
11
11
|
ANCHORED_INTERPOLATION_REGEX = /\A#{INTERPOLATION_REGEX}/m
|
12
12
|
INTERPOLATION_SPLIT_REGEX = /(\#\{.*?\})/m
|
13
13
|
|
14
|
-
attr_reader :tokens, :prev_token, :
|
15
|
-
:
|
16
|
-
|
14
|
+
attr_reader :tokens, :prev_token, :chunk, :current_indent,
|
15
|
+
:invalid_keyword, :filename, :parser_info
|
16
|
+
attr_accessor :lineno
|
17
17
|
# for REPL
|
18
18
|
attr_accessor :ignore_indentation_check
|
19
19
|
|
@@ -139,7 +139,7 @@ module Riml
|
|
139
139
|
|
140
140
|
@token_buf << [token_name.intern, identifier]
|
141
141
|
|
142
|
-
elsif BUILTIN_COMMANDS.include?(identifier) &&
|
142
|
+
elsif BUILTIN_COMMANDS.include?(identifier) && peek(identifier.size) != '('
|
143
143
|
@token_buf << [:BUILTIN_COMMAND, identifier]
|
144
144
|
elsif RIML_FILE_COMMANDS.include? identifier
|
145
145
|
@token_buf << [:RIML_FILE_COMMAND, identifier]
|
@@ -330,7 +330,9 @@ module Riml
|
|
330
330
|
end
|
331
331
|
|
332
332
|
def tokenize_without_moving_pos(code)
|
333
|
-
Lexer.new(code).
|
333
|
+
Lexer.new(code, filename, false).tap do |l|
|
334
|
+
l.lineno = lineno
|
335
|
+
end.tokenize
|
334
336
|
end
|
335
337
|
|
336
338
|
def statement_modifier?
|
@@ -350,5 +352,9 @@ module Riml
|
|
350
352
|
def more_code_to_tokenize?
|
351
353
|
@i < @code.size
|
352
354
|
end
|
355
|
+
|
356
|
+
def peek(n = 1)
|
357
|
+
@chunk[n]
|
358
|
+
end
|
353
359
|
end
|
354
360
|
end
|
data/lib/riml/nodes.rb
CHANGED
@@ -29,23 +29,25 @@ module Riml
|
|
29
29
|
"#{filename}:#{parser_info[:lineno]}"
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
32
|
+
%w(
|
33
|
+
control_structure
|
34
|
+
call_node
|
35
|
+
object_instantiation_node
|
36
|
+
list_node
|
37
|
+
list_or_dict_get_node
|
38
|
+
operator_node
|
39
|
+
wrap_in_parens_node
|
40
|
+
sublist_node
|
41
|
+
dict_get_dot_node
|
42
|
+
dictionary_node
|
43
|
+
curly_brace_part
|
44
|
+
).each do |node_name|
|
45
|
+
define_method "descendant_of_#{node_name}?" do
|
46
|
+
parent_node_name = node_name.split('_').map(&:capitalize).join
|
40
47
|
parent_node = Riml.const_get parent_node_name
|
41
48
|
parent_node === self.parent_node
|
42
|
-
else
|
43
|
-
super
|
44
49
|
end
|
45
50
|
end
|
46
|
-
def respond_to?(method, include_private = false)
|
47
|
-
super || method =~ DESCENDANT_OF_REGEX
|
48
|
-
end
|
49
51
|
end
|
50
52
|
|
51
53
|
module Walkable
|
@@ -189,19 +191,6 @@ module Riml
|
|
189
191
|
self
|
190
192
|
end
|
191
193
|
|
192
|
-
# forward missing methods to `nodes` array
|
193
|
-
def method_missing(method, *args, &block)
|
194
|
-
if nodes.respond_to?(method)
|
195
|
-
nodes.send(method, *args, &block)
|
196
|
-
else
|
197
|
-
super
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def respond_to?(method, include_private = false)
|
202
|
-
super || nodes.respond_to?(method, include_private)
|
203
|
-
end
|
204
|
-
|
205
194
|
def children
|
206
195
|
nodes
|
207
196
|
end
|
@@ -759,14 +748,6 @@ module Riml
|
|
759
748
|
end
|
760
749
|
children.concat(default_param_nodes)
|
761
750
|
end
|
762
|
-
|
763
|
-
def method_missing(method, *args, &blk)
|
764
|
-
if children.respond_to?(method)
|
765
|
-
children.send(method, *args, &blk)
|
766
|
-
else
|
767
|
-
super
|
768
|
-
end
|
769
|
-
end
|
770
751
|
end
|
771
752
|
|
772
753
|
class DefaultParamNode < Struct.new(:parameter, :expression)
|
@@ -792,13 +773,6 @@ module Riml
|
|
792
773
|
|
793
774
|
alias function? function
|
794
775
|
|
795
|
-
def initialize_copy(source)
|
796
|
-
super
|
797
|
-
self.for_node_variable_names = for_node_variable_names.dup
|
798
|
-
self.argument_variable_names = argument_variable_names.dup
|
799
|
-
self.function = source.function
|
800
|
-
end
|
801
|
-
|
802
776
|
def merge(other)
|
803
777
|
dup.merge! other
|
804
778
|
end
|
data/lib/riml/parser.rb
CHANGED
@@ -24,8 +24,14 @@ module_eval(<<'...end grammar.y/module_eval...', 'grammar.y', 560)
|
|
24
24
|
@options ||= {}
|
25
25
|
end
|
26
26
|
|
27
|
+
@@ast_cache = {}
|
28
|
+
|
27
29
|
# parses tokens or code into output nodes
|
28
30
|
def parse(object, ast_rewriter = Riml::AST_Rewriter.new, filename = nil, included = false)
|
31
|
+
#if @@ast_cache[filename]
|
32
|
+
#return @@ast_cache[filename]
|
33
|
+
#end
|
34
|
+
|
29
35
|
if tokens?(object)
|
30
36
|
@tokens = object
|
31
37
|
elsif code?(object)
|
@@ -45,11 +51,17 @@ module_eval(<<'...end grammar.y/module_eval...', 'grammar.y', 560)
|
|
45
51
|
raise Riml::ParseError, error_msg
|
46
52
|
end
|
47
53
|
|
54
|
+
|
48
55
|
@ast_rewriter ||= ast_rewriter
|
49
|
-
|
56
|
+
unless @ast_rewriter
|
57
|
+
#@@ast_cache[filename] = ast if filename
|
58
|
+
return ast
|
59
|
+
end
|
50
60
|
@ast_rewriter.ast = ast
|
51
61
|
@ast_rewriter.options ||= options
|
52
62
|
@ast_rewriter.rewrite(filename, included)
|
63
|
+
#@@ast_cache[filename] = @ast_rewriter.ast if filename
|
64
|
+
#@ast_rewriter.ast
|
53
65
|
end
|
54
66
|
|
55
67
|
# get the next token from either the list of tokens provided, or
|
data/lib/riml/path_cache.rb
CHANGED
@@ -21,11 +21,11 @@ module Riml
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def save_classes_registered(ast, class_diff)
|
24
|
-
@ast_classes_registered_cache[ast] = class_diff
|
24
|
+
@ast_classes_registered_cache[ast.object_id] = class_diff
|
25
25
|
end
|
26
26
|
|
27
27
|
def fetch_classes_registered(ast)
|
28
|
-
@ast_classes_registered_cache[ast] || {}
|
28
|
+
@ast_classes_registered_cache[ast.object_id] || {}
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
data/lib/riml/walker.rb
CHANGED
@@ -1,14 +1,21 @@
|
|
1
1
|
module Riml
|
2
2
|
class Walker
|
3
|
-
|
3
|
+
MAX_RECURSION_LVL_ACTUAL = 1_000_000
|
4
|
+
|
5
|
+
def self.walk_node(node, method, max_recursion_lvl = -1)
|
6
|
+
if max_recursion_lvl == -1
|
7
|
+
max_recursion_lvl = MAX_RECURSION_LVL_ACTUAL
|
8
|
+
end
|
4
9
|
# breadth-first walk
|
5
10
|
to_visit = [node]
|
11
|
+
lvl = 0
|
6
12
|
while to_visit.length > 0
|
7
13
|
cur_node = to_visit.shift
|
8
14
|
cur_node.children.each do |child|
|
9
15
|
to_visit << child
|
10
|
-
end if cur_node.respond_to?(:children)
|
16
|
+
end if lvl < max_recursion_lvl && cur_node.respond_to?(:children)
|
11
17
|
method.call(cur_node)
|
18
|
+
lvl += 1
|
12
19
|
end
|
13
20
|
end
|
14
21
|
end
|
data/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: riml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-10-
|
12
|
+
date: 2013-10-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: racc
|
@@ -106,6 +106,7 @@ files:
|
|
106
106
|
- version.rb
|
107
107
|
- lib/riml.rb
|
108
108
|
- lib/riml/parser.rb
|
109
|
+
- lib/riml/file_rollback.rb
|
109
110
|
- lib/riml/get_sid_function.vim
|
110
111
|
- lib/riml/walker.rb
|
111
112
|
- lib/riml/rewritten_ast_cache.rb
|
@@ -150,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
151
|
version: '0'
|
151
152
|
segments:
|
152
153
|
- 0
|
153
|
-
hash:
|
154
|
+
hash: 3731001160727385716
|
154
155
|
requirements: []
|
155
156
|
rubyforge_project:
|
156
157
|
rubygems_version: 1.8.25
|