ripper2ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.markdown +10 -0
  3. data/lib/core_ext/array/flush.rb +5 -0
  4. data/lib/core_ext/hash/delete_at.rb +5 -0
  5. data/lib/core_ext/object/meta_class.rb +5 -0
  6. data/lib/core_ext/object/try.rb +12 -0
  7. data/lib/erb/stripper.rb +48 -0
  8. data/lib/highlighters/ansi.rb +29 -0
  9. data/lib/ripper/event_log.rb +45 -0
  10. data/lib/ripper/ruby_builder.rb +168 -0
  11. data/lib/ripper/ruby_builder/buffer.rb +34 -0
  12. data/lib/ripper/ruby_builder/events/args.rb +40 -0
  13. data/lib/ripper/ruby_builder/events/array.rb +71 -0
  14. data/lib/ripper/ruby_builder/events/assignment.rb +55 -0
  15. data/lib/ripper/ruby_builder/events/block.rb +80 -0
  16. data/lib/ripper/ruby_builder/events/call.rb +123 -0
  17. data/lib/ripper/ruby_builder/events/case.rb +17 -0
  18. data/lib/ripper/ruby_builder/events/const.rb +47 -0
  19. data/lib/ripper/ruby_builder/events/for.rb +13 -0
  20. data/lib/ripper/ruby_builder/events/hash.rb +24 -0
  21. data/lib/ripper/ruby_builder/events/identifier.rb +41 -0
  22. data/lib/ripper/ruby_builder/events/if.rb +37 -0
  23. data/lib/ripper/ruby_builder/events/lexer.rb +159 -0
  24. data/lib/ripper/ruby_builder/events/literal.rb +47 -0
  25. data/lib/ripper/ruby_builder/events/method.rb +21 -0
  26. data/lib/ripper/ruby_builder/events/operator.rb +23 -0
  27. data/lib/ripper/ruby_builder/events/statements.rb +50 -0
  28. data/lib/ripper/ruby_builder/events/string.rb +117 -0
  29. data/lib/ripper/ruby_builder/events/symbol.rb +22 -0
  30. data/lib/ripper/ruby_builder/events/while.rb +27 -0
  31. data/lib/ripper/ruby_builder/queue.rb +33 -0
  32. data/lib/ripper/ruby_builder/stack.rb +125 -0
  33. data/lib/ripper/ruby_builder/token.rb +91 -0
  34. data/lib/ripper2ruby.rb +1 -0
  35. data/lib/ruby.rb +28 -0
  36. data/lib/ruby/aggregate.rb +71 -0
  37. data/lib/ruby/alternation/args.rb +25 -0
  38. data/lib/ruby/alternation/hash.rb +25 -0
  39. data/lib/ruby/alternation/list.rb +19 -0
  40. data/lib/ruby/args.rb +36 -0
  41. data/lib/ruby/array.rb +27 -0
  42. data/lib/ruby/assignment.rb +32 -0
  43. data/lib/ruby/assoc.rb +17 -0
  44. data/lib/ruby/block.rb +42 -0
  45. data/lib/ruby/call.rb +34 -0
  46. data/lib/ruby/case.rb +30 -0
  47. data/lib/ruby/const.rb +49 -0
  48. data/lib/ruby/for.rb +18 -0
  49. data/lib/ruby/hash.rb +14 -0
  50. data/lib/ruby/if.rb +35 -0
  51. data/lib/ruby/list.rb +40 -0
  52. data/lib/ruby/literal.rb +45 -0
  53. data/lib/ruby/method.rb +19 -0
  54. data/lib/ruby/node.rb +47 -0
  55. data/lib/ruby/node/composite.rb +68 -0
  56. data/lib/ruby/node/conversions.rb +66 -0
  57. data/lib/ruby/node/position.rb +35 -0
  58. data/lib/ruby/node/source.rb +29 -0
  59. data/lib/ruby/node/text.rb +121 -0
  60. data/lib/ruby/node/traversal.rb +82 -0
  61. data/lib/ruby/operator.rb +49 -0
  62. data/lib/ruby/params.rb +41 -0
  63. data/lib/ruby/statements.rb +45 -0
  64. data/lib/ruby/string.rb +40 -0
  65. data/lib/ruby/symbol.rb +27 -0
  66. data/lib/ruby/token.rb +51 -0
  67. data/lib/ruby/while.rb +32 -0
  68. data/test/all.rb +3 -0
  69. data/test/builder/stack_test.rb +67 -0
  70. data/test/builder/text_test.rb +118 -0
  71. data/test/context_test.rb +54 -0
  72. data/test/erb_stripper_test.rb +29 -0
  73. data/test/fixtures/all.rb.src +150 -0
  74. data/test/fixtures/source_1.rb +16 -0
  75. data/test/fixtures/source_2.rb +1 -0
  76. data/test/fixtures/stuff.rb +371 -0
  77. data/test/fixtures/template.html.erb +22 -0
  78. data/test/fixtures/tmp.rb +6 -0
  79. data/test/lib_test.rb +92 -0
  80. data/test/lib_test_helper.rb +103 -0
  81. data/test/libs.txt +227 -0
  82. data/test/nodes/args_test.rb +100 -0
  83. data/test/nodes/array_test.rb +141 -0
  84. data/test/nodes/assignment_test.rb +49 -0
  85. data/test/nodes/block_test.rb +125 -0
  86. data/test/nodes/call_test.rb +229 -0
  87. data/test/nodes/case_test.rb +68 -0
  88. data/test/nodes/comments_test.rb +25 -0
  89. data/test/nodes/const_test.rb +46 -0
  90. data/test/nodes/conversions_test.rb +9 -0
  91. data/test/nodes/for_test.rb +34 -0
  92. data/test/nodes/hash_test.rb +71 -0
  93. data/test/nodes/heredoc_test.rb +202 -0
  94. data/test/nodes/identifier_test.rb +51 -0
  95. data/test/nodes/if_test.rb +100 -0
  96. data/test/nodes/literals_test.rb +63 -0
  97. data/test/nodes/method_test.rb +92 -0
  98. data/test/nodes/namespaces_test.rb +65 -0
  99. data/test/nodes/node_test.rb +74 -0
  100. data/test/nodes/nodes_test.rb +23 -0
  101. data/test/nodes/operator_test.rb +241 -0
  102. data/test/nodes/separators_test.rb +97 -0
  103. data/test/nodes/statements_test.rb +70 -0
  104. data/test/nodes/string_test.rb +92 -0
  105. data/test/nodes/symbol_test.rb +57 -0
  106. data/test/nodes/unless_test.rb +42 -0
  107. data/test/nodes/until_test.rb +61 -0
  108. data/test/nodes/while_test.rb +71 -0
  109. data/test/test_helper.rb +51 -0
  110. data/test/traversal_test.rb +53 -0
  111. metadata +163 -0
@@ -0,0 +1,159 @@
1
+ class Ripper
2
+ class RubyBuilder < Ripper::SexpBuilder
3
+ module Lexer
4
+ # unimplemented = :tlambda, :tlambeg
5
+
6
+ def on_parse_error(msg)
7
+ raise ParseError.new("#{filename}:#{position.row + 1}: #{msg}")
8
+ end
9
+
10
+ def on_param_error(param)
11
+ raise ParseError.new("#{filename}:#{position.row + 1}: syntax error, invalid parameter type: #{param.to_ruby}")
12
+ end
13
+
14
+ def on_ignored_nl(*args)
15
+ token = push(super)
16
+ on_heredoc_literal if end_heredoc?(token)
17
+ token
18
+ end
19
+
20
+ def on_nl(*args)
21
+ token = push(super)
22
+ on_heredoc_literal if end_heredoc?(token)
23
+ token
24
+ end
25
+
26
+ def on_comment(*args)
27
+ token = push(super)
28
+ on_heredoc_literal if end_heredoc?(token)
29
+ token
30
+ end
31
+
32
+ def on_sp(*args)
33
+ token = push(super)
34
+ on_heredoc_literal if end_heredoc?(token) # ripper counts \ + nl ("\\\n") as whitespace
35
+ token
36
+ end
37
+
38
+ def on_semicolon(*args)
39
+ push(super)
40
+ end
41
+
42
+ def on_period(*args)
43
+ push(super)
44
+ end
45
+
46
+ def on_comma(*args)
47
+ push(super)
48
+ end
49
+
50
+ def on_backtick(*args)
51
+ push(super)
52
+ end
53
+
54
+ def on_symbeg(*args)
55
+ push(super)
56
+ end
57
+
58
+ def on_tstring_beg(*args)
59
+ push(super)
60
+ end
61
+
62
+ def on_tstring_content(token)
63
+ push(super)
64
+ nil
65
+ end
66
+
67
+ def on_tstring_end(token)
68
+ push(super)
69
+ on_words_end(token) if closes_words?(token) # simulating on_words_end event
70
+ end
71
+
72
+ def on_qwords_beg(*args)
73
+ push(super)
74
+ end
75
+
76
+ def on_words_beg(*args)
77
+ push(super)
78
+ end
79
+
80
+ def on_words_sep(token)
81
+ token.each_char do |token|
82
+ case token
83
+ when "\n"
84
+ push([:@nl, token, position])
85
+ when /\s+/
86
+ push([:@sp, token, position])
87
+ else
88
+ push([:@words_end, token, position])
89
+ on_words_end(token) if closes_words?(token) # simulating on_words_end event
90
+ end
91
+ end
92
+ end
93
+
94
+ def on_embexpr_beg(*args)
95
+ push(super)
96
+ end
97
+
98
+ def on_embexpr_end(*args)
99
+ push(super)
100
+ end
101
+
102
+ def on_regexp_beg(*args)
103
+ push(super)
104
+ end
105
+
106
+ def on_regexp_end(*args)
107
+ push(super)
108
+ end
109
+
110
+ def on_lparen(*args)
111
+ push(super)
112
+ end
113
+
114
+ def on_rparen(*args)
115
+ push(super)
116
+ end
117
+
118
+ def on_lbracket(*args)
119
+ push(super)
120
+ end
121
+
122
+ def on_rbracket(*args)
123
+ push(super)
124
+ end
125
+
126
+ def on_lbrace(*args)
127
+ push(super)
128
+ end
129
+
130
+ def on_rbrace(*args)
131
+ push(super)
132
+ end
133
+
134
+ def on_op(*args)
135
+ push(super)
136
+ end
137
+
138
+ def on_embdoc(doc)
139
+ push([:@comment, doc, position])
140
+ end
141
+
142
+ def on_embdoc_beg(doc)
143
+ push([:@comment, doc, position])
144
+ end
145
+
146
+ def on_embdoc_end(doc)
147
+ push([:@comment, doc, position])
148
+ end
149
+
150
+ def on_embvar(*args)
151
+ push(super)
152
+ end
153
+
154
+ def on___end__(*args)
155
+ push(super)
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,47 @@
1
+ class Ripper
2
+ class RubyBuilder < Ripper::SexpBuilder
3
+ module Literal
4
+ @@tokens = %w(class module def do begin rescue ensure retry end
5
+ if unless then else elsif case when while until for in
6
+ not and or alias undef super yield return next redo break
7
+ defined? BEGIN END)
8
+
9
+ def on_kw(token)
10
+ if @@tokens.include?(token)
11
+ push(super) # these aren't passed to the next parser event, so we need them on the stack
12
+ else
13
+ push(super)
14
+ build_keyword(pop_token(:"@#{token}"))
15
+ end
16
+ end
17
+
18
+ def on_int(token)
19
+ push
20
+ Ruby::Integer.new(token, position, prolog)
21
+ end
22
+
23
+ def on_float(token)
24
+ push
25
+ Ruby::Float.new(token, position, prolog)
26
+ end
27
+
28
+ def on_dot2(left, right)
29
+ Ruby::Range.new(left, pop_token(:'@..'), right)
30
+ end
31
+
32
+ def on_dot3(left, right)
33
+ Ruby::Range.new(left, pop_token(:'@...'), right)
34
+ end
35
+
36
+ def on_CHAR(token)
37
+ push
38
+ Ruby::Char.new(token, position, prolog)
39
+ end
40
+
41
+ def on_label(label)
42
+ push
43
+ Ruby::Label.new(label, position, prolog)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,21 @@
1
+ class Ripper
2
+ class RubyBuilder < Ripper::SexpBuilder
3
+ module Method
4
+ def on_def(identifier, params, body)
5
+ rdelim = pop_token(:@end)
6
+ # the identifier might be a keyword, e.g. def class; end. could even be def def; end
7
+ identifier = pop_identifier(identifier.type, :right => rdelim) if identifier.is_a?(Ripper::RubyBuilder::Token)
8
+ ldelim = pop_token(:@def, :pass => true)
9
+ Ruby::Method.new(nil, nil, identifier, params, body, ldelim, rdelim)
10
+ end
11
+
12
+ def on_defs(target, separator, identifier, params, body)
13
+ rdelim = pop_token(:@end)
14
+ ldelim = pop_token(:@def, :pass => true)
15
+ identifier = pop_identifier(identifier.type, :left => ldelim, :right => rdelim) if identifier.is_a?(Ripper::RubyBuilder::Token)
16
+ separator = pop_token(:@period, :'@::')
17
+ Ruby::Method.new(target, separator, identifier, params, body, ldelim, rdelim)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ class Ripper
2
+ class RubyBuilder < Ripper::SexpBuilder
3
+ module Operator
4
+ def on_unary(operator, operand)
5
+ operator = pop_unary_operator(:pass => true, :right => operand) # e.g. not(1)
6
+ ldelim = pop_token(:@lparen, :left => operator)
7
+ rdelim = pop_token(:@rparen, :left => operator) if ldelim
8
+ Ruby::Unary.new(operator, operand, ldelim, rdelim) if operator
9
+ end
10
+
11
+ def on_binary(left, operator, right)
12
+ operator = pop_token(:"@#{operator}", :pass => true, :right => right)
13
+ Ruby::Binary.new(operator, left, right) if operator
14
+ end
15
+
16
+ def on_ifop(condition, left, right)
17
+ operators = pop_ternary_operator(:left => condition, :right => left),
18
+ pop_ternary_operator(:left => left, :right => right)
19
+ Ruby::IfOp.new(condition, left, right, operators)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,50 @@
1
+ class Ripper
2
+ class RubyBuilder < Ripper::SexpBuilder
3
+ module Statements
4
+ def on_program(statements)
5
+ program = statements.to_program(src, filename, pop_end_data)
6
+ program << Ruby::Token.new('', position, prolog) unless stack.buffer.empty?
7
+ program
8
+ end
9
+
10
+ def on_body_stmt(body, rescue_block, else_block, ensure_block)
11
+ statements = [rescue_block, else_block, ensure_block].compact
12
+ body = body.to_chained_block(nil, statements) unless statements.empty?
13
+ body
14
+ end
15
+
16
+ def on_paren(node)
17
+ node = Ruby::Statements.new(node) unless node.is_a?(Ruby::ArgsList) || node.is_a?(Ruby::Params)
18
+ node.rdelim ||= pop_token(:@rparen)
19
+ node.ldelim ||= pop_token(:@lparen)
20
+ node
21
+ end
22
+
23
+ def on_stmts_add(target, statement)
24
+ on_words_end if statement.is_a?(Ruby::Array) && !string_stack.empty? # simulating on_words_end event
25
+ target.elements << statement if statement
26
+ target
27
+ end
28
+
29
+ def on_stmts_new
30
+ Ruby::Statements.new
31
+ end
32
+
33
+ def on_void_stmt
34
+ nil
35
+ end
36
+
37
+ def on_var_ref(ref)
38
+ ref.instance_of?(Ruby::Identifier) ? Ruby::Variable.new(ref.token, ref.position, ref.prolog) : ref
39
+ end
40
+
41
+ def on_const_ref(const)
42
+ const
43
+ end
44
+
45
+ def on_var_field(field)
46
+ field
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,117 @@
1
+ class Ripper
2
+ class RubyBuilder < Ripper::SexpBuilder
3
+ module String
4
+ def on_string_concat(*strings)
5
+ Ruby::StringConcat.new(strings)
6
+ end
7
+
8
+ def on_string_literal(string)
9
+ string_stack.pop if string == string_stack.last
10
+ string.rdelim = pop_token(:@tstring_end) if string.respond_to?(:rdelim)
11
+ string
12
+ end
13
+
14
+ def on_string_add(string, content)
15
+ content = pop_string_content unless content
16
+ target = heredoc? ? string_stack.last : string
17
+ target << content
18
+ string
19
+ end
20
+
21
+ def on_string_content(*args)
22
+ if token = pop_token(:@heredoc_beg)
23
+ Ruby::HeredocBegin.new(token.token, token.position, token.prolog)
24
+ else
25
+ string_stack << Ruby::String.new(nil, pop_token(:@tstring_beg))
26
+ string_stack.last
27
+ end
28
+ end
29
+
30
+ def on_xstring_literal(string, type = :@tstring_end)
31
+ string_stack.pop if string == string_stack.last
32
+ string.rdelim = pop_token(type) if string.respond_to?(:rdelim)
33
+ string
34
+ end
35
+
36
+ def on_regexp_literal(string, rdelim)
37
+ on_xstring_literal(string, rdelim.type)
38
+ end
39
+
40
+ def on_xstring_new(*args)
41
+ if token = pop_token(:@heredoc_beg)
42
+ Ruby::HeredocBegin.new(token.token, token.position, token.prolog)
43
+ else
44
+ ldelim = pop(:@symbeg, :@backtick, :@regexp_beg, :max => 1, :pass => true).first
45
+ string_stack << build_xstring(ldelim)
46
+ string_stack.last
47
+ end
48
+ end
49
+
50
+ def on_xstring_add(string, content)
51
+ on_string_add(string, content)
52
+ end
53
+
54
+ def on_word_new
55
+ Ruby::String.new
56
+ end
57
+
58
+ def on_word_add(string, word)
59
+ word = pop_string_content unless word
60
+ string << word
61
+ end
62
+
63
+ def on_heredoc_literal(*args)
64
+ string_stack.flush.each { |heredoc| push([:@heredoc, heredoc]) }
65
+ end
66
+
67
+ def on_heredoc_new
68
+ string_stack << Ruby::Heredoc.new
69
+ end
70
+
71
+ def on_heredoc_beg(*args)
72
+ token = push(super)
73
+ on_heredoc_new
74
+ end
75
+
76
+ def on_heredoc_end(token)
77
+ string_stack.last.rdelim = Ruby::Token.new(token, position)
78
+ nil
79
+ end
80
+
81
+ def on_string_embexpr(expression)
82
+ expression.ldelim = pop_token(:@embexpr_beg)
83
+ expression.rdelim = pop_token(:@rbrace)
84
+ expression
85
+ end
86
+
87
+ def on_string_dvar(variable)
88
+ variable = Ruby::DelimitedVariable.new(variable.to_identifier)
89
+ ldelim = pop_token(:@embvar)
90
+ variable.ldelim = ldelim
91
+ variable
92
+ end
93
+
94
+ protected
95
+
96
+ def heredocs
97
+ @heredoc ||= []
98
+ end
99
+
100
+ def heredoc?
101
+ string_stack.last.is_a?(Ruby::Heredoc)
102
+ end
103
+
104
+ def end_heredoc?(token)
105
+ extra_heredoc_stage? && extra_heredoc_char?(token)
106
+ end
107
+
108
+ def extra_heredoc_stage?
109
+ heredoc? && !!string_stack.last.rdelim
110
+ end
111
+
112
+ def extra_heredoc_char?(token)
113
+ token && (token.newline? || token.comment? || token.token == "\\\n")
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,22 @@
1
+ class Ripper
2
+ class RubyBuilder < Ripper::SexpBuilder
3
+ module Symbol
4
+ def on_symbol_literal(symbol)
5
+ symbol = pop_identifier(symbol.type) if symbol.try(:known?) # happens w/ symbols that are also keywords, e.g. :class
6
+ symbol
7
+ end
8
+
9
+ def on_symbol(token)
10
+ push
11
+ token = pop_identifier(token.type) if token.try(:known?)
12
+ Ruby::Symbol.new(token, pop_token(:@symbeg))
13
+ end
14
+
15
+ def on_dyna_symbol(symbol)
16
+ string_stack.pop if symbol == string_stack.last
17
+ symbol.rdelim = pop_token(:@tstring_end)
18
+ symbol
19
+ end
20
+ end
21
+ end
22
+ end