riml 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|