rogems 1.0.0

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.
@@ -0,0 +1,840 @@
1
+ require "Exceptions"
2
+ require "parser/ruby30"
3
+ # opt-in to most recent AST format:
4
+ Parser::Builders::Default.emit_lambda = true
5
+ Parser::Builders::Default.emit_procarg0 = true
6
+ Parser::Builders::Default.emit_encoding = true
7
+ Parser::Builders::Default.emit_index = true
8
+ Parser::Builders::Default.emit_arg_inside_procarg0 = true
9
+ Parser::Builders::Default.emit_forward_arg = true
10
+ Parser::Builders::Default.emit_kwargs = true
11
+ Parser::Builders::Default.emit_match_pattern = true
12
+
13
+ module RoGems
14
+ class CodeGenerator
15
+ attr_reader :output
16
+
17
+ def initialize(config, source)
18
+ @source = source
19
+ @debug_mode = !config["debugging"].nil? && config["debugging"] == true
20
+ @output = ""
21
+ @block = 0
22
+ @line = 0
23
+
24
+ @method_aliases = [:each, :each_with_index, :nil?, :to_s]
25
+ @dont_return_nodes = [:cvasgn, :ivasgn, :puts, :if, :while, :until, :for, :break]
26
+ @return_later_nodes = [:lvasgn, :class, :module, :def]
27
+ @literals = [:true, :false, :nil, :float, :int, :str, :sym, :array, :hash]
28
+ end
29
+
30
+ def destroy
31
+ @source = nil
32
+ @debug_mode = nil
33
+ @output = nil
34
+ @block = nil
35
+ @line = nil
36
+ @method_aliases = nil
37
+ @dont_return_nodes = nil
38
+ @return_later_nodes = nil
39
+ end
40
+
41
+ def generate
42
+ @output = ""
43
+ write(@debug_mode ? "-- " : "")
44
+ write("local ruby = require(game.ReplicatedStorage.Ruby.Runtime)")
45
+ self.newline
46
+ self.newline
47
+
48
+ root_node = Parser::Ruby30.parse(@source)
49
+ walk_ast(root_node)
50
+ if @debug_mode then
51
+ puts root_node
52
+ end
53
+ @output
54
+ end
55
+
56
+ def write(text)
57
+ @output << text
58
+ end
59
+
60
+ def writeln(text)
61
+ write(text)
62
+ self.newline
63
+ end
64
+
65
+ def newline()
66
+ write("\n")
67
+ write(" " * @block)
68
+ @line += 1
69
+ end
70
+
71
+ def block()
72
+ write(" " * @block)
73
+ @block += 1
74
+ end
75
+
76
+ def end()
77
+ @block -= 1
78
+ self.newline
79
+ write("end")
80
+ end
81
+
82
+ def walk_ast(node, *extra_data)
83
+ if node.is_a?(Parser::AST::Node)
84
+ case node.type
85
+ when :true, :false, :nil # literals
86
+ write(node.type.to_s)
87
+ when :float, :int
88
+ write(node.children[0].to_s)
89
+ when :str, :sym
90
+ content = node.children[0].to_s
91
+ write(self.quote_surround(content))
92
+ when :array
93
+ write("{")
94
+ node.children.each do |child|
95
+ walk_ast(child)
96
+ write(child != node.children.last ? ", " : "")
97
+ end
98
+ write("}")
99
+ when :hash
100
+ write("{")
101
+ self.block
102
+ self.newline
103
+ node.children.each do |pair|
104
+ walk_ast(pair)
105
+ if pair != node.children.last then
106
+ write(",")
107
+ self.newline
108
+ end
109
+ end
110
+ @block -= 1
111
+ self.newline
112
+ write("}")
113
+ when :pair
114
+ key, value = *node.children
115
+ is_lit = @literals.include?(key.type)
116
+ write(is_lit ? "[" : key.children[1].to_s)
117
+ if is_lit then
118
+ walk_ast(key)
119
+ write("]")
120
+ end
121
+ write(" = ")
122
+ walk_ast(value)
123
+ when :if # control flow
124
+ add_end = extra_data[0]
125
+ condition, block, elseif = *node.children
126
+ is_nextif = !block.nil? && block.type == :next
127
+ if is_nextif then
128
+ self.newline
129
+ end
130
+ write("if ")
131
+ write(is_nextif ? "not (" : "")
132
+ walk_ast(condition)
133
+ write(is_nextif ? ")" : "")
134
+ write(" then")
135
+ self.block
136
+ self.newline
137
+ walk_ast(block)
138
+
139
+ unless elseif.nil? then
140
+ @block -= 1
141
+ self.newline
142
+ write("else")
143
+ if elseif.type == :if then
144
+ walk_ast(elseif, false)
145
+ else
146
+ # @block -= 1
147
+ self.block
148
+ self.newline
149
+ walk_ast(elseif)
150
+ end
151
+ end
152
+ if (add_end.nil? && add_end != false) && !is_nextif then
153
+ self.end
154
+ end
155
+ when :while
156
+ condition, block = *node.children
157
+ write("while ")
158
+ walk_ast(condition)
159
+ write(" do")
160
+ self.block
161
+
162
+ walk_next_conditions(block)
163
+ self.end
164
+ when :until
165
+ condition, block = *node.children
166
+ write("repeat ")
167
+ self.block
168
+
169
+ walk_next_conditions(block)
170
+
171
+ @block -= 1
172
+ self.newline
173
+ write("until ")
174
+ walk_ast(condition)
175
+ when :irange
176
+ min, max = *node.children
177
+ walk_ast(min)
178
+ write(", ")
179
+ walk_ast(max)
180
+ when :for
181
+ symbol, iterable, block = *node.children
182
+ var_name = symbol.type == :mlhs ? symbol.children.map { |s| s.children[0].to_s }.join(", ") : symbol.children[0].to_s
183
+
184
+ write("for #{iterable.type == :irange ? var_name : "_, " + var_name}")
185
+ if iterable.type == :irange then
186
+ write(" = ")
187
+ walk_ast(iterable)
188
+ else
189
+ write(" in pairs(")
190
+ walk_ast(iterable)
191
+ write(")")
192
+ end
193
+ write(" do")
194
+ self.block
195
+
196
+ walk_next_conditions(block)
197
+ self.end
198
+ when :break
199
+ write("break")
200
+ when :and # conditionals
201
+ left_op, right_op = *node.children
202
+ write("(")
203
+ walk_ast(left_op)
204
+ write(") and (")
205
+ walk_ast(right_op)
206
+ write(")")
207
+ when :or
208
+ left_op, right_op = *node.children
209
+ write("(")
210
+ walk_ast(left_op)
211
+ write(") or (")
212
+ walk_ast(right_op)
213
+ write(")")
214
+ when :send # operations
215
+ send(node, *extra_data)
216
+ when :index
217
+ table, idx = *node.children
218
+ write("ruby.Array.at(")
219
+ walk_ast(table)
220
+ write(", ")
221
+ walk_ast(idx)
222
+ write(")")
223
+ when :module # module defs
224
+ module_def(node)
225
+ when :class # class defs
226
+ class_def(node)
227
+ when :begin # blocks
228
+ explicit_no_return = extra_data[0]
229
+ node.children.each do |child|
230
+ has_aliased = has_aliased_method?(child)
231
+ if !explicit_no_return && child == node.children.last && ((child.type == :send && !is_assignment?(child)) || child.children[1] != :puts) && !@dont_return_nodes.include?(child.type) && !@return_later_nodes.include?(child.type) && !has_aliased then
232
+ write("return ")
233
+ end
234
+ if child.is_a?(Parser::AST::Node)
235
+ walk_ast(child, *extra_data)
236
+ if child == node.children.last then
237
+ unless @return_later_nodes.include?(child.type) then return end
238
+ puts child
239
+ write("return #{}")
240
+ end
241
+ end
242
+ unless child == node.children.last then
243
+ self.newline
244
+ end
245
+ end
246
+ when :def # defs
247
+ set_args = extra_data[0]
248
+ def_name = node.children[0].to_s.gsub("?", "").gsub("!", "")
249
+ args = (set_args || node.children[1]).children
250
+ arg_list = args.map { |arg| arg.children[0] }.join(", ")
251
+ block = node.children[2]
252
+ class_name = extra_data[4]
253
+ if def_name == :initialize then return end
254
+
255
+ write("function #{class_name.nil? ? "" : class_name + ":"}#{def_name}(#{arg_list})")
256
+ self.block
257
+ self.newline
258
+ unless block.nil? then
259
+ if block.type != :begin && !is_assignment?(block) then
260
+ write("return ")
261
+ end
262
+ walk_ast(block, *extra_data)
263
+ end
264
+ self.end
265
+ when :block # lambdas
266
+ preceding, args_node, block = *node.children
267
+ has_aliased_method, aliased_methods = *has_aliased_method?(preceding)
268
+ args = args_node.children.map { |a| a.children[0].is_a?(Parser::AST::Node) ? a.children[0].children[0].to_s : a.children[0].to_s }
269
+ walk_ast(preceding, nil, nil, true, preceding.children.last, args)
270
+ if has_aliased_method then
271
+ aliased_methods.each { |a| handle_aliased_suffix(a, block) }
272
+ else
273
+ write("(function(#{args.join(", ")})")
274
+ self.block
275
+ self.newline
276
+ walk_ast(block)
277
+ self.end
278
+ write(")")
279
+ end
280
+ when :block_pass # passing fns
281
+ block = node.children[0]
282
+ walk_ast(block)
283
+ when :masgn # multiple assignment
284
+ self.multiple_assign(node)
285
+ when :op_asgn # op assignment
286
+ name_node, op, val = *node.children
287
+ if @debug_mode then
288
+ walk_ast(name_node, true, true)
289
+ write(" = ")
290
+ walk_ast(name_node, true, true)
291
+ write(" #{op.to_s} ")
292
+ else
293
+ walk_ast(name_node, true, true)
294
+ write(" #{op.to_s}= ")
295
+ end
296
+ if val.is_a?(Parser::AST::Node)
297
+ walk_ast(val, *extra_data)
298
+ else
299
+ write(val.children[0].to_s)
300
+ end
301
+ when :lvasgn, :gvasgn # local var assignment
302
+ name, val = *node.children
303
+ write((node.type == :lvasgn ? "local " : "") + (node.type == :gvasgn ? name.gsub!("$", "") : name.to_s) + " = ")
304
+ if val.is_a?(Parser::AST::Node) then
305
+ walk_ast(val, *extra_data)
306
+ else
307
+ write(val.children[0].to_s)
308
+ end
309
+ when :cvasgn
310
+ class_name = extra_data[0]
311
+ self.instancevar_assign(node, "#{class_name}.")
312
+ when :ivasgn
313
+ var_name = node.children[0].to_s.gsub("@", "")
314
+ readers, writers, accessors = *extra_data
315
+ readers.map! { |n| (n.is_a?(String) ? n : n.children[2].children[0]).to_s }
316
+ writers.map! { |n| (n.is_a?(String) ? n : n.children[2].children[0]).to_s }
317
+ accessors.map! { |n| (n.is_a?(String) ? n : n.children[2].children[0]).to_s }
318
+ location = self.get_v_location_name(var_name, readers, writers, accessors)
319
+ self.instancevar_assign(node, location)
320
+ when :lvar # variable indexing
321
+ self.index_var(node)
322
+ when :const
323
+ write(node.children[1].to_s)
324
+ else
325
+ warn("unhandled ast node: #{node.type}")
326
+ end
327
+ elsif node.is_a?(Symbol) then
328
+ sym = check_operator(node.to_s)
329
+ write(sym)
330
+ end
331
+ @last_line = @line
332
+ end
333
+
334
+ def handle_aliased_prefix(a, preceding, block_args)
335
+ case a
336
+ when :each, :each_with_index
337
+ use_pairs = a == :each_with_index || @debug_mode
338
+ v, i = *block_args
339
+ write("for ")
340
+ write(use_pairs ? "#{a == :each_with_index ? i.to_s : "_"}, " : "")
341
+ write("#{v.to_s} in ")
342
+ write(use_pairs ? "pairs" : "ruby.list")
343
+ write("(")
344
+ walk_ast(preceding)
345
+ write(") do")
346
+ self.block
347
+ self.newline
348
+ when :to_s
349
+ walk_ast(preceding)
350
+ write("tostring(")
351
+ when :nil?
352
+ walk_ast(preceding, true)
353
+ end
354
+ end
355
+
356
+ def handle_aliased_suffix(a, block)
357
+ case a
358
+ when :each, :each_with_index
359
+ walk_ast(block)
360
+ self.end
361
+ when :to_s
362
+ write(")")
363
+ when :nil?
364
+ write(" == nil")
365
+ end
366
+ end
367
+
368
+ def walk_next_conditions(node)
369
+ nextif_nodes = node.children.filter { |n| n.is_a?(Parser::AST::Node) && n.type == :if && n.children[1].is_a?(Parser::AST::Node) && n.children[1].type == :next }
370
+ node.children.each do |child|
371
+ self.walk_ast(child)
372
+ end
373
+ node.children.each do |child|
374
+ next if nextif_nodes.include?(child)
375
+ self.end
376
+ end
377
+ end
378
+
379
+ def is_guaranteed_function_call?(node, child, next_child)
380
+ op = is_op?(node.children[1].to_s)
381
+ is_assignment = is_assignment?(node)
382
+ !next_child.nil? && !op && child.is_a?(Symbol) && !is_assignment
383
+ end
384
+
385
+ def send(node, *extra_data)
386
+ if node.children[1] == :attr_accessor || node.children[1] == :attr_reader || node.children[1] == :attr_writer || node.children[1] == :include then return end
387
+
388
+ dont_emit_function_check, not_function, is_block, block_method, block_args = *extra_data
389
+ is_assignment = is_assignment?(node)
390
+ op = is_op?(node.children[1].to_s)
391
+ first_child = node.children[0]
392
+ is_send = !first_child.nil? && first_child.is_a?(Parser::AST::Node) && first_child.children.length > 0 && !first_child.children[0].nil? && first_child.children[0].is_a?(Parser::AST::Node) && (first_child.children[0].type == :send || first_child.children[0].type == :lvar)
393
+ child = node.children[node.children.length - 2]
394
+ next_child = node.children.last
395
+ guaranteed_function_call = is_guaranteed_function_call?(node, child, next_child)
396
+ do_function_check = !guaranteed_function_call && (dont_emit_function_check || false) == false && !is_assignment && !op && !first_child.nil? && (first_child.type == :lvar || is_send) && !(is_block && block_method == node.children[1])
397
+
398
+ if is_op?(next_child.to_s) && next_child == node.children.last then
399
+ walk_ast(next_child)
400
+ end
401
+ if do_function_check then
402
+ current_line = @output.split("\n")[@line]
403
+ if current_line.nil? && is_block.nil? then
404
+ write("local _ = ")
405
+ end
406
+ write("(type(")
407
+ end
408
+
409
+ is_aliased_method, aliased_methods = *has_aliased_method?(node, guaranteed_function_call, do_function_check)
410
+ if is_aliased_method then
411
+ aliased_methods.each { |a| handle_aliased_prefix(a, first_child, block_args) }
412
+ end
413
+
414
+ if !is_aliased_method || child == :puts then
415
+ idx = 1
416
+ node.children.each do |child|
417
+ next_child = node.children[idx] # 1 based
418
+ last_child = node.children[idx - 2]
419
+ guaranteed_function_call = (is_guaranteed_function_call?(node, child, next_child) || ((!is_block.nil? || is_block) && block_method == child)) || false
420
+
421
+ if child.is_a?(Parser::AST::Node) then
422
+ handle_send_child(node, child, idx, guaranteed_function_call, *extra_data)
423
+ elsif child == :puts then
424
+ args = [*node.children]
425
+ args.shift(2)
426
+ write("print(")
427
+ args.each do |a|
428
+ walk_ast(a, true)
429
+ if a != args.last then
430
+ write(", ")
431
+ end
432
+ end
433
+ write(")")
434
+ break
435
+ elsif child == :new then
436
+ write(".new(")
437
+ else
438
+ next if node.children[1] == :puts
439
+ is_var = !node.nil? && node.children[1].is_a?(Symbol) && !self.is_op?(node.children[1].to_s)
440
+ obj_asgn = !first_child.nil? && (first_child.type == :lvar || first_child.type == :send)
441
+ write_dot = nil
442
+
443
+ sym = child.to_s
444
+ str = check_operator(sym)
445
+ if guaranteed_function_call then
446
+ str.gsub!("?", "")
447
+ str.gsub!("!", "")
448
+ end
449
+
450
+ is_aliased_method, aliased_methods = *has_aliased_method?(child, guaranteed_function_call, do_function_check)
451
+ if is_var && obj_asgn && !is_aliased_method then
452
+ write_dot = (do_function_check || (not_function || false) == true || is_assignment) || (!guaranteed_function_call && !(next_child.nil? && not_function == false))
453
+ write(write_dot ? "." : ":")
454
+ end
455
+ unless is_aliased_method then
456
+ write(str)
457
+ end
458
+ if (is_var && obj_asgn && !do_function_check && !not_function && !guaranteed_function_call && !is_assignment && !op && !write_dot) then
459
+ args = [*node.children]
460
+ args.shift(2)
461
+ write("(#{args.join(", ")})")
462
+ end
463
+ if guaranteed_function_call && !write_dot && (is_block.nil? || !is_block) then
464
+ write("(")
465
+ self.walk_ast(next_child)
466
+ write(")")
467
+ break
468
+ end
469
+ end
470
+ idx += 1
471
+ end
472
+ end
473
+
474
+ if do_function_check then
475
+ write(") == \"function\" and ")
476
+ walk_ast(node, true, false)
477
+ write(" or ")
478
+ walk_ast(node, true, true)
479
+ write(")")
480
+ end
481
+ if node.children[1] == :new then
482
+ write(")")
483
+ end
484
+ if (is_block == false || is_block.nil?) && is_aliased_method && !is_send then
485
+ aliased_methods.each { |a| handle_aliased_suffix(a, child) }
486
+ end
487
+ end
488
+
489
+ def get_symbols_in(node)
490
+ if node.nil? then return [] end
491
+ descendants = []
492
+ if node.is_a?(Parser::AST::Node) then
493
+ node.children.each do |child|
494
+ if child.is_a?(Parser::AST::Node) && child.children.length > 0 then
495
+ descendants.push(*get_symbols_in(child))
496
+ else
497
+ descendants.push(child)
498
+ end
499
+ end
500
+ else
501
+ descendants.push(node)
502
+ end
503
+ descendants
504
+ end
505
+
506
+ def has_aliased_method?(node, guaranteed_function_call = false, do_function_check = false)
507
+ symbols = get_symbols_in(node)
508
+
509
+ aliased_methods = []
510
+ symbols.each do |sym|
511
+ is_aliased_method = @method_aliases.include?(sym)
512
+ if is_aliased_method then
513
+ aliased_methods.push(sym)
514
+ end
515
+ end
516
+
517
+ if aliased_methods.length > 0 && (guaranteed_function_call || !do_function_check) then
518
+ return true, aliased_methods.uniq
519
+ else
520
+ return false
521
+ end
522
+ end
523
+
524
+ def handle_send_child(node, child, idx, guaranteed_function_call, *extra_data)
525
+ next_child = node.children[idx] # idx is 1 based, not 0 based
526
+ last_child = node.children[idx - 2]
527
+ op = is_op?(node.children[1].to_s)
528
+
529
+ case child.type
530
+ when :str
531
+ walk_ast(child)
532
+ write(node.children.last != child ? ", " : "")
533
+ when :int, :float, :true, :false, :send, :lvar
534
+ walk_ast(child, *extra_data)
535
+ when :ivar
536
+ var_name = child.children[0].to_s.gsub("@", "")
537
+ readers, writers, accessors = *extra_data
538
+ readers.map! { |n| (n.is_a?(String) ? n : n.children[2].children[0]).to_s }
539
+ writers.map! { |n| (n.is_a?(String) ? n : n.children[2].children[0]).to_s }
540
+ accessors.map! { |n| (n.is_a?(String) ? n : n.children[2].children[0]).to_s }
541
+ location = self.get_v_location_name(var_name, readers, writers, accessors) || "private."
542
+ write(location + var_name)
543
+ when :const
544
+ walk_ast(child)
545
+ if next_child.is_a?(Symbol) && next_child != :new then
546
+ write(".")
547
+ end
548
+ when :begin
549
+ handle_send_child(child, child.children[0], idx, last_child == :puts)
550
+ when :block_pass
551
+
552
+ else
553
+ walk_ast(child, *extra_data)
554
+ # var_name = child.children[0].to_s.strip
555
+ # write(var_name)
556
+ end
557
+ end
558
+
559
+ def is_assignment?(node)
560
+ node.children[1].to_s.include?("=") || node.type == :lvasgn || node.type == :gvasgn
561
+ end
562
+
563
+ def primary_privates(inited_privates)
564
+ inited_privates.each do |var|
565
+ instancevar_assign(var)
566
+ unless var == inited_privates.last then
567
+ self.newline
568
+ end
569
+ end
570
+ end
571
+
572
+ def class_initializer(class_name, class_block, initializer = nil, parent = nil, readers = nil, writers = nil, accessors = nil, inited_privates = nil)
573
+ if initializer.nil? then
574
+ writeln(")")
575
+ end
576
+
577
+ args = []
578
+ unless initializer.nil? then
579
+ args = initializer.children.map do |child|
580
+ res = []
581
+ if child.is_a?(Parser::AST::Node) && child.type == :super
582
+ vals = child.children.map do |a|
583
+ sym = a.type == :str ? self.quote_surround(a.children[0]) : a.children[0]
584
+ end
585
+ vals.each { |c| res.push(c) }
586
+ res
587
+ end
588
+ end
589
+ end
590
+
591
+ if args.length > 0 then
592
+ self.newline
593
+ end
594
+
595
+ mixins = class_block.children.filter { |child| child.is_a?(Parser::AST::Node) && child.children[1] == :include }.map { |mixin| mixin.children[2].children[1].to_s }
596
+ writeln("local include = {#{mixins.join(", ")}}")
597
+ base_table = parent.nil? ? "{}" : "#{parent.children[1]}.new(#{args.compact.join(", ")})"
598
+ writeln("local idxMeta = setmetatable(#{class_name}, { __index = #{base_table} })")
599
+ writeln("idxMeta.__type = \"#{class_name}\"")
600
+
601
+ write("for ")
602
+ write(@debug_mode ? "_, " : "")
603
+ write("mixin in ")
604
+ write(@debug_mode ? "pairs" : "ruby.list")
605
+ write("(include) do")
606
+ @block -= 1
607
+ self.newline
608
+ @block += 1
609
+ self.block
610
+ write("for k, v in pairs(mixin) do")
611
+ @block -= 2
612
+ self.newline
613
+ @block += 2
614
+ self.block
615
+ write("idxMeta[k] = v")
616
+ self.end
617
+ self.end
618
+ self.newline
619
+
620
+
621
+ writeln("local self = setmetatable({}, { __index = idxMeta })")
622
+ writeln("self.attr_accessor = setmetatable({}, { __index = idxMeta.attr_accessor or {} })")
623
+ writeln("self.attr_reader = setmetatable({}, { __index = idxMeta.attr_reader or {} })")
624
+ writeln("self.attr_writer = setmetatable({}, { __index = idxMeta.attr_writer or {} })")
625
+ writeln("self.writable = {}")
626
+ writeln("self.private = {}")
627
+ self.newline
628
+
629
+ primary_privates(inited_privates)
630
+ unless initializer.nil? then
631
+ initializer_block = initializer.children[2]
632
+ walk_ast(initializer_block, readers, writers, accessors)
633
+ end
634
+
635
+ self.newline
636
+ self.newline
637
+ writeln("return setmetatable(self, {")
638
+ @block -= 1
639
+ self.block
640
+ writeln("__index = function(t, k)")
641
+ self.block
642
+ writeln("if not self.attr_reader[k] and not self.attr_accessor[k] and self.private[k] then")
643
+ @block -= 1
644
+ self.block
645
+ @block += 2
646
+ write("return nil")
647
+ self.end
648
+ self.newline
649
+ write("return self.attr_reader[k] or self.attr_accessor[k] or #{class_name}[k]")
650
+ self.end
651
+ writeln(",")
652
+
653
+ writeln("__newindex = function(t, k, v)")
654
+ @block -= 2
655
+ self.block
656
+ writeln("if t.writable[k] or self.writable[k] or idxMeta.writable[k] then")
657
+ @block += 1
658
+ self.block
659
+ @block -= 1
660
+ writeln("if self.attr_writer[k] then")
661
+ self.block
662
+ @block += 1
663
+ writeln("self.attr_writer[k] = v")
664
+ write("elseif self.attr_accessor[k] then")
665
+ @block += 1
666
+ self.newline
667
+ write("self.attr_accessor[k] = v")
668
+ self.end
669
+ @block -= 1
670
+ self.newline
671
+
672
+ write("else")
673
+ @block += 1
674
+ self.newline
675
+ write("error(\"Attempt to write to un-writable attribute '\"..k..\"'\")")
676
+ self.end
677
+ self.end
678
+ @block -= 1
679
+
680
+ self.newline
681
+ write("})")
682
+
683
+ self.end
684
+ @block -= 1
685
+ end
686
+
687
+ def get_class_initer_def(block)
688
+ initializer = block.children.filter { |def_node| def_node.type == :def && def_node.children[0] == :initialize }[0]
689
+ if initializer && initializer.children[0] == :initialize then
690
+ initializer_args = initializer.children[1]
691
+ arg_list = initializer_args.children.map { |arg| arg.children[0] }.join(", ")
692
+ write("#{arg_list})")
693
+ end
694
+ initializer
695
+ end
696
+
697
+ def class_def(node)
698
+ class_name = node.children[0].children[1].to_s
699
+ parent = node.children[1]
700
+ block = node.children[2]
701
+
702
+ write("--classdef")
703
+ self.newline
704
+ write("local #{class_name} = {} do")
705
+ self.newline
706
+ @block += 1
707
+ self.block
708
+ @block -= 2
709
+ self.block
710
+
711
+ stmts = block.children.filter { |stmt| stmt.type == :cvasgn }
712
+ stmts.each do |stmt|
713
+ walk_ast(stmt, class_name)
714
+ self.newline
715
+ end
716
+
717
+ added_initializer = false
718
+ write("function #{class_name}.new(")
719
+ @block += 1
720
+
721
+ unless block.nil? then
722
+ unless block.type == :begin || added_initializer then
723
+ class_initializer(class_name, block, nil, parent)
724
+ added_initializer = true
725
+ end
726
+ case block.type
727
+ when :begin
728
+ unless added_initializer then
729
+ readers = block.children.filter { |stmt| stmt.is_a?(Parser::AST::Node) && stmt.children[1] == :attr_reader }.map { |stmt| stmt.children[2].children[0].to_s }
730
+ writers = block.children.filter { |stmt| stmt.is_a?(Parser::AST::Node) && stmt.children[1] == :attr_writer }.map { |stmt| stmt.children[2].children[0].to_s }
731
+ accessors = block.children.filter { |stmt| stmt.is_a?(Parser::AST::Node) && stmt.children[1] == :attr_accessor }
732
+ inited_privates = block.children.filter { |stmt| stmt.is_a?(Parser::AST::Node) && stmt.type == :ivasgn }
733
+ initializer = get_class_initer_def(block)
734
+
735
+ class_initializer(class_name, block, initializer, parent, readers, writers, accessors, inited_privates)
736
+ added_initializer = true
737
+ end
738
+ when :send
739
+
740
+ when :cvasgn
741
+ walk_ast(node, class_name)
742
+ end
743
+ else
744
+ class_initializer(class_name, block, nil, parent)
745
+ end
746
+
747
+ @block += 1
748
+ self.end
749
+ end
750
+
751
+ def module_def(node)
752
+ module_name = node.children[0].children[1].to_s
753
+ block = node.children[1]
754
+
755
+ writeln("--moduledef")
756
+ writeln("local #{module_name} = {} do")
757
+ @block += 1
758
+ self.block
759
+ @block -= 1
760
+
761
+ unless block.nil? then
762
+ _, args, def_block = *block.children
763
+ new_block = block.updated(nil, ["#{module_name}:#{block.children[0].to_s}".to_sym, args, def_block])
764
+ walk_ast(new_block)
765
+ end
766
+
767
+ self.end
768
+ end
769
+
770
+ def quote_surround(s)
771
+ "\"#{s}\""
772
+ end
773
+
774
+ def instancevar_assign(node, location = nil)
775
+ name_node, val_node = *node.children
776
+ key = name_node.to_s.gsub("@", "")
777
+
778
+ write((location || "self.private.") + "#{key} = ")
779
+ walk_ast(val_node)
780
+ if location == "self.attr_accessor." || location == "self.attr_writer." then
781
+ self.newline
782
+ write("self.writable.#{key} = true")
783
+ end
784
+ end
785
+
786
+ def multiple_assign(node)
787
+ names_node, vals_node = *node.children
788
+
789
+ added_keyword = false
790
+ names_node.children.each do |name|
791
+ if name.type == :lvasgn && !added_keyword then
792
+ added_keyword = true
793
+ write("local ")
794
+ end
795
+ var_name = name.children[0].to_s
796
+ write((name.type == :gvasgn ? var_name.gsub!("$", "") : var_name) + (name == names_node.children.last ? "" : ", "))
797
+ end
798
+ write(" = ")
799
+
800
+ vals_node.children.each do |val|
801
+ write(val.children[0].to_s + (val == vals_node.children.last ? "" : ", "))
802
+ end
803
+ end
804
+
805
+ def get_v_location_name(var_name, readers, writers, accessors)
806
+ if !readers.nil? && readers.include?(var_name) then
807
+ "self.attr_reader."
808
+ elsif !writers.nil? && writers.include?(var_name) then
809
+ "self.attr_writer."
810
+ elsif !accessors.nil? && accessors.include?(var_name) then
811
+ "self.attr_accessor."
812
+ end
813
+ end
814
+
815
+ def is_op?(str)
816
+ operators = %w(+ - * / += -= *= /= %= **= % ** & | ^ > >= < <= == === != =~ !~ && || =)
817
+ operators.include?(str.strip) || is_unary_op?(str)
818
+ end
819
+
820
+ def is_unary_op?(str)
821
+ operators = %w(- !)
822
+ operators.include?(str.strip)
823
+ end
824
+
825
+ def check_operator(str)
826
+ if is_op?(str)
827
+ if str == "=~" || str == "!~" || str == "^" || str == "&" || str == "|" then
828
+ raise Exceptions::UnsupportedBitOpError.new
829
+ end
830
+ "#{is_unary_op?(str) ? "" : " "}#{str.gsub("!=", "~=").gsub("**", "^").gsub("===", "==").gsub("&&", "and").gsub("||", "or").gsub("!", "not")} "
831
+ else
832
+ str.gsub("=", " = ")
833
+ end
834
+ end
835
+
836
+ def index_var(node)
837
+ write(node.children[0].to_s.strip)
838
+ end
839
+ end
840
+ end