riml 0.2.9 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,13 +1,6 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- columnize (0.3.6)
5
- debugger (1.6.1)
6
- columnize (>= 0.3.1)
7
- debugger-linecache (~> 1.2.0)
8
- debugger-ruby_core_source (~> 1.2.3)
9
- debugger-linecache (1.2.0)
10
- debugger-ruby_core_source (1.2.3)
11
4
  minitest (2.5.1)
12
5
  racc (1.4.9)
13
6
  rake (10.0.4)
@@ -16,7 +9,6 @@ PLATFORMS
16
9
  ruby
17
10
 
18
11
  DEPENDENCIES
19
- debugger
20
12
  minitest (~> 2.5.1)
21
13
  racc
22
14
  rake
data/README.md CHANGED
@@ -171,21 +171,25 @@ Classes
171
171
 
172
172
  ###Basic Class
173
173
 
174
- class MyClass function! g:MyClassConstructor(data, otherData, ...)
174
+ function! s:SID()
175
+ return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
176
+ endfunction
177
+
178
+ class MyClass function! s:MyClassConstructor(data, otherData, ...)
175
179
  def initialize(data, otherData, *options) let myClassObj = {}
176
180
  self.data = data let myClassObj.data = a:data
177
181
  self.otherData = otherData let myClassObj.otherData = a:otherData
178
182
  self.options = options let myClassObj.options = a:000
179
- end let myClassObj.getData = function('g:MyClass_getData')
180
- let myClassObj.getOtherData = function('g:MyClass_getOtherData')
183
+ end let myClassObj.getData = function('<SNR>' . s:SID() . '_s:MyClass_getData')
184
+ let myClassObj.getOtherData = function('<SNR>' . s:SID() . '_s:MyClass_getOtherData')
181
185
  defm getData return myClassObj
182
186
  return self.data endfunction
183
187
  end
184
- function! g:MyClass_getdata() dict
188
+ function! <SID>s:MyClass_getdata() dict
185
189
  defm getOtherData return self.data
186
190
  return self.otherData endfunction
187
191
  end
188
- end function! g:MyClass_getOtherData() dict
192
+ end function! <SID>s:MyClass_getOtherData() dict
189
193
  return self.otherData
190
194
  endfunction
191
195
 
@@ -195,27 +199,40 @@ inside a class, use 'def'. To create an instance of this class, simply:
195
199
 
196
200
  obj = new MyClass('someData', 'someOtherData')
197
201
 
202
+ Classes have a default scope modifier of 's:'. That is, they cannot be instantiated
203
+ outside the script in which they are defined. In order to allow them to be instantiated
204
+ in any script file, you must declare the class with the explicit scope modifier of 'g:'.
205
+ For example:
206
+
207
+ class g:MyClass
208
+ ...
209
+ end
210
+
198
211
  In this basic example of a class, we see a \*splat variable. This is just a
199
212
  convenient way to refer to 'a:000' in the body of a function. Splat variables
200
213
  are optional parameters and get compiled to '...'.
201
214
 
202
215
  ###Class Inheritance
203
216
 
204
- class Translation function! g:TranslationConstructor(input)
217
+ function! s:SID()
218
+ return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
219
+ endfunction
220
+
221
+ class Translation function! s:TranslationConstructor(input)
205
222
  def initialize(input) let translationObj = {}
206
223
  self.input = input let translationObj.input = a:input
207
224
  end return translationObj
208
225
  end endfunction
209
226
 
210
- class FrenchToEnglishTranslation < Translation function! g:FrenchToEnglishTranslationConstructor(input)
227
+ class FrenchToEnglishTranslation < Translation function! s:FrenchToEnglishTranslationConstructor(input)
211
228
  defm translate let frenchToEnglishTranslationObj = {}
212
- if (self.input == "Bonjour!") let translationObj = g:TranslationConstructor(a:input)
229
+ if (self.input == "Bonjour!") let translationObj = s:TranslationConstructor(a:input)
213
230
  echo "Hello!" call extend(frenchToEnglishTranslationObj, translationObj)
214
- else let frenchToEnglishTranslationObj.translate = function('g:FrenchToEnglishTranslation_translate')
231
+ else let frenchToEnglishTranslationObj.translate = function('<SNR>' . s:SID() . '_s:FrenchToEnglishTranslation_translate')
215
232
  echo "Sorry, I don't know that word." return frenchToEnglishTranslationObj
216
233
  end endfunction
217
234
  end
218
- end function! g:FrenchToEnglishTranslation_translate() dict
235
+ end function! <SID>s:FrenchToEnglishTranslation_translate() dict
219
236
  if (self.input ==# "Bonjour!")
220
237
  translation = new echo "Hello!"
221
238
  \ FrenchToEnglishTranslation("Bonjour!") else
@@ -223,7 +240,7 @@ are optional parameters and get compiled to '...'.
223
240
  endif
224
241
  endfunction
225
242
 
226
- let s:translation = g:TranslationConstructor("Bonjour!")
243
+ let s:translation = s:TranslationConstructor("Bonjour!")
227
244
  call s:translation.translate()
228
245
  => "Hello!"
229
246
 
@@ -234,6 +251,14 @@ instances use the initialize function from 'Translation', and new instances must
234
251
  be provided with an 'input' argument on creation. Basically, if a class doesn't
235
252
  provide an initialize function, it uses its superclass's.
236
253
 
254
+ A base class and inheriting class can have different scope modifiers. For example, if you
255
+ had a script-local base class and wanted to extend it but have the extending class be
256
+ global, this is not a problem. Simply:
257
+
258
+ class g:GlobalClass < ScriptLocalClass
259
+ ...
260
+ end
261
+
237
262
  If you look at the last line of Riml in the previous example, you'll see that
238
263
  it doesn't use Vimscript's builtin 'call' function for calling the 'translate'
239
264
  method on the translation object. Riml can figure out when 'call' is necessary,
@@ -241,7 +266,11 @@ and will add it to the compiled Vimscript.
241
266
 
242
267
  ###Using 'super'
243
268
 
244
- class Car function! g:CarConstructor(make, model, color)
269
+ function! s:SID()
270
+ return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
271
+ endfunction
272
+
273
+ class Car function! s:CarConstructor(make, model, color)
245
274
  def initialize(make, model, color) let carObj = {}
246
275
  self.make = make let carObj.make = a:make
247
276
  self.model = model let carObj.model = a:model
@@ -249,16 +278,16 @@ and will add it to the compiled Vimscript.
249
278
  end endfunction
250
279
  end
251
280
 
252
- class HotRod < Car function! g:HotRodConstructor(make, model, color, topSpeed)
281
+ class HotRod < Car function! s:HotRodConstructor(make, model, color, topSpeed)
253
282
  def initialize(make, model, color, topSpeed) let hotRodObj = {}
254
283
  self.topSpeed = topSpeed let hotRodObj.topSpeed = a:topSpeed
255
- super(make, model, color) let carObj = g:CarConstructor(a:make, a:model, a:color)
284
+ super(make, model, color) let carObj = s:CarConstructor(a:make, a:model, a:color)
256
285
  end call extend(hotRodObj, carObj)
257
- let hotRodObj.drive = function('g:HotRod_drive')
286
+ let hotRodObj.drive = function('<SNR>' . s:SID() . '_s:HotRod_drive')
258
287
  defm drive return hotRodObj
259
288
  if self.topSpeed > 140 endfunction
260
289
  echo "Ahhhhhhh!"
261
- else function! g:HotRod_drive() dict
290
+ else function! <SID>s:HotRod_drive() dict
262
291
  echo "Nice" if self.topSpeed ># 140
263
292
  end echo "Ahhhhhhh!"
264
293
  end else
@@ -266,8 +295,9 @@ and will add it to the compiled Vimscript.
266
295
  endif
267
296
  newCar = new HotRod("chevy", "mustang", "red", 160) endfunction
268
297
  newCar.drive()
269
- let s:newCar = g:HotRodConstructor("chevy", "mustang", "red", 160)
298
+ let s:newCar = s:HotRodConstructor("chevy", "mustang", "red", 160)
270
299
  call s:newCar.drive()
300
+ => "Ahhhhhhh!"
271
301
 
272
302
  Use of 'super' is legal only within subclasses. If arguments are given, these arguments are sent
273
303
  to the superclass's function of the same name. If no arguments are given and parentheses are omitted,
data/lib/ast_rewriter.rb CHANGED
@@ -7,24 +7,31 @@ module Riml
7
7
  include Riml::Constants
8
8
 
9
9
  attr_accessor :ast
10
- attr_reader :classes, :rewritten_include_files
10
+ attr_reader :classes, :rewritten_included_and_sourced_files
11
11
 
12
12
  def initialize(ast = nil, classes = nil)
13
13
  @ast = ast
14
14
  @classes = classes || ClassMap.new
15
- @rewritten_include_files = {}
16
- # keeps track of which files included which, to prevent infinite loops
17
- @included_file_refs = {}
15
+ # Keeps track of filenames with their rewritten ASTs, to prevent rewriting
16
+ # the same AST more than once.
17
+ @rewritten_included_and_sourced_files = {}
18
+ # Keeps track of which filenames included/sourced which.
19
+ # ex: { nil => ["main.riml"], "main.riml" => ["lib1.riml", "lib2.riml"],
20
+ # "lib1.riml" => [], "lib2.riml" => [] }
21
+ @included_and_sourced_file_refs = Hash.new { |h, k| h[k] = [] }
18
22
  end
19
23
 
20
- def rewrite(from_file = nil)
21
- if from_file
22
- if rewritten_ast = rewritten_include_files[from_file]
23
- return rewritten_ast
24
- end
25
- rewrite_included_files!(from_file)
24
+ def rewrite(filename = nil, included = false)
25
+ if filename && (rewritten_ast = rewritten_included_and_sourced_files[filename])
26
+ return rewritten_ast
26
27
  end
27
28
  establish_parents(ast)
29
+ class_registry = RegisterDefinedClasses.new(ast, classes)
30
+ class_registry.rewrite_on_match
31
+ rewrite_included_and_sourced_files!(filename)
32
+ if filename && !included && add_SID_function?(filename)
33
+ add_SID_function!
34
+ end
28
35
  rewriters = [
29
36
  StrictEqualsComparisonOperator.new(ast, classes),
30
37
  VarEqualsComparisonOperator.new(ast, classes),
@@ -60,30 +67,33 @@ module Riml
60
67
  replace node if match?(node)
61
68
  end
62
69
 
63
- # We need to rewrite the included files before anything else. This is in
64
- # order to keep track of any classes defined in the included files (and
65
- # files included in those, etc...). We keep a cache of rewritten asts
66
- # because the 'riml_include'd files are parsed more than once. They're
67
- # parsed first before anything else, plus whenever the compiler visits a
68
- # 'compile_include' node in order to compile it on the spot.
69
- def rewrite_included_files!(from_file)
70
+ # We need to rewrite the included/sourced files before anything else. This is in
71
+ # order to keep track of any classes defined in the included and sourced files (and
72
+ # files included/sourced in those, etc...). We keep a cache of rewritten asts
73
+ # because the included/sourced files are parsed more than once. They're parsed
74
+ # first in this step, plus whenever the compiler visits a 'riml_include'/'riml_source'
75
+ # node in order to compile it on the spot.
76
+ def rewrite_included_and_sourced_files!(filename)
70
77
  old_ast = ast
71
78
  ast.children.each do |node|
72
- next unless RimlCommandNode === node && node.name == 'riml_include'
79
+ next unless RimlCommandNode === node
80
+ action = node.name == 'riml_include' ? 'include' : 'source'
81
+
73
82
  node.each_existing_file! do |file, fullpath|
74
- if from_file && @included_file_refs[file] == from_file
75
- msg = "#{from_file.inspect} can't include #{file.inspect}, as " \
76
- " #{file.inspect} already included #{from_file.inspect}"
77
- raise IncludeFileLoop, msg
78
- elsif from_file == file
83
+ if filename && @included_and_sourced_file_refs[file].include?(filename)
84
+ msg = "#{filename.inspect} can't #{action} #{file.inspect}, as " \
85
+ " #{file.inspect} already included/sourced #{filename.inspect}"
86
+ # IncludeFileLoop/SourceFileLoop
87
+ raise Riml.const_get("#{action.capitalize}FileLoop"), msg
88
+ elsif filename == file
79
89
  raise UserArgumentError, "#{file.inspect} can't include itself"
80
90
  end
81
- @included_file_refs[from_file] = file
91
+ @included_and_sourced_file_refs[filename] << file
82
92
  riml_src = File.read(fullpath)
83
93
  # recursively parse included files with this ast_rewriter in order
84
94
  # to pick up any classes that are defined there
85
- rewritten_ast = Parser.new.parse(riml_src, self, file)
86
- rewritten_include_files[file] = rewritten_ast
95
+ rewritten_ast = Parser.new.parse(riml_src, self, file, action == 'include')
96
+ rewritten_included_and_sourced_files[file] = rewritten_ast
87
97
  end
88
98
  end
89
99
  ensure
@@ -94,6 +104,53 @@ module Riml
94
104
  true
95
105
  end
96
106
 
107
+ # Add SID function if this is the main file and it has defined classes, or
108
+ # if it included other files and any one of those other files defined classes.
109
+ def add_SID_function?(filename)
110
+ return true if ast.children.grep(ClassDefinitionNode).any?
111
+ included_files = @included_and_sourced_file_refs[filename]
112
+ while included_files.any?
113
+ incs = []
114
+ included_files.each do |included_file|
115
+ if (ast = rewritten_included_and_sourced_files[included_file])
116
+ return true if ast.children.grep(ClassDefinitionNode).any?
117
+ end
118
+ incs.concat @included_and_sourced_file_refs[included_file]
119
+ end
120
+ included_files = incs
121
+ end
122
+ false
123
+ end
124
+
125
+ # :h <SID>
126
+ def add_SID_function!
127
+ fchild = ast.nodes.first
128
+ return false if DefNode === fchild && fchild.name == 'SID' && fchild.scope_modifier == 's:'
129
+ fn = DefNode.new('!', nil, 's:', 'SID', [], nil, Nodes.new([
130
+ ReturnNode.new(CallNode.new(nil, 'matchstr', [
131
+ CallNode.new(nil, 'expand', [StringNode.new('<sfile>', :s)]),
132
+ StringNode.new('<SNR>\zs\d\+\ze_SID$', :s)
133
+ ]
134
+ ))
135
+ ])
136
+ )
137
+ fn.parent = ast.nodes
138
+ establish_parents(fn)
139
+ ast.nodes.unshift fn
140
+ end
141
+
142
+ class RegisterDefinedClasses < AST_Rewriter
143
+ def match?(node)
144
+ ClassDefinitionNode === node
145
+ end
146
+
147
+ def replace(node)
148
+ n = node.dup
149
+ n.instance_variable_set("@registered_state", true)
150
+ classes[node.full_name] = n
151
+ end
152
+ end
153
+
97
154
  class StrictEqualsComparisonOperator < AST_Rewriter
98
155
  def match?(node)
99
156
  BinaryOperatorNode === node && node.operator == '==='
@@ -139,12 +196,15 @@ module Riml
139
196
  end
140
197
 
141
198
  def replace(node)
142
- classes[node.name] = node
199
+ classes[node.full_name] = node
143
200
 
201
+ RegisterPrivateFunctions.new(node, classes).rewrite_on_match
202
+ DefNodeToPrivateFunction.new(node, classes).rewrite_on_match
144
203
  InsertInitializeMethod.new(node, classes).rewrite_on_match
145
204
  constructor = node.constructor
146
- constructor.scope_modifier = 'g:' unless constructor.scope_modifier
147
205
  constructor.name = node.constructor_name
206
+ constructor.original_name = 'initialize'
207
+ constructor.scope_modifier = node.scope_modifier
148
208
  # set up dictionary variable at top of function
149
209
  dict_name = node.constructor_obj_name
150
210
  constructor.expressions.unshift(
@@ -155,6 +215,7 @@ module Riml
155
215
  ExtendObjectWithMethods.new(node, classes).rewrite_on_match
156
216
  SelfToDictName.new(dict_name).rewrite_on_match(constructor)
157
217
  SuperToSuperclassFunction.new(node, classes).rewrite_on_match
218
+ PrivateFunctionCallToPassObjExplicitly.new(node, classes).rewrite_on_match
158
219
 
159
220
  constructor.expressions.push(
160
221
  ReturnNode.new(GetVariableNode.new(nil, dict_name))
@@ -162,6 +223,87 @@ module Riml
162
223
  reestablish_parents(constructor)
163
224
  end
164
225
 
226
+ class RegisterPrivateFunctions < AST_Rewriter
227
+ def match?(node)
228
+ node.instance_of?(DefNode) && node.name != 'initialize'
229
+ end
230
+
231
+ def replace(node)
232
+ ast.private_function_names << node.name
233
+ end
234
+ end
235
+
236
+ class SelfToObjArgumentInPrivateFunction < AST_Rewriter
237
+ def initialize(ast, classes, class_node)
238
+ super(ast, classes)
239
+ @class_node = class_node
240
+ end
241
+
242
+ def match?(node)
243
+ return unless GetVariableNode === node && node.scope_modifier == nil && node.name == 'self'
244
+ return if node.parent.is_a?(DictGetDotNode) && node.parent.parent.is_a?(CallNode) &&
245
+ (@class_node.private_function_names & node.parent.keys).size == 1
246
+ # make sure we're not nested in a different function
247
+ n = node
248
+ until n.instance_of?(DefNode)
249
+ n = n.parent
250
+ end
251
+ n == ast
252
+ end
253
+
254
+ def replace(node)
255
+ node.name = @class_node.constructor_obj_name
256
+ node.scope_modifier = 'a:'
257
+ end
258
+ end
259
+
260
+ class DefNodeToPrivateFunction < AST_Rewriter
261
+ def match?(node)
262
+ return unless node.instance_of?(DefNode) && node.name != 'initialize'
263
+ node.private_function = true
264
+ end
265
+
266
+ def replace(node)
267
+ class_node = ast
268
+ class_name = class_node.name
269
+ node.scope_modifier = 's:'
270
+ node.name = "#{class_name}_#{node.name}"
271
+ node.sid = nil
272
+ node.keywords -= ['dict']
273
+ node.parameters.unshift(class_node.constructor_obj_name)
274
+ # rewrite `self` in function body to a:#{class_name}Obj
275
+ self_to_obj_argument = SelfToObjArgumentInPrivateFunction.new(node, classes, class_node)
276
+ self_to_obj_argument.rewrite_on_match
277
+ reestablish_parents(node)
278
+ end
279
+ end
280
+
281
+ class PrivateFunctionCallToPassObjExplicitly < AST_Rewriter
282
+ def match?(node)
283
+ CallNode === node && DictGetDotNode === node.name && node.name.dict.scope_modifier.nil? &&
284
+ node.name.dict.name == 'self' && (node.name.keys & ast.private_function_names).size == 1
285
+ end
286
+
287
+ def replace(node)
288
+ node.scope_modifier = 's:'
289
+ # find function that I'm in
290
+ n = node
291
+ until n.instance_of?(DefNode)
292
+ n = n.parent
293
+ end
294
+ if n.original_name == 'initialize'
295
+ node.arguments.unshift(GetVariableNode.new(nil, ast.constructor_obj_name))
296
+ elsif n.private_function
297
+ node.arguments.unshift(GetVariableNode.new('a:', ast.constructor_obj_name))
298
+ else
299
+ node.arguments.unshift(GetVariableNode.new(nil, 'self'))
300
+ end
301
+ func_name = node.name.keys.first
302
+ node.name = "#{ast.name}_#{func_name}"
303
+ reestablish_parents(node)
304
+ end
305
+ end
306
+
165
307
  class ExtendObjectWithMethods < AST_Rewriter
166
308
  def match?(node)
167
309
  DefMethodNode === node
@@ -177,10 +319,12 @@ module Riml
177
319
  node.remove
178
320
  def_node.original_name = def_node.name.dup
179
321
  def_node.name.insert(0, "#{ast.name}_")
322
+ def_node.sid = SIDNode.new
180
323
  reestablish_parents(def_node)
181
324
  extend_obj_with_methods(def_node)
182
325
  end
183
326
 
327
+ # Ex: `let dogObj.bark = function('<SNR>' . s:SID() . '_s:Dog_bark')`
184
328
  def extend_obj_with_methods(def_node)
185
329
  constructor = ast.constructor
186
330
  extension =
@@ -190,9 +334,23 @@ module Riml
190
334
  [def_node.original_name]
191
335
  ),
192
336
  CallNode.new(
193
- nil, 'function', [StringNode.new("#{def_node.scope_modifier}#{def_node.name}", :s)]
337
+ nil, 'function', [
338
+ BinaryOperatorNode.new(
339
+ '.',
340
+ [
341
+ BinaryOperatorNode.new(
342
+ '.',
343
+ [
344
+ StringNode.new('<SNR>', :s),
345
+ CallNode.new('s:', 'SID', []),
346
+ ]
347
+ ),
348
+ StringNode.new("_s:#{def_node.name}", :s)
349
+ ],
350
+ )
351
+ ],
194
352
  )
195
- )
353
+ )
196
354
  constructor.expressions << extension
197
355
  extension.parent = constructor.expressions
198
356
  end
@@ -223,11 +381,11 @@ module Riml
223
381
  def replace(class_node)
224
382
  if class_node.superclass?
225
383
  def_node = DefNode.new(
226
- '!', nil, "initialize", superclass_params, nil, Nodes.new([SuperNode.new([], false)])
384
+ '!', nil, nil, "initialize", superclass_params, nil, Nodes.new([SuperNode.new([], false)])
227
385
  )
228
386
  else
229
387
  def_node = DefNode.new(
230
- '!', nil, "initialize", [], nil, Nodes.new([])
388
+ '!', nil, nil, "initialize", [], nil, Nodes.new([])
231
389
  )
232
390
  end
233
391
  class_node.expressions.unshift(def_node)
@@ -235,7 +393,7 @@ module Riml
235
393
  end
236
394
 
237
395
  def superclass_params
238
- classes.superclass(ast.name).constructor.parameters
396
+ classes.superclass(ast.full_name).constructor.parameters
239
397
  end
240
398
 
241
399
  def recursive?
@@ -255,7 +413,13 @@ module Riml
255
413
  end
256
414
 
257
415
  def replace(constructor)
258
- superclass = classes.superclass(class_node.name)
416
+ unless class_node.superclass?
417
+ # TODO: raise error instead of aborting
418
+ abort "class #{class_node.full_name.inspect} called super in its " \
419
+ " initialize function, but it has no superclass."
420
+ end
421
+
422
+ superclass = classes.superclass(class_node.full_name)
259
423
  super_constructor = superclass.constructor
260
424
 
261
425
  set_var_node = AssignNode.new('=', GetVariableNode.new(nil, superclass.constructor_obj_name),
@@ -305,14 +469,15 @@ module Riml
305
469
  end
306
470
 
307
471
  def replace(node)
308
- func_scope = @function_node.scope_modifier
309
- superclass = classes[ast.superclass_name]
472
+ # TODO: check if class even has superclass before all this
473
+ func_scope = 's:'
474
+ superclass = classes[ast.superclass_full_name]
310
475
  while superclass && !superclass.has_function?(func_scope, superclass_func_name(superclass)) && superclass.superclass?
311
- superclass = classes[superclass.superclass_name]
476
+ superclass = classes[superclass.superclass_full_name]
312
477
  end
313
478
  if superclass.nil? || !superclass.has_function?(func_scope, superclass_func_name(superclass))
314
479
  raise Riml::UserFunctionNotFoundError,
315
- "super was called in class #{ast.name} in " \
480
+ "super was called in class #{ast.full_name} in " \
316
481
  "function #{@function_node.original_name}, but there are no " \
317
482
  "functions with this name in that class's superclass hierarchy."
318
483
  end
@@ -342,9 +507,21 @@ module Riml
342
507
  [super_func_name]
343
508
  ),
344
509
  CallNode.new(
345
- nil,
346
- 'function',
347
- [StringNode.new("g:#{super_func_name}", :s)]
510
+ nil, 'function', [
511
+ BinaryOperatorNode.new(
512
+ '.',
513
+ [
514
+ BinaryOperatorNode.new(
515
+ '.',
516
+ [
517
+ StringNode.new('<SNR>', :s),
518
+ CallNode.new('s:', 'SID', []),
519
+ ]
520
+ ),
521
+ StringNode.new("_s:#{super_func_name}", :s)
522
+ ],
523
+ )
524
+ ],
348
525
  )
349
526
  )
350
527
  ast.constructor.expressions << assign_node
@@ -359,7 +536,9 @@ module Riml
359
536
  end
360
537
 
361
538
  def replace(node)
362
- constructor_name = node.call_node.name
539
+ constructor_name = (node.call_node.scope_modifier ||
540
+ ClassDefinitionNode::DEFAULT_SCOPE_MODIFIER) +
541
+ node.call_node.name
363
542
  class_node = classes[constructor_name]
364
543
  call_node = node.call_node
365
544
  call_node.name = class_node.constructor_name