sorcerer 0.0.1 → 0.0.2

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/README.textile CHANGED
@@ -1,2 +1,39 @@
1
1
  h1. Sorcerer -- Recovering the Source
2
2
 
3
+ p. Sorcerer will generate Ruby code from a Ripper-like abstract syntax
4
+ tree (i.e. S-Expressions).
5
+
6
+ p. Sorcerer is targetted mainly at small snippets of Ruby code,
7
+ expressable in a single line. Longer examples may be re-sourced, but
8
+ they will be rendered in a single line format.
9
+
10
+ h2. Limitations
11
+
12
+ Sorcerer is only testing on Ruby 1.9.
13
+
14
+ bq. <em>Technically, Sorcerer should work on Ruby 1.8, but since Ripper is
15
+ 1.9 I've only tried it on that platform.</em>
16
+
17
+ h2. Examples
18
+
19
+ <pre style="background: LightGray">
20
+ sexp = [:binary,
21
+ [:var_ref, [:@ident, "a", [1, 0]]],
22
+ :+,
23
+ [:var_ref, [:@ident, "b", [1, 4]]]]
24
+ puts Sorcerer.source(sexp)
25
+ </pre>
26
+
27
+ will generate
28
+
29
+ <pre style="background: LightGray">
30
+ a + b
31
+ </pre>
32
+
33
+ Ripper may be used to produce the s-expressions used by Sorcerer. The following will produce the same output.
34
+
35
+ <pre style="background: LightGrey">
36
+ sexp = Ripper::SexpBuilder.new("a + b").parse
37
+ puts Sorcerer.source(sexp)
38
+ </pre>
39
+
data/Rakefile CHANGED
@@ -10,18 +10,9 @@ rescue Exception
10
10
  nil
11
11
  end
12
12
 
13
- module Config
14
- PROJ = 'sorcerer'
15
- RUBY = 'ruby19'
16
-
17
- BASE_RDOC_OPTIONS = [
18
- '--line-numbers', '--inline-source',
19
- '--main' , 'README.rdoc',
20
- '--title', 'Rake -- Ruby Make'
21
- ]
22
- end
23
-
24
- PKG_VERSION = '0.0.1'
13
+ PROJ = 'sorcerer'
14
+ RUBY = 'ruby19'
15
+ PKG_VERSION = '0.0.2'
25
16
 
26
17
  PKG_FILES = FileList[
27
18
  'README.textile',
@@ -32,20 +23,25 @@ PKG_FILES = FileList[
32
23
  'test/**/*.rb',
33
24
  ]
34
25
 
26
+ BASE_RDOC_OPTIONS = [
27
+ '--line-numbers', '--inline-source',
28
+ '--main' , 'README.rdoc',
29
+ '--title', 'Rake -- Ruby Make'
30
+ ]
35
31
 
36
32
  task :default => :test
37
33
 
38
34
  # Modify the TestTask to allow running ruby19 for the tests
39
35
  class Ruby19TestTask < Rake::TestTask
40
36
  def ruby(*args)
41
- sh "#{Config::RUBY} #{args.join(' ')}"
37
+ sh "#{RUBY} #{args.join(' ')}"
42
38
  end
43
39
  end
44
40
 
45
41
  Ruby19TestTask.new(:test) do |t|
46
42
  t.warning = true
47
43
  t.verbose = false
48
- t.test_files = FileList["test/#{Config::PROJ}/*_test.rb"]
44
+ t.test_files = FileList["test/#{PROJ}/*_test.rb"]
49
45
  end
50
46
 
51
47
  if ! defined?(Gem)
@@ -61,9 +57,10 @@ else
61
57
  s.files = PKG_FILES.to_a
62
58
  s.require_path = 'lib' # Use these for libraries.
63
59
  s.has_rdoc = true
64
- s.rdoc_options = Config::BASE_RDOC_OPTIONS
60
+ s.rdoc_options = BASE_RDOC_OPTIONS
65
61
  s.author = "Jim Weirich"
66
62
  s.email = "jim.weirich@gmail.com"
63
+ s.rubyforge_project = 'sorcerer'
67
64
  s.homepage = "http://github.com/jimweirich/sorcerer"
68
65
  end
69
66
 
data/lib/sorcerer.rb CHANGED
@@ -1 +1,10 @@
1
- require 'sorcerer/sorcerer'
1
+ module Sorcerer
2
+ # Generate the source code for teh given Ripper S-Expression.
3
+ def Sorcerer.source(sexp, debug=false)
4
+ Sorcerer::Resource.new(sexp, debug).source
5
+ end
6
+ end
7
+
8
+ require 'sorcerer/resource'
9
+ require 'sorcerer/subexpression'
10
+
@@ -0,0 +1,712 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ripper'
4
+
5
+ module Sorcerer
6
+ class Resource
7
+ class NoHandlerError < StandardError
8
+ end
9
+
10
+ def initialize(sexp, debug=false)
11
+ @sexp = sexp
12
+ @source = ''
13
+ @debug = debug
14
+ @word_level = 0
15
+ end
16
+
17
+ def source
18
+ resource(@sexp)
19
+ @source
20
+ end
21
+
22
+ def resource(sexp)
23
+ return unless sexp
24
+ handler = Handlers[sexp.first]
25
+ raise NoHandlerError.new(sexp.first) unless handler
26
+ if @debug
27
+ puts "----------------------------------------------------------"
28
+ pp sexp
29
+ end
30
+ handler.call(self, sexp)
31
+ end
32
+
33
+ def handle_block(sexp)
34
+ resource(sexp[1]) # Arguments
35
+ if ! void?(sexp[2])
36
+ emit(" ")
37
+ resource(sexp[2]) # Statements
38
+ end
39
+ emit(" ")
40
+ end
41
+
42
+ def opt_parens(sexp)
43
+ emit(" ") unless sexp.first == :arg_paren || sexp.first == :paren
44
+ resource(sexp)
45
+ end
46
+
47
+ def emit(string)
48
+ puts "EMITTING '#{string}'" if @debug
49
+ @source << string
50
+ end
51
+
52
+ def nyi(sexp)
53
+ raise "Handler for #{sexp.first} not implemented (#{sexp.inspect})"
54
+ end
55
+
56
+ def emit_separator(sep, first)
57
+ emit(sep) unless first
58
+ false
59
+ end
60
+
61
+ def params(normal_args, default_args, rest_args, unknown, block_arg)
62
+ first = true
63
+ if normal_args
64
+ normal_args.each do |sx|
65
+ first = emit_separator(", ", first)
66
+ resource(sx)
67
+ end
68
+ end
69
+ if default_args
70
+ default_args.each do |sx|
71
+ first = emit_separator(", ", first)
72
+ resource(sx[0])
73
+ emit("=")
74
+ resource(sx[1])
75
+ end
76
+ end
77
+ if rest_args
78
+ first = emit_separator(", ", first)
79
+ resource(rest_args)
80
+ end
81
+ if block_arg
82
+ first = emit_separator(", ", first)
83
+ resource(block_arg)
84
+ end
85
+ end
86
+
87
+ def words(marker, sexp)
88
+ emit("%#{marker}{") if @word_level == 0
89
+ @word_level += 1
90
+ if sexp[1] != [:qwords_new] && sexp[1] != [:words_new]
91
+ resource(sexp[1])
92
+ emit(" ")
93
+ end
94
+ resource(sexp[2])
95
+ @word_level -= 1
96
+ emit("}") if @word_level == 0
97
+ end
98
+
99
+ VOID_STATEMENT = [:stmts_add, [:stmts_new], [:void_stmt]]
100
+ VOID_BODY = [:body_stmt, VOID_STATEMENT, nil, nil, nil]
101
+
102
+ def void?(sexp)
103
+ sexp.nil? ||
104
+ sexp == VOID_STATEMENT ||
105
+ sexp == VOID_BODY
106
+ end
107
+
108
+ NYI = lambda { |src, sexp| src.nyi(sexp) }
109
+ DBG = lambda { |src, sexp| pp(sexp) }
110
+ NOOP = lambda { |src, sexp| }
111
+ SPACE = lambda { |src, sexp| src.emit(" ") }
112
+ PASS1 = lambda { |src, sexp| src.resource(sexp[1]) }
113
+ PASS2 = lambda { |src, sexp| src.resource(sexp[2]) }
114
+ EMIT1 = lambda { |src, sexp| src.emit(sexp[1]) }
115
+
116
+ Handlers = {
117
+ # parser keywords
118
+
119
+ :BEGIN => lambda { |src, sexp|
120
+ src.emit("BEGIN {")
121
+ unless src.void?(sexp[1])
122
+ src.emit(" ")
123
+ src.resource(sexp[1])
124
+ end
125
+ src.emit(" }")
126
+ },
127
+ :END => lambda { |src, sexp|
128
+ src.emit("END {")
129
+ unless src.void?(sexp[1])
130
+ src.emit(" ")
131
+ src.resource(sexp[1])
132
+ end
133
+ src.emit(" }")
134
+ },
135
+ :alias => lambda { |src, sexp|
136
+ src.emit("alias ")
137
+ src.resource(sexp[1])
138
+ src.emit(" ")
139
+ src.resource(sexp[2])
140
+ },
141
+ :alias_error => NYI,
142
+ :aref => lambda { |src, sexp|
143
+ src.resource(sexp[1])
144
+ src.emit("[")
145
+ src.resource(sexp[2])
146
+ src.emit("]")
147
+ },
148
+ :aref_field => lambda { |src, sexp|
149
+ src.resource(sexp[1])
150
+ src.emit("[")
151
+ src.resource(sexp[2])
152
+ src.emit("]")
153
+ },
154
+ :arg_ambiguous => NYI,
155
+ :arg_paren => lambda { |src, sexp|
156
+ src.emit("(")
157
+ src.resource(sexp[1]) if sexp[1]
158
+ src.emit(")")
159
+ },
160
+ :args_add => lambda { |src, sexp|
161
+ src.resource(sexp[1])
162
+ if sexp[1].first != :args_new
163
+ src.emit(", ")
164
+ end
165
+ src.resource(sexp[2])
166
+ },
167
+ :args_add_block => lambda { |src, sexp|
168
+ src.resource(sexp[1])
169
+ if sexp[2]
170
+ if sexp[1].first != :args_new
171
+ src.emit(", ")
172
+ end
173
+ if sexp[2]
174
+ src.emit("&")
175
+ src.resource(sexp[2])
176
+ end
177
+ end
178
+ },
179
+ :args_add_star => lambda { |src, sexp|
180
+ src.resource(sexp[1])
181
+ if sexp[1].first != :args_new
182
+ src.emit(", ")
183
+ end
184
+ src.emit("*")
185
+ src.resource(sexp[2])
186
+ },
187
+ :args_new => NOOP,
188
+ :args_prepend => NYI,
189
+ :array => lambda { |src, sexp|
190
+ src.emit("[")
191
+ src.resource(sexp[1])
192
+ src.emit("]")
193
+ },
194
+ :assign => lambda { |src, sexp|
195
+ src.resource(sexp[1])
196
+ src.emit(" = ")
197
+ src.resource(sexp[2])
198
+ },
199
+ :assign_error => NYI,
200
+ :assoc_new => lambda { |src, sexp|
201
+ src.resource(sexp[1])
202
+ src.emit(" => ")
203
+ src.resource(sexp[2])
204
+ },
205
+ :assoclist_from_args => lambda { |src, sexp|
206
+ first = true
207
+ sexp[1].each do |sx|
208
+ src.emit(", ") unless first
209
+ first = false
210
+ src.resource(sx)
211
+ end
212
+ },
213
+ :bare_assoc_hash => lambda { |src, sexp|
214
+ first = true
215
+ sexp[1].each do |sx|
216
+ src.emit(", ") unless first
217
+ first = false
218
+ src.resource(sx)
219
+ end
220
+ },
221
+ :begin => lambda { |src, sexp|
222
+ src.emit("begin")
223
+ src.resource(sexp[1])
224
+ src.emit("end")
225
+ },
226
+ :binary => lambda { |src, sexp|
227
+ src.resource(sexp[1])
228
+ src.emit(" #{sexp[2]} ")
229
+ src.resource(sexp[3])
230
+ },
231
+ :block_var => lambda { |src, sexp|
232
+ src.emit(" |")
233
+ src.resource(sexp[1])
234
+ src.emit("|")
235
+ },
236
+ :block_var_add_block => NYI,
237
+ :block_var_add_star => NYI,
238
+ :blockarg => lambda { |src, sexp|
239
+ src.emit("&")
240
+ src.resource(sexp[1])
241
+ },
242
+ :body_stmt => lambda { |src, sexp|
243
+ src.resource(sexp[1]) # Main Body
244
+ src.emit("; ")
245
+ src.resource(sexp[2]) # Rescue
246
+ src.resource(sexp[4]) # Ensure
247
+ },
248
+ :brace_block => lambda { |src, sexp|
249
+ src.emit(" {")
250
+ src.handle_block(sexp)
251
+ src.emit("}")
252
+ },
253
+ :break => lambda { |src, sexp|
254
+ src.emit("break")
255
+ src.emit(" ") unless sexp[1] == [:args_new]
256
+ src.resource(sexp[1])
257
+ },
258
+ :call => lambda { |src, sexp|
259
+ src.resource(sexp[1])
260
+ src.emit(sexp[2])
261
+ src.resource(sexp[3])
262
+ },
263
+ :case => lambda { |src, sexp|
264
+ src.emit("case ")
265
+ src.resource(sexp[1])
266
+ src.emit(" ")
267
+ src.resource(sexp[2])
268
+ src.emit(" end")
269
+ },
270
+ :class => lambda { |src, sexp|
271
+ src.emit("class ")
272
+ src.resource(sexp[1])
273
+ if ! src.void?(sexp[2])
274
+ src.emit " < "
275
+ src.resource(sexp[2])
276
+ end
277
+ src.emit("; ")
278
+ src.resource(sexp[3]) unless src.void?(sexp[3])
279
+ src.emit("end")
280
+ },
281
+ :class_name_error => NYI,
282
+ :command => lambda { |src, sexp|
283
+ src.resource(sexp[1])
284
+ src.emit(" ")
285
+ src.resource(sexp[2])
286
+ },
287
+ :command_call => NYI,
288
+ :const_path_field => lambda { |src, sexp|
289
+ src.resource(sexp[1])
290
+ src.emit("::")
291
+ src.resource(sexp[2])
292
+ },
293
+ :const_path_ref => lambda { |src, sexp|
294
+ src.resource(sexp[1])
295
+ src.emit("::")
296
+ src.resource(sexp[2])
297
+ },
298
+ :const_ref => PASS1,
299
+ :def => lambda { |src, sexp|
300
+ src.emit("def ")
301
+ src.resource(sexp[1])
302
+ src.opt_parens(sexp[2])
303
+ src.resource(sexp[3])
304
+ src.emit("end")
305
+ },
306
+ :defined => lambda { |src, sexp|
307
+ src.emit("defined?(")
308
+ src.resource(sexp[1])
309
+ src.emit(")")
310
+ },
311
+ :defs => NYI,
312
+ :do_block => lambda { |src, sexp|
313
+ src.emit(" do")
314
+ src.handle_block(sexp)
315
+ src.emit("end")
316
+ },
317
+ :dot2 => lambda { |src, sexp|
318
+ src.resource(sexp[1])
319
+ src.emit("..")
320
+ src.resource(sexp[2])
321
+ },
322
+ :dot3 => lambda { |src, sexp|
323
+ src.resource(sexp[1])
324
+ src.emit("...")
325
+ src.resource(sexp[2])
326
+ },
327
+ :dyna_symbol => lambda { |src, sexp|
328
+ src.emit(':"')
329
+ src.resource(sexp[1])
330
+ src.emit('"')
331
+ },
332
+ :else => lambda { |src, sexp|
333
+ src.emit(" else ")
334
+ src.resource(sexp[1])
335
+ },
336
+ :elsif => lambda { |src, sexp|
337
+ src.emit(" elsif ")
338
+ src.resource(sexp[1])
339
+ src.emit(" then ")
340
+ src.resource(sexp[2])
341
+ src.resource(sexp[3])
342
+ },
343
+ :ensure => lambda { |src, sexp|
344
+ src.emit("ensure ")
345
+ if sexp[1]
346
+ src.resource(sexp[1])
347
+ src.emit("; ") unless src.void?(sexp[1])
348
+ end
349
+ },
350
+ :excessed_comma => NYI,
351
+ :fcall => PASS1,
352
+ :field => lambda { |src, sexp|
353
+ src.resource(sexp[1])
354
+ src.emit(sexp[2])
355
+ src.resource(sexp[3])
356
+ },
357
+ :for => lambda { |src, sexp|
358
+ src.emit("for ")
359
+ src.resource(sexp[1])
360
+ src.emit(" in ")
361
+ src.resource(sexp[2])
362
+ src.emit(" do ")
363
+ unless src.void?(sexp[3])
364
+ src.resource(sexp[3])
365
+ src.emit(" ")
366
+ end
367
+ src.emit("end")
368
+ },
369
+ :hash => lambda { |src, sexp|
370
+ src.emit("{")
371
+ src.resource(sexp[1])
372
+ src.emit("}")
373
+ },
374
+ :if => lambda { |src, sexp|
375
+ src.emit("if ")
376
+ src.resource(sexp[1])
377
+ src.emit(" then ")
378
+ src.resource(sexp[2])
379
+ src.resource(sexp[3])
380
+ src.emit(" end")
381
+ },
382
+ :if_mod => lambda { |src, sexp|
383
+ src.resource(sexp[2])
384
+ src.emit(" if ")
385
+ src.resource(sexp[1])
386
+ },
387
+ :ifop => lambda { |src, sexp|
388
+ src.resource(sexp[1])
389
+ src.emit(" ? ")
390
+ src.resource(sexp[2])
391
+ src.emit(" : ")
392
+ src.resource(sexp[3])
393
+ },
394
+ :lambda => lambda { |src, sexp|
395
+ src.emit("->")
396
+ src.resource(sexp[1])
397
+ src.emit(" {")
398
+ if ! src.void?(sexp[2])
399
+ src.emit(" ")
400
+ src.resource(sexp[2])
401
+ end
402
+ src.emit(" ")
403
+ src.emit("}")
404
+ },
405
+ :magic_comment => NYI,
406
+ :massign => lambda { |src, sexp|
407
+ src.resource(sexp[1])
408
+ src.emit(" = ")
409
+ src.resource(sexp[2])
410
+ },
411
+ :method_add_arg => lambda { |src, sexp|
412
+ src.resource(sexp[1])
413
+ src.resource(sexp[2])
414
+ },
415
+ :method_add_block => lambda { |src, sexp|
416
+ src.resource(sexp[1])
417
+ src.resource(sexp[2])
418
+ },
419
+ :mlhs_add => lambda { |src, sexp|
420
+ src.resource(sexp[1])
421
+ src.emit(", ") unless sexp[1] == [:mlhs_new]
422
+ src.resource(sexp[2])
423
+ },
424
+ :mlhs_add_star => lambda { |src, sexp|
425
+ src.resource(sexp[1])
426
+ src.emit(", ") unless sexp[1] == [:mlhs_new]
427
+ src.emit("*")
428
+ src.resource(sexp[2])
429
+ },
430
+ :mlhs_new => NOOP,
431
+ :mlhs_paren => lambda { |src, sexp|
432
+ src.emit("(")
433
+ src.resource(sexp[1])
434
+ src.emit(")")
435
+ },
436
+ :module => lambda { |src, sexp|
437
+ src.emit("module ")
438
+ src.resource(sexp[1])
439
+ if src.void?(sexp[2])
440
+ src.emit("; ")
441
+ else
442
+ src.resource(sexp[2])
443
+ end
444
+ src.emit("end")
445
+ },
446
+ :mrhs_add => lambda { |src, sexp|
447
+ src.resource(sexp[1])
448
+ src.emit(", ")
449
+ src.resource(sexp[2])
450
+ },
451
+ :mrhs_add_star => lambda { |src, sexp|
452
+ src.resource(sexp[1])
453
+ src.emit(", ")
454
+ src.emit("*")
455
+ src.resource(sexp[2])
456
+ },
457
+ :mrhs_new => NYI,
458
+ :mrhs_new_from_args => PASS1,
459
+ :next => lambda { |src, sexp|
460
+ src.emit("next")
461
+ },
462
+ :opassign => lambda { |src, sexp|
463
+ src.resource(sexp[1])
464
+ src.emit(" ")
465
+ src.resource(sexp[2])
466
+ src.emit(" ")
467
+ src.resource(sexp[3])
468
+ },
469
+ :param_error => NYI,
470
+ :params => lambda { |src, sexp|
471
+ src.params(sexp[1], sexp[2], sexp[3], sexp[4], sexp[5])
472
+ },
473
+ :paren => lambda { |src, sexp|
474
+ src.emit("(")
475
+ src.resource(sexp[1])
476
+ src.emit(")")
477
+ },
478
+ :parse_error => NYI,
479
+ :program => PASS1,
480
+ :qwords_add => lambda { |src, sexp|
481
+ src.words("w", sexp)
482
+ },
483
+ :qwords_new => NOOP,
484
+ :redo => lambda { |src, sexp|
485
+ src.emit("redo")
486
+ },
487
+ :regexp_literal => lambda { |src, sexp|
488
+ src.emit("/")
489
+ src.resource(sexp[1])
490
+ src.emit("/")
491
+ },
492
+ :rescue => lambda { |src, sexp|
493
+ src.emit("rescue")
494
+ if sexp[1] # Exception list
495
+ src.emit(" ")
496
+ if sexp[1].first.kind_of?(Symbol)
497
+ src.resource(sexp[1])
498
+ else
499
+ src.resource(sexp[1].first)
500
+ end
501
+ src.emit(" => ")
502
+ src.resource(sexp[2])
503
+ end
504
+ src.emit(";")
505
+ if sexp[3] # Rescue Code
506
+ if src.void?(sexp[3])
507
+ src.emit(" ")
508
+ else
509
+ src.emit(" ")
510
+ src.resource(sexp[3])
511
+ src.emit("; ")
512
+ end
513
+ end
514
+ },
515
+ :rescue_mod => lambda { |src, sexp|
516
+ src.resource(sexp[2])
517
+ src.emit(" rescue ")
518
+ src.resource(sexp[1])
519
+ },
520
+ :rest_param => lambda { |src, sexp|
521
+ src.emit("*")
522
+ src.resource(sexp[1])
523
+ },
524
+ :retry => lambda { |src, sexp|
525
+ src.emit("retry")
526
+ },
527
+ :return => lambda { |src, sexp|
528
+ src.emit("return")
529
+ src.opt_parens(sexp[1])
530
+ },
531
+ :return0 => lambda { |src, sexp|
532
+ src.emit("return")
533
+ },
534
+ :sclass => NYI,
535
+ :stmts_add => lambda { |src, sexp|
536
+ if sexp[1] != [:stmts_new]
537
+ src.resource(sexp[1])
538
+ src.emit("; ")
539
+ end
540
+ src.resource(sexp[2])
541
+ },
542
+ :stmts_new => NOOP,
543
+ :string_add => lambda { |src, sexp|
544
+ src.resource(sexp[1])
545
+ src.resource(sexp[2])
546
+ },
547
+ :string_concat => lambda { |src, sexp|
548
+ src.resource(sexp[1])
549
+ src.emit(" ")
550
+ src.resource(sexp[2])
551
+ },
552
+ :string_content => NOOP,
553
+ :string_dvar => NYI,
554
+ :string_embexpr => lambda { |src, sexp|
555
+ src.emit('#{')
556
+ src.resource(sexp[1])
557
+ src.emit('}')
558
+ },
559
+ :string_literal => lambda { |src, sexp|
560
+ src.emit('"')
561
+ src.resource(sexp[1])
562
+ src.emit('"')
563
+ },
564
+ :super => lambda { |src, sexp|
565
+ src.emit("super")
566
+ src.opt_parens(sexp[1])
567
+ },
568
+ :symbol => lambda { |src, sexp|
569
+ src.emit(":")
570
+ src.resource(sexp[1])
571
+ },
572
+ :symbol_literal => PASS1,
573
+ :top_const_field => NYI,
574
+ :top_const_ref => NYI,
575
+ :unary => lambda { |src, sexp|
576
+ src.emit(sexp[1].to_s[0,1])
577
+ src.resource(sexp[2])
578
+ },
579
+ :undef => lambda { |src, sexp|
580
+ src.emit("undef ")
581
+ src.resource(sexp[1].first)
582
+ },
583
+ :unless => lambda { |src, sexp|
584
+ src.emit("unless ")
585
+ src.resource(sexp[1])
586
+ src.emit(" then ")
587
+ src.resource(sexp[2])
588
+ src.resource(sexp[3])
589
+ src.emit(" end")
590
+ },
591
+ :unless_mod => lambda { |src, sexp|
592
+ src.resource(sexp[2])
593
+ src.emit(" unless ")
594
+ src.resource(sexp[1])
595
+ },
596
+ :until => lambda { |src, sexp|
597
+ src.emit("until ")
598
+ src.resource(sexp[1])
599
+ src.emit(" do ")
600
+ src.resource(sexp[2])
601
+ src.emit(" end")
602
+ },
603
+ :until_mod => lambda { |src, sexp|
604
+ src.resource(sexp[2])
605
+ src.emit(" until ")
606
+ src.resource(sexp[1])
607
+ },
608
+ :var_alias => NYI,
609
+ :var_field => PASS1,
610
+ :var_ref => PASS1,
611
+ :void_stmt => NOOP,
612
+ :when => lambda { |src, sexp|
613
+ src.emit("when ")
614
+ src.resource(sexp[1])
615
+ src.emit("; ")
616
+ src.resource(sexp[2])
617
+ if sexp[3] && sexp[3].first == :when
618
+ src.emit(" ")
619
+ end
620
+ src.resource(sexp[3])
621
+ },
622
+ :while => lambda { |src, sexp|
623
+ src.emit("while ")
624
+ src.resource(sexp[1])
625
+ src.emit(" do ")
626
+ src.resource(sexp[2])
627
+ src.emit(" end")
628
+ },
629
+ :while_mod => lambda { |src, sexp|
630
+ src.resource(sexp[2])
631
+ src.emit(" while ")
632
+ src.resource(sexp[1])
633
+ },
634
+ :word_add => PASS2,
635
+ :word_new => NOOP,
636
+ :words_add => lambda { |src, sexp|
637
+ src.words("W", sexp)
638
+ },
639
+ :words_new => NOOP,
640
+ :xstring_add => lambda { |src, sexp|
641
+ src.resource(sexp[1])
642
+ src.resource(sexp[2])
643
+ },
644
+ :xstring_literal => lambda { |src, sexp|
645
+ src.emit('"')
646
+ src.resource(sexp[1])
647
+ src.emit('"')
648
+ },
649
+ :xstring_new => NOOP,
650
+ :yield => lambda { |src, sexp|
651
+ src.emit("yield")
652
+ src.opt_parens(sexp[1])
653
+ },
654
+ :yield0 => lambda { |src, sexp|
655
+ src.emit("yield")
656
+ },
657
+ :zsuper => lambda { |src, sexp|
658
+ src.emit("super")
659
+ },
660
+
661
+ # Scanner keywords
662
+
663
+ :@CHAR => NYI,
664
+ :@__end__ => NYI,
665
+ :@backref => NYI,
666
+ :@backtick => NYI,
667
+ :@comma => NYI,
668
+ :@comment => NYI,
669
+ :@const => EMIT1,
670
+ :@cvar => EMIT1,
671
+ :@embdoc => NYI,
672
+ :@embdoc_beg => NYI,
673
+ :@embdoc_end => NYI,
674
+ :@embexpr_beg => NYI,
675
+ :@embexpr_end => NYI,
676
+ :@embvar => NYI,
677
+ :@float => EMIT1,
678
+ :@gvar => EMIT1,
679
+ :@heredoc_beg => NYI,
680
+ :@heredoc_end => NYI,
681
+ :@ident => EMIT1,
682
+ :@ignored_nl => NYI,
683
+ :@int => EMIT1,
684
+ :@ivar => EMIT1,
685
+ :@kw => EMIT1,
686
+ :@label => NYI,
687
+ :@lbrace => NYI,
688
+ :@lbracket => NYI,
689
+ :@lparen => NYI,
690
+ :@nl => NYI,
691
+ :@op => EMIT1,
692
+ :@period => NYI,
693
+ :@qwords_beg => NYI,
694
+ :@rbrace => NYI,
695
+ :@rbracket => NYI,
696
+ :@regexp_beg => NYI,
697
+ :@regexp_end => NYI,
698
+ :@rparen => NYI,
699
+ :@semicolon => NYI,
700
+ :@sp => NYI,
701
+ :@symbeg => NYI,
702
+ :@tlambda => NYI,
703
+ :@tlambeg => NYI,
704
+ :@tstring_beg => NYI,
705
+ :@tstring_content => EMIT1,
706
+ :@tstring_end => NYI,
707
+ :@words_beg => NYI,
708
+ :@words_sep => NYI,
709
+ }
710
+ end
711
+
712
+ end