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 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