sorcerer 0.0.1

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