sorcerer 0.0.1

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