riml 0.3.4 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|