sorcerer 0.0.1 → 0.0.2

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