riml 0.1.3

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