riml 0.1.3
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/LICENSE +20 -0
- data/README.md +148 -0
- data/bin/riml +69 -0
- data/config/environment.rb +10 -0
- data/lib/ast_rewriter.rb +268 -0
- data/lib/class_map.rb +46 -0
- data/lib/compiler.rb +579 -0
- data/lib/constants.rb +280 -0
- data/lib/errors.rb +4 -0
- data/lib/grammar.y +485 -0
- data/lib/helper.rb +45 -0
- data/lib/lexer.rb +276 -0
- data/lib/nodes.rb +723 -0
- data/lib/parser.rb +2748 -0
- data/lib/walker.rb +15 -0
- data/version.rb +4 -0
- metadata +75 -0
data/lib/compiler.rb
ADDED
@@ -0,0 +1,579 @@
|
|
1
|
+
require File.expand_path('../nodes', __FILE__)
|
2
|
+
|
3
|
+
# visits AST nodes and translates them into VimL
|
4
|
+
module Riml
|
5
|
+
class Compiler
|
6
|
+
|
7
|
+
# Base abstract visitor
|
8
|
+
class Visitor
|
9
|
+
attr_accessor :propagate_up_tree
|
10
|
+
attr_reader :value
|
11
|
+
|
12
|
+
def initialize(options={})
|
13
|
+
@propagate_up_tree = options[:propagate_up_tree]
|
14
|
+
end
|
15
|
+
|
16
|
+
def visit(node)
|
17
|
+
node.compiled_output.clear
|
18
|
+
@value = compile(node)
|
19
|
+
@value << "\n" if node.force_newline and @value[-1] != "\n"
|
20
|
+
propagate_up_tree(node, @value)
|
21
|
+
end
|
22
|
+
|
23
|
+
def propagate_up_tree(node, output)
|
24
|
+
node.parent_node.compiled_output << output.to_s unless @propagate_up_tree == false || node.parent_node.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def visitor_for_node(node, params={})
|
28
|
+
Compiler.const_get("#{node.class.name}Visitor").new(params)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class IfNodeVisitor < Visitor
|
33
|
+
def compile(node)
|
34
|
+
condition_visitor = visitor_for_node(node.condition)
|
35
|
+
node.condition.parent_node = node
|
36
|
+
node.body.parent_node = node
|
37
|
+
node.compiled_output = "if ("
|
38
|
+
node.compiled_output << "!" if UnlessNode === node
|
39
|
+
|
40
|
+
node.condition.accept(condition_visitor)
|
41
|
+
node.compiled_output << ")\n"
|
42
|
+
node.body.accept(NodesVisitor.new(:propagate_up_tree => false))
|
43
|
+
|
44
|
+
node.body.compiled_output.each_line do |line|
|
45
|
+
node.compiled_output << (line =~ /else|elseif\n\Z/ ? line : node.indent + line)
|
46
|
+
end
|
47
|
+
node.compiled_output << "\n" unless node.compiled_output[-1] == "\n"
|
48
|
+
node.force_newline = true
|
49
|
+
node.compiled_output << "endif"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
UnlessNodeVisitor = IfNodeVisitor
|
54
|
+
|
55
|
+
class TernaryOperatorNodeVisitor < Visitor
|
56
|
+
def compile(node)
|
57
|
+
node.operands.each {|n| n.parent_node = node}
|
58
|
+
cond_visitor = visitor_for_node(node.condition)
|
59
|
+
node.condition.accept(cond_visitor)
|
60
|
+
node.compiled_output << ' ? '
|
61
|
+
if_expr_visitor = visitor_for_node(node.if_expr)
|
62
|
+
node.if_expr.accept(if_expr_visitor)
|
63
|
+
node.compiled_output << ' : '
|
64
|
+
else_expr_visitor = visitor_for_node(node.else_expr)
|
65
|
+
node.else_expr.accept(else_expr_visitor)
|
66
|
+
node.compiled_output
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class WhileNodeVisitor < Visitor
|
71
|
+
def compile(node)
|
72
|
+
node.condition.parent_node = node
|
73
|
+
node.compiled_output = "while ("
|
74
|
+
node.compiled_output << "!" if UntilNode === node
|
75
|
+
|
76
|
+
node.condition.accept visitor_for_node(node.condition)
|
77
|
+
node.compiled_output << ")\n"
|
78
|
+
|
79
|
+
node.body.accept NodesVisitor.new(:propagate_up_tree => false)
|
80
|
+
|
81
|
+
node.body.compiled_output.each_line do |line|
|
82
|
+
node.compiled_output << node.indent + line
|
83
|
+
end
|
84
|
+
node.compiled_output << "\n" unless node.compiled_output[-1] == "\n"
|
85
|
+
node.force_newline = true
|
86
|
+
node.compiled_output << "endwhile"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
UntilNodeVisitor = WhileNodeVisitor
|
91
|
+
|
92
|
+
class ElseNodeVisitor < Visitor
|
93
|
+
def compile(node)
|
94
|
+
node.compiled_output = "else\n"
|
95
|
+
expressions_visitor = NodesVisitor.new
|
96
|
+
node.expressions.parent_node = node
|
97
|
+
node.expressions.accept(expressions_visitor)
|
98
|
+
node.compiled_output
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class ElseifNodeVisitor < Visitor
|
103
|
+
def compile(node)
|
104
|
+
node.compiled_output = "elseif ("
|
105
|
+
node.condition.parent_node = node
|
106
|
+
node.condition.accept(visitor_for_node(node.condition))
|
107
|
+
node.compiled_output << ")\n"
|
108
|
+
node.expressions.parent_node = node
|
109
|
+
node.expressions.accept(visitor_for_node(node.expressions))
|
110
|
+
node.force_newline = true
|
111
|
+
node.compiled_output
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class NodesVisitor < Visitor
|
116
|
+
def compile(nodes)
|
117
|
+
nodes.each_with_index do |node, i|
|
118
|
+
visitor = visitor_for_node(node)
|
119
|
+
next_node = nodes.nodes[i+1]
|
120
|
+
node.parent_node = nodes
|
121
|
+
if ElseNode === next_node
|
122
|
+
node.force_newline = true
|
123
|
+
end
|
124
|
+
node.accept(visitor)
|
125
|
+
end
|
126
|
+
nodes.compiled_output
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class LiteralNodeVisitor < Visitor
|
131
|
+
def compile(node)
|
132
|
+
value = case node.value
|
133
|
+
when TrueClass
|
134
|
+
1
|
135
|
+
when FalseClass
|
136
|
+
0
|
137
|
+
when NilClass
|
138
|
+
'nil'
|
139
|
+
when Numeric
|
140
|
+
node.value
|
141
|
+
when String
|
142
|
+
StringNode === node ? string_surround(node) : node.value.dup
|
143
|
+
when Array
|
144
|
+
node.value.each {|n| n.parent_node = node}
|
145
|
+
'[' <<
|
146
|
+
node.value.map do |n|
|
147
|
+
n.accept(visitor_for_node(n))
|
148
|
+
n.compiled_output
|
149
|
+
end.join(', ') << ']'
|
150
|
+
when Hash
|
151
|
+
node.value.each {|k_n, v_n| k_n.parent_node, v_n.parent_node = [node, node]}
|
152
|
+
'{' <<
|
153
|
+
node.value.map do |k,v|
|
154
|
+
k.accept(visitor_for_node(k))
|
155
|
+
v.accept(visitor_for_node(v))
|
156
|
+
k.compiled_output << ': ' << v.compiled_output
|
157
|
+
end.join(', ') << '}'
|
158
|
+
end.to_s
|
159
|
+
|
160
|
+
node.compiled_output = value
|
161
|
+
end
|
162
|
+
|
163
|
+
private
|
164
|
+
def string_surround(string_node)
|
165
|
+
case string_node.type
|
166
|
+
when :d
|
167
|
+
'"' << string_node.value << '"'
|
168
|
+
when :s
|
169
|
+
"'" << string_node.value << "'"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
TrueNodeVisitor = LiteralNodeVisitor
|
175
|
+
FalseNodeVisitor = LiteralNodeVisitor
|
176
|
+
NilNodeVisitor = LiteralNodeVisitor
|
177
|
+
|
178
|
+
NumberNodeVisitor = LiteralNodeVisitor
|
179
|
+
StringNodeVisitor = LiteralNodeVisitor
|
180
|
+
RegexpNodeVisitor = LiteralNodeVisitor
|
181
|
+
ExLiteralNodeVisitor = LiteralNodeVisitor
|
182
|
+
|
183
|
+
ListNodeVisitor = LiteralNodeVisitor
|
184
|
+
DictionaryNodeVisitor = LiteralNodeVisitor
|
185
|
+
|
186
|
+
ScopeModifierLiteralNodeVisitor = LiteralNodeVisitor
|
187
|
+
FinishNodeVisitor = LiteralNodeVisitor
|
188
|
+
ContinueNodeVisitor = LiteralNodeVisitor
|
189
|
+
BreakNodeVisitor = LiteralNodeVisitor
|
190
|
+
|
191
|
+
class HeredocNodeVisitor < Visitor
|
192
|
+
def compile(node)
|
193
|
+
node.string_node.parent_node = node
|
194
|
+
node.string_node.accept(StringNodeVisitor.new)
|
195
|
+
node.compiled_output
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
class ReturnNodeVisitor < Visitor
|
200
|
+
def compile(node)
|
201
|
+
node.compiled_output = "return"
|
202
|
+
return (node.compiled_output << "\n") if node.expression.nil?
|
203
|
+
node.expression.parent_node = node
|
204
|
+
node.compiled_output << " "
|
205
|
+
node.expression.accept(visitor_for_node(node.expression))
|
206
|
+
node.force_newline = true
|
207
|
+
node.compiled_output
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# common visiting methods for nodes that are scope modified with variable
|
212
|
+
# name prefixes
|
213
|
+
class ScopedVisitor < Visitor
|
214
|
+
private
|
215
|
+
def set_modifier(node)
|
216
|
+
# Ex: n:myVariable = "override riml default scoping" compiles into:
|
217
|
+
# myVariable = "override riml default scoping"
|
218
|
+
node.scope_modifier = "" if node.scope_modifier == "n:"
|
219
|
+
return node.scope_modifier if node.scope_modifier
|
220
|
+
node.scope_modifier = scope_modifier_for_variable_name(node)
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
def scope_modifier_for_variable_name(node)
|
225
|
+
if node.scope
|
226
|
+
return "a:" if node.scope.argument_variable_names.include?(node.name)
|
227
|
+
return ""
|
228
|
+
end
|
229
|
+
"s:"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
class AssignNodeVisitor < ScopedVisitor
|
234
|
+
def compile(node)
|
235
|
+
node.lhs.accept(visitor_for_node(node.lhs, :propagate_up_tree => false))
|
236
|
+
node.compiled_output = "let #{node.lhs.compiled_output} #{node.operator} "
|
237
|
+
node.rhs.parent_node = node
|
238
|
+
node.rhs.accept(visitor_for_node(node.rhs))
|
239
|
+
node.compiled_output = "unlet! #{node.lhs.compiled_output}" if node.rhs.compiled_output == 'nil'
|
240
|
+
node.force_newline = true
|
241
|
+
node.compiled_output
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# scope_modifier, name
|
246
|
+
class GetVariableNodeVisitor < ScopedVisitor
|
247
|
+
def compile(node)
|
248
|
+
set_modifier(node)
|
249
|
+
|
250
|
+
if node.scope && node.scope.function? && (splat = node.scope.function.splat)
|
251
|
+
check_for_splat_match!(node, splat)
|
252
|
+
end
|
253
|
+
if node.question_existence?
|
254
|
+
node.compiled_output = %Q{exists("#{node.full_name}")}
|
255
|
+
else
|
256
|
+
node.compiled_output = "#{node.full_name}"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
private
|
261
|
+
def check_for_splat_match!(node, splat)
|
262
|
+
if node.name == splat[1..-1]
|
263
|
+
node.scope_modifier = "a:"
|
264
|
+
node.name = '000'
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
class GetSpecialVariableNodeVisitor < Visitor
|
270
|
+
def compile(node)
|
271
|
+
node.compiled_output = node.full_name
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
class GetCurlyBraceNameNodeVisitor < ScopedVisitor
|
276
|
+
def compile(node)
|
277
|
+
set_modifier(node)
|
278
|
+
node.compiled_output = node.scope_modifier
|
279
|
+
node.variable.parts.each do |part|
|
280
|
+
node.compiled_output <<
|
281
|
+
if part.interpolated?
|
282
|
+
part.value.accept(visitor_for_node(part.value))
|
283
|
+
"{#{part.value.compiled_output}}"
|
284
|
+
else
|
285
|
+
"#{part.value}"
|
286
|
+
end
|
287
|
+
end
|
288
|
+
node.compiled_output
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
class UnletVariableNodeVisitor < Visitor
|
293
|
+
def compile(node)
|
294
|
+
node.variables.each {|v| v.parent_node = node}
|
295
|
+
node.compiled_output = "unlet#{node.bang}"
|
296
|
+
node.variables.each do |var|
|
297
|
+
node.compiled_output << " "
|
298
|
+
var.accept(visitor_for_node(var))
|
299
|
+
end
|
300
|
+
node.compiled_output
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# operator, operands
|
305
|
+
class BinaryOperatorNodeVisitor < Visitor
|
306
|
+
def compile(node)
|
307
|
+
op1, op2 = node.operand1, node.operand2
|
308
|
+
op1_visitor, op2_visitor = visitor_for_node(op1), visitor_for_node(op2)
|
309
|
+
node.operands.each {|n| n.parent_node = node}
|
310
|
+
op1.accept(op1_visitor)
|
311
|
+
op2_visitor.propagate_up_tree = false
|
312
|
+
op2.accept(op2_visitor)
|
313
|
+
if node.ignorecase_capable_operator?(node.operator)
|
314
|
+
operator_suffix = "# "
|
315
|
+
else
|
316
|
+
operator_suffix = " "
|
317
|
+
end
|
318
|
+
node.compiled_output << " #{node.operator}#{operator_suffix}"
|
319
|
+
op2_visitor.propagate_up_tree = true
|
320
|
+
op2.accept(op2_visitor)
|
321
|
+
node.compiled_output
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
class UnaryOperatorNodeVisitor < Visitor
|
326
|
+
def compile(node)
|
327
|
+
node.compiled_output << node.operator
|
328
|
+
node.operand.parent_node = node
|
329
|
+
node.operand.accept(visitor_for_node(node.operand))
|
330
|
+
node.compiled_output
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
class DefNodeVisitor < Visitor
|
335
|
+
def visit(node)
|
336
|
+
setup_local_scope_for_descendants(node)
|
337
|
+
super
|
338
|
+
end
|
339
|
+
|
340
|
+
def compile(node)
|
341
|
+
modifier = node.scope ? nil : node.scope_modifier || 's:'
|
342
|
+
bang = node.bang
|
343
|
+
params = process_parameters!(node)
|
344
|
+
declaration = "function#{bang} #{modifier}"
|
345
|
+
declaration <<
|
346
|
+
if node.name.respond_to?(:variable)
|
347
|
+
node.name.accept(visitor_for_node(node.name))
|
348
|
+
node.name.compiled_output
|
349
|
+
else
|
350
|
+
node.name
|
351
|
+
end << "(#{params.join(', ')})"
|
352
|
+
declaration << (node.keyword ? " #{node.keyword}\n" : "\n")
|
353
|
+
node.expressions.parent_node = node
|
354
|
+
node.expressions.accept NodesVisitor.new(:propagate_up_tree => false)
|
355
|
+
|
356
|
+
body = ""
|
357
|
+
unless node.expressions.compiled_output.empty?
|
358
|
+
node.expressions.compiled_output.each_line do |line|
|
359
|
+
body << node.indent + line
|
360
|
+
end
|
361
|
+
end
|
362
|
+
node.compiled_output = declaration << body << "endfunction\n"
|
363
|
+
end
|
364
|
+
|
365
|
+
private
|
366
|
+
def setup_local_scope_for_descendants(node)
|
367
|
+
node.expressions.accept(EstablishScopeVisitor.new(:scope => node.to_scope))
|
368
|
+
end
|
369
|
+
|
370
|
+
def process_parameters!(node)
|
371
|
+
splat = node.splat
|
372
|
+
return node.parameters unless splat
|
373
|
+
node.parameters.map {|p| p == splat ? '...' : p}
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# helper to drill down to all descendants of a certain node and do
|
378
|
+
# something to all or a set of them
|
379
|
+
class DrillDownVisitor < Visitor
|
380
|
+
def walk_node!(node)
|
381
|
+
node.each do |expr|
|
382
|
+
expr.accept(self) if expr.respond_to?(:accept)
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
class EstablishScopeVisitor < DrillDownVisitor
|
388
|
+
def initialize(options)
|
389
|
+
@scope = options[:scope]
|
390
|
+
end
|
391
|
+
|
392
|
+
def visit(node)
|
393
|
+
establish_scope(node)
|
394
|
+
end
|
395
|
+
|
396
|
+
def establish_scope(node)
|
397
|
+
if node.scope
|
398
|
+
node.scope = node.scope.merge @scope
|
399
|
+
else
|
400
|
+
node.scope = @scope
|
401
|
+
end
|
402
|
+
walk_node!(node) if node.respond_to?(:each)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
class CallNodeVisitor < ScopedVisitor
|
407
|
+
def compile(node)
|
408
|
+
set_modifier(node) unless node.builtin_function?
|
409
|
+
node.compiled_output =
|
410
|
+
if node.name.respond_to?(:variable)
|
411
|
+
node.name.accept(visitor_for_node(node.name))
|
412
|
+
node.scope_modifier + node.name.compiled_output
|
413
|
+
elsif DictGetDotNode === node.name
|
414
|
+
node.name.accept(visitor_for_node(node.name))
|
415
|
+
node.name.compiled_output
|
416
|
+
else
|
417
|
+
"#{node.full_name}"
|
418
|
+
end
|
419
|
+
node.compiled_output << (node.no_parens_necessary? ? " " : "(")
|
420
|
+
node.arguments.each_with_index do |arg, i|
|
421
|
+
arg.parent_node = node
|
422
|
+
arg_visitor = visitor_for_node(arg)
|
423
|
+
arg.accept(arg_visitor)
|
424
|
+
node.compiled_output << ", " unless last_arg?(node.arguments, i)
|
425
|
+
end
|
426
|
+
node.compiled_output << ")" unless node.no_parens_necessary?
|
427
|
+
|
428
|
+
unless node.descendant_of_control_structure? ||
|
429
|
+
node.descendant_of_call_node? ||
|
430
|
+
node.descendant_of_list_node? ||
|
431
|
+
node.descendant_of_list_or_dict_get_node? ||
|
432
|
+
node.descendant_of_operator_node?
|
433
|
+
node.force_newline = true
|
434
|
+
end
|
435
|
+
node.compiled_output
|
436
|
+
end
|
437
|
+
|
438
|
+
private
|
439
|
+
def last_arg?(args, i)
|
440
|
+
args[i+1].nil?
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
class ExplicitCallNodeVisitor < CallNodeVisitor
|
445
|
+
def compile(node)
|
446
|
+
pre = "call "
|
447
|
+
post = super
|
448
|
+
node.compiled_output = pre << post
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
class ForNodeVisitor < Visitor
|
453
|
+
def compile(node)
|
454
|
+
if node.variables
|
455
|
+
node.variables.parent_node = node
|
456
|
+
node.variables.each {|v| v.scope_modifier = ""}
|
457
|
+
node.variables.accept(
|
458
|
+
visitor_for_node(
|
459
|
+
node.variables,
|
460
|
+
:propagate_up_tree => false
|
461
|
+
)
|
462
|
+
)
|
463
|
+
node.compiled_output = "for #{node.variables.compiled_output} in "
|
464
|
+
else
|
465
|
+
node.compiled_output = "for #{node.variable} in "
|
466
|
+
end
|
467
|
+
node.in_expression.parent_node = node
|
468
|
+
node.in_expression.force_newline = true
|
469
|
+
node.in_expression.accept(visitor_for_node(node.in_expression))
|
470
|
+
node.expressions.parent_node = node
|
471
|
+
node.expressions.accept(EstablishScopeVisitor.new(:scope => node.to_scope))
|
472
|
+
node.expressions.accept(NodesVisitor.new :propagate_up_tree => false)
|
473
|
+
body = node.expressions.compiled_output
|
474
|
+
body.each_line do |line|
|
475
|
+
node.compiled_output << node.indent + line
|
476
|
+
end
|
477
|
+
node.compiled_output << "endfor\n"
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
class TryNodeVisitor < Visitor
|
482
|
+
# try_block, catch_nodes, ensure_block
|
483
|
+
def compile(node)
|
484
|
+
try, catches, _ensure = node.try_block, node.catch_nodes, node.ensure_block
|
485
|
+
node.compiled_output = "try\n"
|
486
|
+
try.accept(visitor_for_node(try, :propagate_up_tree => false))
|
487
|
+
try.compiled_output.each_line do |line|
|
488
|
+
node.compiled_output << node.indent + line
|
489
|
+
end
|
490
|
+
|
491
|
+
catches.each do |c|
|
492
|
+
c.accept(visitor_for_node(c, :propagate_up_tree => false))
|
493
|
+
c.compiled_output.each_line do |line|
|
494
|
+
node.compiled_output << ( line =~ /\A\s*catch/ ? line : node.indent + line )
|
495
|
+
end
|
496
|
+
end if catches
|
497
|
+
|
498
|
+
if _ensure
|
499
|
+
node.compiled_output << "finally\n"
|
500
|
+
_ensure.accept(visitor_for_node(_ensure, :propagate_up_tree => false))
|
501
|
+
_ensure.compiled_output.each_line do |line|
|
502
|
+
node.compiled_output << node.indent + line
|
503
|
+
end
|
504
|
+
end
|
505
|
+
node.compiled_output << "endtry\n"
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
class CatchNodeVisitor < Visitor
|
510
|
+
# regexp, block
|
511
|
+
def compile(node)
|
512
|
+
regexp, exprs = node.regexp, node.expressions
|
513
|
+
node.compiled_output = "catch"
|
514
|
+
exprs.parent_node = node
|
515
|
+
if regexp
|
516
|
+
regexp.parent_node = node
|
517
|
+
node.compiled_output << " "
|
518
|
+
regexp.accept(visitor_for_node(regexp))
|
519
|
+
end
|
520
|
+
node.compiled_output << "\n"
|
521
|
+
exprs.accept(visitor_for_node(exprs))
|
522
|
+
node.compiled_output
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
class DictGetBracketNodeVisitor < Visitor
|
527
|
+
def compile(node)
|
528
|
+
node.dict.parent_node = node
|
529
|
+
node.keys.each do |k|
|
530
|
+
k.parent_node = node
|
531
|
+
end
|
532
|
+
node.dict.accept(visitor_for_node(node.dict))
|
533
|
+
node.keys.each do |key|
|
534
|
+
node.compiled_output << '['
|
535
|
+
key.accept(visitor_for_node(key))
|
536
|
+
node.compiled_output << "]"
|
537
|
+
end
|
538
|
+
node.compiled_output
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
542
|
+
class ListOrDictGetNodeVisitor < DictGetBracketNodeVisitor; end
|
543
|
+
|
544
|
+
class DictGetDotNodeVisitor < Visitor
|
545
|
+
def compile(node)
|
546
|
+
node.dict.parent_node = node
|
547
|
+
node.dict.accept(visitor_for_node(node.dict))
|
548
|
+
node.keys.each do |key|
|
549
|
+
node.compiled_output << ".#{key}"
|
550
|
+
end
|
551
|
+
node.compiled_output
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
class ClassDefinitionNodeVisitor < Visitor
|
556
|
+
def compile(node)
|
557
|
+
node.expressions.parent_node = node
|
558
|
+
node.expressions.accept(NodesVisitor.new)
|
559
|
+
node.compiled_output
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
class ObjectInstantiationNodeVisitor < Visitor
|
564
|
+
def compile(node)
|
565
|
+
node.call_node.parent_node = node
|
566
|
+
node.call_node.accept(visitor_for_node(node.call_node))
|
567
|
+
node.compiled_output
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
# compiles nodes into output code
|
572
|
+
def compile(root_node)
|
573
|
+
root_visitor = NodesVisitor.new
|
574
|
+
root_node.accept(root_visitor)
|
575
|
+
root_node.compiled_output
|
576
|
+
end
|
577
|
+
|
578
|
+
end
|
579
|
+
end
|