ripper_ruby_parser 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +76 -0
- data/Rakefile +24 -0
- data/lib/ripper_ruby_parser/parser.rb +18 -0
- data/lib/ripper_ruby_parser/sexp_ext.rb +14 -0
- data/lib/ripper_ruby_parser/sexp_handlers/arguments.rb +23 -0
- data/lib/ripper_ruby_parser/sexp_handlers/arrays.rb +15 -0
- data/lib/ripper_ruby_parser/sexp_handlers/assignment.rb +80 -0
- data/lib/ripper_ruby_parser/sexp_handlers/blocks.rb +49 -0
- data/lib/ripper_ruby_parser/sexp_handlers/conditionals.rb +64 -0
- data/lib/ripper_ruby_parser/sexp_handlers/hashes.rb +27 -0
- data/lib/ripper_ruby_parser/sexp_handlers/helper_methods.rb +49 -0
- data/lib/ripper_ruby_parser/sexp_handlers/literals.rb +83 -0
- data/lib/ripper_ruby_parser/sexp_handlers/loops.rb +11 -0
- data/lib/ripper_ruby_parser/sexp_handlers/method_calls.rb +47 -0
- data/lib/ripper_ruby_parser/sexp_handlers/methods.rb +38 -0
- data/lib/ripper_ruby_parser/sexp_handlers/operators.rb +41 -0
- data/lib/ripper_ruby_parser/sexp_handlers.rb +35 -0
- data/lib/ripper_ruby_parser/sexp_processor.rb +150 -0
- data/lib/ripper_ruby_parser/version.rb +3 -0
- data/lib/ripper_ruby_parser.rb +5 -0
- data/test/end_to_end/comparison_test.rb +56 -0
- data/test/end_to_end/lib_comparison_test.rb +29 -0
- data/test/end_to_end/test_comparison_test.rb +33 -0
- data/test/test_helper.rb +12 -0
- data/test/unit/parser_test.rb +623 -0
- data/test/unit/sexp_processor_test.rb +309 -0
- data/test/unit/version_test.rb +5 -0
- metadata +137 -0
data/README.rdoc
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
= RipperRubyParser
|
2
|
+
|
3
|
+
by Matijs van Zuijlen
|
4
|
+
|
5
|
+
http://www.github.com/mvz/ripper_ruby_parser
|
6
|
+
|
7
|
+
== Description
|
8
|
+
|
9
|
+
Parse with Ripper, produce sexps that are compatible with RubyParser.
|
10
|
+
|
11
|
+
== Features/Notes
|
12
|
+
|
13
|
+
* Drop-in replacement for RubyParser.
|
14
|
+
* Should handle 1.9 syntax gracefully.
|
15
|
+
* Only tested with MRI 1.9.3. Definitely does not work with the ripper gem for
|
16
|
+
MRI 1.8.
|
17
|
+
* Many edge cases are surely not yet taken care of (but hey, it's version
|
18
|
+
0.0.1).
|
19
|
+
|
20
|
+
== Install
|
21
|
+
|
22
|
+
* gem install ripper_ruby_parser
|
23
|
+
|
24
|
+
== Synopsis
|
25
|
+
|
26
|
+
Basic usage:
|
27
|
+
|
28
|
+
require 'ripper_ruby_parser'
|
29
|
+
|
30
|
+
parser = RipperRubyParser::Parser.new
|
31
|
+
result = parser.parse "puts 'Hello World'"
|
32
|
+
p result
|
33
|
+
# => s(:call, nil, :puts, s(:arglist, s(:str, "Hello World!")))
|
34
|
+
|
35
|
+
== Requirements
|
36
|
+
|
37
|
+
* Ruby 1.9.3. It may work with lower 1.9 versions. Let me know if it does.
|
38
|
+
* sexp_processor
|
39
|
+
|
40
|
+
== Hacking and contributing
|
41
|
+
|
42
|
+
If you want to send pull requests or patches, please:
|
43
|
+
|
44
|
+
* Make sure `rake test` runs without reporting any failures. If your code
|
45
|
+
breaks existing stuff, it won't get merged in.
|
46
|
+
* Add tests for your feature. Otherwise, I can't see if it works or if I
|
47
|
+
break it later.
|
48
|
+
* Make sure latest master merges cleanly with your branch. Things might
|
49
|
+
have moved around since you forked.
|
50
|
+
* Try not to include changes that are irrelevant to your feature in the
|
51
|
+
same commit.
|
52
|
+
|
53
|
+
== License
|
54
|
+
|
55
|
+
(The MIT License)
|
56
|
+
|
57
|
+
Copyright (c) 2012 Matijs van Zuijlen
|
58
|
+
|
59
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
60
|
+
a copy of this software and associated documentation files (the
|
61
|
+
'Software'), to deal in the Software without restriction, including
|
62
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
63
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
64
|
+
permit persons to whom the Software is furnished to do so, subject to
|
65
|
+
the following conditions:
|
66
|
+
|
67
|
+
The above copyright notice and this permission notice shall be
|
68
|
+
included in all copies or substantial portions of the Software.
|
69
|
+
|
70
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
71
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
72
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
73
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
74
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
75
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
76
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
namespace :test do
|
4
|
+
|
5
|
+
Rake::TestTask.new(:unit) do |t|
|
6
|
+
t.libs = ['lib']
|
7
|
+
t.test_files = FileList['test/unit/*_test.rb']
|
8
|
+
t.ruby_opts += ["-w"]
|
9
|
+
end
|
10
|
+
|
11
|
+
Rake::TestTask.new(:end_to_end) do |t|
|
12
|
+
t.libs = ['lib']
|
13
|
+
t.test_files = FileList['test/end_to_end/*_test.rb']
|
14
|
+
t.ruby_opts += ["-w"]
|
15
|
+
end
|
16
|
+
|
17
|
+
task :run => [:unit, :end_to_end]
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Alias to test:run'
|
22
|
+
task :test => 'test:run'
|
23
|
+
|
24
|
+
task :default => :test
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'ripper'
|
2
|
+
require 'ripper_ruby_parser/sexp_processor'
|
3
|
+
|
4
|
+
module RipperRubyParser
|
5
|
+
# Main parser class. Brings together Ripper and our
|
6
|
+
# RipperRubyParser::SexpProcessor.
|
7
|
+
class Parser
|
8
|
+
def initialize processor=SexpProcessor.new
|
9
|
+
@processor = processor
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse source
|
13
|
+
exp = Sexp.from_array(Ripper.sexp source)
|
14
|
+
@processor.process exp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RipperRubyParser
|
2
|
+
module SexpHandlers
|
3
|
+
module Arguments
|
4
|
+
def process_args_add_block exp
|
5
|
+
_, content, _ = exp.shift 3
|
6
|
+
s(:arglist, *handle_list_with_optional_splat(content))
|
7
|
+
end
|
8
|
+
|
9
|
+
def process_args_add_star exp
|
10
|
+
generic_add_star exp
|
11
|
+
end
|
12
|
+
|
13
|
+
def process_arg_paren exp
|
14
|
+
_, args = exp.shift 2
|
15
|
+
args = s() if args.nil?
|
16
|
+
unless args.first.is_a? Symbol
|
17
|
+
args.unshift :arglist
|
18
|
+
end
|
19
|
+
process(args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RipperRubyParser
|
2
|
+
module SexpHandlers
|
3
|
+
module Arrays
|
4
|
+
def process_array exp
|
5
|
+
_, elems = exp.shift 2
|
6
|
+
s(:array, *handle_list_with_optional_splat(elems))
|
7
|
+
end
|
8
|
+
|
9
|
+
def process_aref exp
|
10
|
+
_, item, idx = exp.shift 3
|
11
|
+
s(:call, process(item), :[], process(idx))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module RipperRubyParser
|
2
|
+
module SexpHandlers
|
3
|
+
module Assignment
|
4
|
+
def process_assign exp
|
5
|
+
_, lvalue, value = exp.shift 3
|
6
|
+
|
7
|
+
lvalue = process(lvalue)
|
8
|
+
value = process(value)
|
9
|
+
|
10
|
+
create_assignment_sub_type lvalue, value
|
11
|
+
end
|
12
|
+
|
13
|
+
def process_massign exp
|
14
|
+
_, left, right = exp.shift 3
|
15
|
+
|
16
|
+
left = handle_list_with_optional_splat left
|
17
|
+
|
18
|
+
left.each do |item|
|
19
|
+
case item.sexp_type
|
20
|
+
when :splat
|
21
|
+
item[1][0] = :lasgn
|
22
|
+
else
|
23
|
+
item[0] = :lasgn
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
right = process(right)
|
28
|
+
|
29
|
+
unless right.sexp_type == :array
|
30
|
+
right = s(:to_ary, right)
|
31
|
+
end
|
32
|
+
|
33
|
+
s(:masgn, s(:array, *left), right)
|
34
|
+
end
|
35
|
+
|
36
|
+
def process_mrhs_new_from_args exp
|
37
|
+
_, inner, last = exp.shift 3
|
38
|
+
inner.map! {|item| process(item)}
|
39
|
+
inner.push process(last)
|
40
|
+
s(:array, *inner)
|
41
|
+
end
|
42
|
+
|
43
|
+
def process_mlhs_add_star exp
|
44
|
+
generic_add_star exp
|
45
|
+
end
|
46
|
+
|
47
|
+
def process_opassign exp
|
48
|
+
_, lvalue, operator, value = exp.shift 4
|
49
|
+
|
50
|
+
lvalue = process(lvalue)
|
51
|
+
value = process(value)
|
52
|
+
operator = operator[1].gsub(/=/, '').to_sym
|
53
|
+
operator_call = s(:call, lvalue, operator, s(:arglist, value))
|
54
|
+
|
55
|
+
case lvalue.sexp_type
|
56
|
+
when :ivar
|
57
|
+
s(:iasgn, lvalue[1], operator_call)
|
58
|
+
when :aref_field
|
59
|
+
s(:op_asgn1, lvalue[1], s(:arglist, lvalue[2][1]), operator, value)
|
60
|
+
else
|
61
|
+
s(:lasgn, lvalue[1], operator_call)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def create_assignment_sub_type lvalue, value
|
66
|
+
case lvalue.sexp_type
|
67
|
+
when :ivar
|
68
|
+
s(:iasgn, lvalue[1], value)
|
69
|
+
when :aref_field
|
70
|
+
s(:attrasgn, lvalue[1], :[]=, s(:arglist, lvalue[2][1], value))
|
71
|
+
when :const
|
72
|
+
s(:cdecl, lvalue[1], value)
|
73
|
+
else
|
74
|
+
s(:lasgn, lvalue[1], value)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module RipperRubyParser
|
2
|
+
module SexpHandlers
|
3
|
+
module Blocks
|
4
|
+
def process_method_add_block exp
|
5
|
+
_, call, block = exp.shift 3
|
6
|
+
block = process(block)
|
7
|
+
args = convert_block_args(block[1])
|
8
|
+
stmt = block[2].first
|
9
|
+
s(:iter, process(call), args, stmt)
|
10
|
+
end
|
11
|
+
|
12
|
+
def process_brace_block exp
|
13
|
+
handle_generic_block exp
|
14
|
+
end
|
15
|
+
|
16
|
+
def process_do_block exp
|
17
|
+
handle_generic_block exp
|
18
|
+
end
|
19
|
+
|
20
|
+
def process_params exp
|
21
|
+
_, normal, defaults, *_ = exp.shift 6
|
22
|
+
|
23
|
+
args = [*normal].map do |id|
|
24
|
+
identifier_node_to_symbol id
|
25
|
+
end
|
26
|
+
|
27
|
+
assigns = [*defaults].map do |pair|
|
28
|
+
sym = identifier_node_to_symbol pair[0]
|
29
|
+
val = process pair[1]
|
30
|
+
s(:lasgn, sym, val)
|
31
|
+
end
|
32
|
+
|
33
|
+
if assigns.length > 0
|
34
|
+
args += assigns.map {|lasgn| lasgn[1]}
|
35
|
+
args << s(:block, *assigns)
|
36
|
+
end
|
37
|
+
|
38
|
+
s(:args, *args)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def handle_generic_block exp
|
44
|
+
_, args, stmts = exp.shift 3
|
45
|
+
s(:block, process(args), s(handle_statement_list(stmts)))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module RipperRubyParser
|
2
|
+
module SexpHandlers
|
3
|
+
module Conditionals
|
4
|
+
def process_if exp
|
5
|
+
_, cond, truepart, falsepart = exp.shift 4
|
6
|
+
s(:if,
|
7
|
+
process(cond),
|
8
|
+
handle_statement_list(truepart),
|
9
|
+
process(falsepart))
|
10
|
+
end
|
11
|
+
|
12
|
+
def process_elsif exp
|
13
|
+
process_if exp
|
14
|
+
end
|
15
|
+
|
16
|
+
def process_if_mod exp
|
17
|
+
_, cond, truepart = exp.shift 3
|
18
|
+
s(:if, process(cond), process(truepart), nil)
|
19
|
+
end
|
20
|
+
|
21
|
+
def process_unless_mod exp
|
22
|
+
_, cond, truepart = exp.shift 3
|
23
|
+
s(:if, process(cond), nil, process(truepart))
|
24
|
+
end
|
25
|
+
|
26
|
+
def process_unless exp
|
27
|
+
_, cond, truepart, falsepart = exp.shift 4
|
28
|
+
s(:if,
|
29
|
+
process(cond),
|
30
|
+
process(falsepart),
|
31
|
+
handle_statement_list(truepart))
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_case exp
|
35
|
+
_, expr, clauses = exp.shift 3
|
36
|
+
s(:case, process(expr), *process(clauses))
|
37
|
+
end
|
38
|
+
|
39
|
+
def process_when exp
|
40
|
+
_, values, truepart, falsepart = exp.shift 4
|
41
|
+
|
42
|
+
if falsepart.nil?
|
43
|
+
falsepart = [nil]
|
44
|
+
else
|
45
|
+
falsepart = process(falsepart)
|
46
|
+
if falsepart.first.is_a? Symbol
|
47
|
+
falsepart = s(falsepart)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
s(s(:when,
|
52
|
+
process(s(:array, values)),
|
53
|
+
handle_statement_list(truepart)),
|
54
|
+
*falsepart)
|
55
|
+
end
|
56
|
+
|
57
|
+
def process_else exp
|
58
|
+
_, body = exp.shift 2
|
59
|
+
handle_statement_list body
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RipperRubyParser
|
2
|
+
module SexpHandlers
|
3
|
+
module Hashes
|
4
|
+
def process_hash exp
|
5
|
+
_, elems = exp.shift 2
|
6
|
+
s(:hash, *process(elems))
|
7
|
+
end
|
8
|
+
|
9
|
+
def process_assoclist_from_args exp
|
10
|
+
_, elems = exp.shift 2
|
11
|
+
result = s()
|
12
|
+
elems.each {|sub_exp|
|
13
|
+
process(sub_exp).each {|elm|
|
14
|
+
result << elm
|
15
|
+
}
|
16
|
+
}
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
def process_assoc_new exp
|
21
|
+
_, left, right = exp.shift 3
|
22
|
+
s(process(left), process(right))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module RipperRubyParser
|
2
|
+
module SexpHandlers
|
3
|
+
module HelperMethods
|
4
|
+
def handle_list_with_optional_splat exp
|
5
|
+
if exp.nil?
|
6
|
+
[]
|
7
|
+
elsif exp.first.is_a? Symbol
|
8
|
+
process(exp)
|
9
|
+
else
|
10
|
+
exp.map { |sub_exp| process(sub_exp) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def convert_block_args(args)
|
15
|
+
args && s(:lasgn, args[1][1])
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle_statement_list exp
|
19
|
+
statements = exp.
|
20
|
+
map { |sub_exp| process(sub_exp) }.
|
21
|
+
reject { |sub_exp| sub_exp.sexp_type == :void_stmt }
|
22
|
+
|
23
|
+
if statements.length == 1
|
24
|
+
statements.first
|
25
|
+
else
|
26
|
+
s(:block, *statements)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def identifier_node_to_symbol exp
|
31
|
+
assert_type exp, :@ident
|
32
|
+
_, ident, _ = exp.shift 3
|
33
|
+
|
34
|
+
ident.to_sym
|
35
|
+
end
|
36
|
+
|
37
|
+
def generic_add_star exp
|
38
|
+
_, args, splatarg = exp.shift 3
|
39
|
+
items = args.map { |sub| process(sub) }
|
40
|
+
items << s(:splat, process(splatarg))
|
41
|
+
s(*items)
|
42
|
+
end
|
43
|
+
|
44
|
+
def is_literal? exp
|
45
|
+
exp.sexp_type == :lit
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module RipperRubyParser
|
2
|
+
module SexpHandlers
|
3
|
+
module Literals
|
4
|
+
def process_string_literal exp
|
5
|
+
_, content = exp.shift 2
|
6
|
+
process(content)
|
7
|
+
end
|
8
|
+
|
9
|
+
def process_string_content exp
|
10
|
+
_, inner = exp.shift 2
|
11
|
+
|
12
|
+
string = extract_inner_string(inner)
|
13
|
+
rest = []
|
14
|
+
|
15
|
+
if string.sexp_type == :str
|
16
|
+
string = string[1]
|
17
|
+
else
|
18
|
+
rest << string
|
19
|
+
string = ""
|
20
|
+
end
|
21
|
+
|
22
|
+
string = unescape(string)
|
23
|
+
|
24
|
+
until exp.empty? do
|
25
|
+
result = process(exp.shift)
|
26
|
+
if result.sexp_type == :str
|
27
|
+
result[1] = unescape(result[1])
|
28
|
+
end
|
29
|
+
rest << result
|
30
|
+
end
|
31
|
+
|
32
|
+
if rest.empty?
|
33
|
+
s(:str, string)
|
34
|
+
else
|
35
|
+
s(:dstr, string, *rest)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def process_string_embexpr exp
|
40
|
+
_, list = exp.shift 2
|
41
|
+
s(:evstr, process(list.first))
|
42
|
+
end
|
43
|
+
|
44
|
+
def process_regexp_literal exp
|
45
|
+
_, content, _ = exp.shift 3
|
46
|
+
|
47
|
+
string = extract_inner_string content[0]
|
48
|
+
|
49
|
+
s(:lit, Regexp.new(string[1]))
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_symbol_literal exp
|
53
|
+
_, symbol = exp.shift 2
|
54
|
+
sym = symbol[1]
|
55
|
+
s(:lit, extract_node_symbol(sym))
|
56
|
+
end
|
57
|
+
|
58
|
+
def process_dyna_symbol exp
|
59
|
+
_, list = exp.shift 2
|
60
|
+
|
61
|
+
string = process list[0]
|
62
|
+
s(:lit, string[1].to_sym)
|
63
|
+
end
|
64
|
+
|
65
|
+
def process_at_tstring_content exp
|
66
|
+
_, string, _ = exp.shift 3
|
67
|
+
s(:str, string)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def extract_inner_string exp
|
73
|
+
process(exp) || s(:str, "")
|
74
|
+
end
|
75
|
+
|
76
|
+
def unescape string
|
77
|
+
string.gsub /(\\[n\\"])/ do
|
78
|
+
eval "\"#{$1}\""
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module RipperRubyParser
|
2
|
+
module SexpHandlers
|
3
|
+
module MethodCalls
|
4
|
+
def process_method_add_arg exp
|
5
|
+
_, call, parens = exp.shift 3
|
6
|
+
call = process call
|
7
|
+
s(:call, call[1], call[2], process(parens))
|
8
|
+
end
|
9
|
+
|
10
|
+
def process_call exp
|
11
|
+
_, receiver, _, method = exp.shift 4
|
12
|
+
s(:call, process(receiver), identifier_node_to_symbol(method), s(:arglist))
|
13
|
+
end
|
14
|
+
|
15
|
+
def process_command exp
|
16
|
+
_, ident, arglist = exp.shift 3
|
17
|
+
|
18
|
+
ident = identifier_node_to_symbol ident
|
19
|
+
arglist = process arglist
|
20
|
+
|
21
|
+
s(:call, nil, ident, arglist)
|
22
|
+
end
|
23
|
+
|
24
|
+
def process_command_call exp
|
25
|
+
_, receiver, _, method, arguments = exp.shift 5
|
26
|
+
s(:call,
|
27
|
+
process(receiver),
|
28
|
+
identifier_node_to_symbol(method),
|
29
|
+
process(arguments))
|
30
|
+
end
|
31
|
+
|
32
|
+
def process_vcall exp
|
33
|
+
_, ident = exp.shift 3
|
34
|
+
|
35
|
+
ident = identifier_node_to_symbol ident
|
36
|
+
|
37
|
+
s(:call, nil, ident, s(:arglist))
|
38
|
+
end
|
39
|
+
|
40
|
+
def process_fcall exp
|
41
|
+
_, method = exp.shift 2
|
42
|
+
s(:call, nil, identifier_node_to_symbol(method), s(:arglist))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module RipperRubyParser
|
2
|
+
module SexpHandlers
|
3
|
+
module Methods
|
4
|
+
def process_def exp
|
5
|
+
_, ident, params, body = exp.shift 4
|
6
|
+
ident = identifier_node_to_symbol ident
|
7
|
+
s(:defn, ident, process(params), method_body(body))
|
8
|
+
end
|
9
|
+
|
10
|
+
def process_defs exp
|
11
|
+
_, receiver, _, method, args, body = exp.shift 6
|
12
|
+
s(:defs, process(receiver),
|
13
|
+
identifier_node_to_symbol(method),
|
14
|
+
process(args), process(body))
|
15
|
+
end
|
16
|
+
|
17
|
+
def process_return exp
|
18
|
+
_, arglist = exp.shift 2
|
19
|
+
arglist = process(arglist)
|
20
|
+
s(:return, arglist[1])
|
21
|
+
end
|
22
|
+
|
23
|
+
def process_return0 exp
|
24
|
+
_ = exp.shift
|
25
|
+
s(:return)
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_body exp
|
29
|
+
scope = process exp
|
30
|
+
block = scope[1]
|
31
|
+
if block.length == 1
|
32
|
+
block.push s(:nil)
|
33
|
+
end
|
34
|
+
scope
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module RipperRubyParser
|
2
|
+
module SexpHandlers
|
3
|
+
module Operators
|
4
|
+
OPERATOR_MAP = {
|
5
|
+
"&&".to_sym => :and,
|
6
|
+
"||".to_sym => :or
|
7
|
+
}
|
8
|
+
|
9
|
+
def process_binary exp
|
10
|
+
_, left, op, right = exp.shift 4
|
11
|
+
mapped = OPERATOR_MAP[op]
|
12
|
+
if mapped
|
13
|
+
s(mapped, process(left), process(right))
|
14
|
+
else
|
15
|
+
s(:call, process(left), op, s(:arglist, process(right)))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def process_unary exp
|
20
|
+
_, _, arg = exp.shift 3
|
21
|
+
arg = process(arg)
|
22
|
+
if is_literal? arg
|
23
|
+
s(:lit, -arg[1])
|
24
|
+
else
|
25
|
+
s(:call, arg, :-@, s(:arglist))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def process_dot2 exp
|
30
|
+
_, left, right = exp.shift 3
|
31
|
+
left = process(left)
|
32
|
+
right = process(right)
|
33
|
+
if is_literal?(left) && is_literal?(right)
|
34
|
+
s(:lit, Range.new(left[1], right[1]))
|
35
|
+
else
|
36
|
+
s(:dot2, left, right)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|