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/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