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 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 = OpenStruct.new
19
- options.compile_files = []
20
- options.check_syntax_files = []
21
- options.repl = false
22
- options.vi_readline = false
23
- options.allow_undefined_global_classes = DEFAULT_PARSE_OPTIONS[:allow_undefined_global_classes]
24
- options.readable = DEFAULT_COMPILE_OPTIONS[:readable]
25
- options.output_dir = DEFAULT_COMPILE_FILES_OPTIONS[:output_dir]
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.compile_files, *filenames)
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.stdio = true
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.check_syntax_files, *filenames)
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.allow_undefined_global_classes = true
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.output_dir = dir
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.readable = false
68
+ options[:readable] = false
70
69
  end
71
70
 
72
71
  opts.on("-i", "--interactive", "Start an interactive riml session (REPL).") do
73
- options.repl = true
72
+ options[:repl] = true
74
73
  end
75
74
 
76
75
  opts.on("--vi", "Use vi readline settings during interactive session.") do
77
- options.vi_readline = options.repl = true
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.readable,
117
- :allow_undefined_global_classes => options.allow_undefined_global_classes
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.output_dir
119
+ :output_dir => options[:output_dir]
121
120
  )
122
- if options.stdio
121
+ if options[:stdio]
123
122
  puts Riml.compile($stdin.read, compile_options)
124
- elsif options.compile_files.any?
125
- Riml.compile_files(*options.compile_files, compile_files_options)
126
- elsif options.check_syntax_files.any?
127
- files = options.check_syntax_files.uniq
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.repl
132
+ elsif options[:repl]
133
133
  require 'riml/repl'
134
- Riml::Repl.new(options.vi_readline, compile_options).run
134
+ Riml::Repl.new(options[:vi_readline], compile_options).run
135
135
  else
136
136
  ARGV.replace ['--help']
137
137
  start
@@ -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
- while filenames.any?
110
- to_compile = filenames.shift(4)
111
- to_compile.each do |fname|
112
- _parser, _compiler = Parser.new, Compiler.new
113
- _compiler.options = compiler.options.dup
114
- _parser.options = parser.options.dup
115
- threads << Thread.new do
116
- f = File.open(fname)
117
- # `do_compile` will close file handle
118
- do_compile(f, _parser, _compiler)
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
@@ -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), lambda { |_| recursive? })
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
- def recursive?
143
- true
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
- ReturnNode.new(CallNode.new(nil, 'matchstr', [
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 recursive?
615
- false
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 recursive?
672
- false
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
@@ -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.force_newline = true
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.force_newline = true
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 + line
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.descendant_of_object_instantiation_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.descendant_of_dict_get_dot_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 + line
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 + line
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 + line
668
+ node.compiled_output << node.outdent << line
671
669
  else
672
- node.compiled_output << node.indent + line
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 + line
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) + output
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
@@ -1,3 +1,7 @@
1
1
  function! s:SID()
2
- return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
2
+ if exists('s:SID_VALUE')
3
+ return s:SID_VALUE
4
+ endif
5
+ let s:SID_VALUE = matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
6
+ return s:SID_VALUE
3
7
  endfunction
@@ -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
- return ast unless @ast_rewriter
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
@@ -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, :lineno, :chunk,
15
- :current_indent, :invalid_keyword, :filename,
16
- :parser_info
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) && !chunk[/\A#{Regexp.escape(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).tokenize
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
@@ -29,23 +29,25 @@ module Riml
29
29
  "#{filename}:#{parser_info[:lineno]}"
30
30
  end
31
31
 
32
- # catches "descendant_of_#{some_class}?" methods
33
- # def descendant_of_call_node?
34
- # CallNode === self.parent_node
35
- # end
36
- DESCENDANT_OF_REGEX = /\Adescendant_of_(.*?)\?/
37
- def method_missing(method, *args, &blk)
38
- if method =~ DESCENDANT_OF_REGEX
39
- parent_node_name = $1.split('_').map(&:capitalize).join
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
@@ -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
- return ast unless @ast_rewriter
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
@@ -29,9 +29,9 @@ module Riml
29
29
  end
30
30
  end
31
31
 
32
- def file(path, filename)
32
+ def file(path, basename)
33
33
  return nil unless @cache[path]
34
- @cache[path][filename]
34
+ @cache[path][basename]
35
35
  end
36
36
 
37
37
  private
@@ -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
@@ -1,14 +1,21 @@
1
1
  module Riml
2
2
  class Walker
3
- def self.walk_node(node, method, walk_children = lambda {|n| true })
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) && walk_children.call(cur_node)
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
@@ -1,4 +1,4 @@
1
1
  module Riml
2
- # last changed: Oct. 14, 2013
3
- VERSION = [0,3,4]
2
+ # last changed: Oct. 20, 2013
3
+ VERSION = [0,3,5]
4
4
  end
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
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-16 00:00:00.000000000 Z
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: -1673750557717787658
154
+ hash: 3731001160727385716
154
155
  requirements: []
155
156
  rubyforge_project:
156
157
  rubygems_version: 1.8.25