unparser 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.
- checksums.yaml +7 -0
- data/.circle.yml +4 -0
- data/.gitignore +2 -0
- data/.rspec +3 -0
- data/.travis.yml +16 -0
- data/Changelog.md +3 -0
- data/Gemfile +6 -0
- data/Gemfile.devtools +60 -0
- data/Guardfile +18 -0
- data/README.md +41 -0
- data/Rakefile +24 -0
- data/TODO +1 -0
- data/config/devtools.yml +2 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +3 -0
- data/config/reek.yml +107 -0
- data/config/yardstick.yml +2 -0
- data/lib/unparser/buffer.rb +93 -0
- data/lib/unparser/constants.rb +87 -0
- data/lib/unparser/emitter/alias.rb +27 -0
- data/lib/unparser/emitter/argument.rb +154 -0
- data/lib/unparser/emitter/assignment.rb +140 -0
- data/lib/unparser/emitter/begin.rb +179 -0
- data/lib/unparser/emitter/binary.rb +52 -0
- data/lib/unparser/emitter/block.rb +53 -0
- data/lib/unparser/emitter/break.rb +28 -0
- data/lib/unparser/emitter/case.rb +97 -0
- data/lib/unparser/emitter/cbase.rb +22 -0
- data/lib/unparser/emitter/class.rb +72 -0
- data/lib/unparser/emitter/def.rb +107 -0
- data/lib/unparser/emitter/defined.rb +27 -0
- data/lib/unparser/emitter/for.rb +50 -0
- data/lib/unparser/emitter/hookexe.rb +42 -0
- data/lib/unparser/emitter/if.rb +85 -0
- data/lib/unparser/emitter/literal/composed.rb +64 -0
- data/lib/unparser/emitter/literal/dynamic.rb +54 -0
- data/lib/unparser/emitter/literal/dynamic_body.rb +109 -0
- data/lib/unparser/emitter/literal/execute_string.rb +38 -0
- data/lib/unparser/emitter/literal/primitive.rb +49 -0
- data/lib/unparser/emitter/literal/range.rb +33 -0
- data/lib/unparser/emitter/literal/regexp.rb +96 -0
- data/lib/unparser/emitter/literal/singleton.rb +24 -0
- data/lib/unparser/emitter/literal.rb +7 -0
- data/lib/unparser/emitter/module.rb +37 -0
- data/lib/unparser/emitter/next.rb +22 -0
- data/lib/unparser/emitter/not.rb +25 -0
- data/lib/unparser/emitter/op_assign.rb +63 -0
- data/lib/unparser/emitter/redo.rb +22 -0
- data/lib/unparser/emitter/repetition.rb +33 -0
- data/lib/unparser/emitter/retry.rb +22 -0
- data/lib/unparser/emitter/return.rb +38 -0
- data/lib/unparser/emitter/root.rb +7 -0
- data/lib/unparser/emitter/send/binary.rb +100 -0
- data/lib/unparser/emitter/send/index.rb +82 -0
- data/lib/unparser/emitter/send/unary.rb +29 -0
- data/lib/unparser/emitter/send.rb +273 -0
- data/lib/unparser/emitter/splat.rb +24 -0
- data/lib/unparser/emitter/super.rb +46 -0
- data/lib/unparser/emitter/undef.rb +25 -0
- data/lib/unparser/emitter/variable.rb +83 -0
- data/lib/unparser/emitter/yield.rb +28 -0
- data/lib/unparser/emitter.rb +308 -0
- data/lib/unparser.rb +87 -0
- data/spec/integration/unparser/spike_spec.rb +914 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/unit/unparser/buffer/append_spec.rb +23 -0
- data/spec/unit/unparser/buffer/content_spec.rb +38 -0
- data/spec/unit/unparser/buffer/indent_spec.rb +18 -0
- data/spec/unit/unparser/buffer/nl_spec.rb +16 -0
- data/spec/unit/unparser/buffer/unindent_spec.rb +18 -0
- data/spec/unit/unparser/class_methods/unparse_spec.rb +16 -0
- data/spec/unit/unparser/emitter/class_methods/handle_spec.rb +17 -0
- data/spec/unit/unparser/emitter/class_methods/visit_spec.rb +37 -0
- data/spec/unit/unparser/emitter/source_map/class_methods/emit_spec.rb +20 -0
- data/unparser.gemspec +24 -0
- metadata +201 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
class Literal
|
4
|
+
|
5
|
+
# Emitter for regexp literals
|
6
|
+
class Regexp < self
|
7
|
+
DELIMITER = '/'.freeze
|
8
|
+
|
9
|
+
handle :regexp
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# Perform dispatch
|
14
|
+
#
|
15
|
+
# @return [undefined]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def dispatch
|
20
|
+
parentheses(DELIMITER, DELIMITER) do
|
21
|
+
visit(dynamic_body)
|
22
|
+
end
|
23
|
+
visit(children.last)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return dynamic body
|
27
|
+
#
|
28
|
+
# @return [undefined]
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
#
|
32
|
+
def dynamic_body
|
33
|
+
Parser::AST::Node.new(:dyn_regexp_body, dynamic_body_children)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return dynamic body children
|
37
|
+
#
|
38
|
+
# @return [Enumerable<Parser::AST::Node>]
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
#
|
42
|
+
def dynamic_body_children
|
43
|
+
children[0..-2].map do |child|
|
44
|
+
escape(child)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Return escaped child
|
49
|
+
#
|
50
|
+
# @return [Parser::AST::Node]
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
#
|
54
|
+
def escape(child)
|
55
|
+
return child unless child.type == :str
|
56
|
+
source = child.children.first
|
57
|
+
Parser::AST::Node.new(:str, [Unparser.transquote(source, delimiter, DELIMITER)])
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return closing delimiter
|
61
|
+
#
|
62
|
+
# @return [String]
|
63
|
+
#
|
64
|
+
# @api private
|
65
|
+
#
|
66
|
+
def delimiter
|
67
|
+
location = node.location
|
68
|
+
return DELIMITER unless location
|
69
|
+
location.expression.source[-1]
|
70
|
+
end
|
71
|
+
memoize :delimiter
|
72
|
+
|
73
|
+
end # Regexp
|
74
|
+
|
75
|
+
# Emitter for regexp options
|
76
|
+
class Regopt < self
|
77
|
+
|
78
|
+
handle :regopt
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# Perform dispatch
|
83
|
+
#
|
84
|
+
# @return [undefined]
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
#
|
88
|
+
def dispatch
|
89
|
+
write(children.map(&:to_s).join)
|
90
|
+
end
|
91
|
+
|
92
|
+
end # Regopt
|
93
|
+
|
94
|
+
end # Literal
|
95
|
+
end # Emitter
|
96
|
+
end # Unparser
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
class Literal
|
4
|
+
# Emiter for literal singletons
|
5
|
+
class Singleton < self
|
6
|
+
|
7
|
+
handle :self, :true, :false, :nil
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# Perform dispatco
|
12
|
+
#
|
13
|
+
# @return [undefined]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
def dispatch
|
18
|
+
buffer.append(node.type.to_s)
|
19
|
+
end
|
20
|
+
|
21
|
+
end # Singleton
|
22
|
+
end # Literal
|
23
|
+
end # Emitter
|
24
|
+
end # Unparser
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
# Emitter for module nodes
|
4
|
+
class Module < self
|
5
|
+
|
6
|
+
handle :module
|
7
|
+
|
8
|
+
children :name, :body
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# Perform dispatch
|
13
|
+
#
|
14
|
+
# @return [undefined]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
def dispatch
|
19
|
+
write(K_MODULE, WS)
|
20
|
+
visit(name)
|
21
|
+
emit_body
|
22
|
+
k_end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Emit body
|
26
|
+
#
|
27
|
+
# @return [undefined]
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
#
|
31
|
+
def emit_body
|
32
|
+
emit_non_nil_body(body)
|
33
|
+
end
|
34
|
+
|
35
|
+
end # Module
|
36
|
+
end # Emitter
|
37
|
+
end # Unparser
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
# Emitter for next nodes
|
4
|
+
class Next < self
|
5
|
+
|
6
|
+
handle :next
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
# Perform dispatch
|
11
|
+
#
|
12
|
+
# @return [undefined]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
def dispatch
|
17
|
+
write(K_NEXT)
|
18
|
+
end
|
19
|
+
|
20
|
+
end # Next
|
21
|
+
end # Emitter
|
22
|
+
end # Unparser
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
# Emitter for 1.8 only not node
|
4
|
+
class Not < self
|
5
|
+
|
6
|
+
handle :not
|
7
|
+
|
8
|
+
children :body
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# Perform dispatch
|
13
|
+
#
|
14
|
+
# @return [undefined]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
def dispatch
|
19
|
+
write(O_NEG)
|
20
|
+
visit(body)
|
21
|
+
end
|
22
|
+
|
23
|
+
end # Not
|
24
|
+
end # Emitter
|
25
|
+
end # Unparser
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
|
4
|
+
# Base class for and and or op-assign
|
5
|
+
class BinaryAssign < self
|
6
|
+
|
7
|
+
children :target, :expression
|
8
|
+
|
9
|
+
MAP = IceNine.deep_freeze(
|
10
|
+
:and_asgn => '&&=',
|
11
|
+
:or_asgn => '||='
|
12
|
+
)
|
13
|
+
|
14
|
+
handle *MAP.keys
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Perform dispatch
|
19
|
+
#
|
20
|
+
# @return [undefined]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
#
|
24
|
+
def dispatch
|
25
|
+
visit(target)
|
26
|
+
write(WS, MAP.fetch(node.type), WS)
|
27
|
+
visit(expression)
|
28
|
+
end
|
29
|
+
|
30
|
+
end # BinaryAssign
|
31
|
+
|
32
|
+
# Emitter for op assign
|
33
|
+
class OpAssign < self
|
34
|
+
|
35
|
+
handle :op_asgn
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Perform dispatch
|
40
|
+
#
|
41
|
+
# @return [undefined]
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
#
|
45
|
+
def dispatch
|
46
|
+
visit(first_child)
|
47
|
+
emit_operator
|
48
|
+
visit(children[2])
|
49
|
+
end
|
50
|
+
|
51
|
+
# Emit operator
|
52
|
+
#
|
53
|
+
# @return [undefined]
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
#
|
57
|
+
def emit_operator
|
58
|
+
write(WS, children[1].to_s, O_ASN, WS)
|
59
|
+
end
|
60
|
+
|
61
|
+
end # OpAssign
|
62
|
+
end # Emitte
|
63
|
+
end # Unparser
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
# Emitter for redo nodes
|
4
|
+
class Redo < self
|
5
|
+
|
6
|
+
handle :redo
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
# Perform dispatch
|
11
|
+
#
|
12
|
+
# @return [undefined]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
def dispatch
|
17
|
+
write(K_REDO)
|
18
|
+
end
|
19
|
+
|
20
|
+
end # Redo
|
21
|
+
end # Emitter
|
22
|
+
end # Unparser
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
|
4
|
+
# Base class for while and until emitters
|
5
|
+
class Repetition < self
|
6
|
+
|
7
|
+
MAP = {
|
8
|
+
:while => K_WHILE,
|
9
|
+
:until => K_UNTIL
|
10
|
+
}.freeze
|
11
|
+
|
12
|
+
handle *MAP.keys
|
13
|
+
|
14
|
+
children :condition, :body
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Perform dispatch
|
19
|
+
#
|
20
|
+
# @return [undefined]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
#
|
24
|
+
def dispatch
|
25
|
+
write(MAP.fetch(node.type), WS)
|
26
|
+
visit(condition)
|
27
|
+
indented { visit(body) }
|
28
|
+
k_end
|
29
|
+
end
|
30
|
+
|
31
|
+
end # Repetition
|
32
|
+
end # Emitter
|
33
|
+
end # Unparser
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
# Emitter for retry nodes
|
4
|
+
class Retry < self
|
5
|
+
|
6
|
+
handle :retry
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
# Perform dispatch
|
11
|
+
#
|
12
|
+
# @return [undefined]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
def dispatch
|
17
|
+
write(K_RETRY)
|
18
|
+
end
|
19
|
+
|
20
|
+
end # Break
|
21
|
+
end # Emitter
|
22
|
+
end # Unparser
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
# Emitter for return nodes
|
4
|
+
class Return < self
|
5
|
+
|
6
|
+
handle :return
|
7
|
+
|
8
|
+
children :argument
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# Perform dispatch
|
13
|
+
#
|
14
|
+
# @return [undefined]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
def dispatch
|
19
|
+
write(K_RETURN)
|
20
|
+
emit_argument
|
21
|
+
end
|
22
|
+
|
23
|
+
# Emit argument
|
24
|
+
#
|
25
|
+
# @return [undefined]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
#
|
29
|
+
def emit_argument
|
30
|
+
return unless argument
|
31
|
+
parentheses do
|
32
|
+
visit(argument)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end # Return
|
37
|
+
end # Emitter
|
38
|
+
end # Unparser
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
class Send
|
4
|
+
# Emitter for binary sends
|
5
|
+
class Binary < self
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
# Return undefined
|
10
|
+
#
|
11
|
+
# @return [undefined]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
#
|
15
|
+
def dispatch
|
16
|
+
emit_receiver
|
17
|
+
emit_operator
|
18
|
+
emit_right
|
19
|
+
end
|
20
|
+
|
21
|
+
# Emit receiver
|
22
|
+
#
|
23
|
+
# @return [undefined]
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
#
|
27
|
+
def emit_receiver
|
28
|
+
emit_unambiguous_receiver
|
29
|
+
write(O_DOT) if parentheses?
|
30
|
+
end
|
31
|
+
|
32
|
+
# Emit operator
|
33
|
+
#
|
34
|
+
# @return [undefined]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
#
|
38
|
+
def emit_operator
|
39
|
+
parens = parentheses? ? EMPTY_STRING : WS
|
40
|
+
parentheses(parens, parens) { write(selector) }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return right node
|
44
|
+
#
|
45
|
+
# @return [Parser::AST::Node]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
#
|
49
|
+
def right_node
|
50
|
+
children[2]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Test for splat argument
|
54
|
+
#
|
55
|
+
# @return [true]
|
56
|
+
# if first argument is a splat
|
57
|
+
#
|
58
|
+
# @return [false]
|
59
|
+
# otherwise
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
#
|
63
|
+
def splat?
|
64
|
+
right_node.type == :splat
|
65
|
+
end
|
66
|
+
|
67
|
+
# Test if parentheses are needed
|
68
|
+
#
|
69
|
+
# @return [true]
|
70
|
+
# if parenthes are needed
|
71
|
+
#
|
72
|
+
# @return [false]
|
73
|
+
# otherwise
|
74
|
+
#
|
75
|
+
# @api private
|
76
|
+
#
|
77
|
+
def parentheses?
|
78
|
+
splat? || children.length >= 4
|
79
|
+
end
|
80
|
+
memoize :parentheses?
|
81
|
+
|
82
|
+
# Emit right
|
83
|
+
#
|
84
|
+
# @return [undefined]
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
#
|
88
|
+
def emit_right
|
89
|
+
node = right_node
|
90
|
+
if parentheses?
|
91
|
+
parentheses { delimited(children[2..-1]) }
|
92
|
+
return
|
93
|
+
end
|
94
|
+
visit(node)
|
95
|
+
end
|
96
|
+
|
97
|
+
end # Binary
|
98
|
+
end # Send
|
99
|
+
end # Emitter
|
100
|
+
end # Unparser
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
class Send
|
4
|
+
# Emitter for send to index references
|
5
|
+
class Index < self
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
# Perform dispatch
|
10
|
+
#
|
11
|
+
# @return [undefined]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
#
|
15
|
+
def dispatch
|
16
|
+
emit_receiver
|
17
|
+
emit_arguments
|
18
|
+
end
|
19
|
+
|
20
|
+
# Emit block within parentheses
|
21
|
+
#
|
22
|
+
# @return [undefined]
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
#
|
26
|
+
def parentheses(&block)
|
27
|
+
super(*INDEX_PARENS, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Emit receiver
|
31
|
+
#
|
32
|
+
# @return [undefined]
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
#
|
36
|
+
def emit_receiver
|
37
|
+
visit(first_child)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Emitter for index reference nodes
|
41
|
+
class Reference < self
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Emit arguments
|
46
|
+
#
|
47
|
+
# @return [undefined]
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
#
|
51
|
+
def emit_arguments
|
52
|
+
parentheses do
|
53
|
+
delimited(arguments)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end # Reference
|
57
|
+
|
58
|
+
# Emitter for assign to index nodes
|
59
|
+
class Assign < self
|
60
|
+
|
61
|
+
# Emit arguments
|
62
|
+
#
|
63
|
+
# @return [undefined]
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
#
|
67
|
+
def emit_arguments
|
68
|
+
index, *assignment = arguments
|
69
|
+
parentheses do
|
70
|
+
delimited([index])
|
71
|
+
end
|
72
|
+
return if assignment.empty? # mlhs
|
73
|
+
write(WS, O_ASN, WS)
|
74
|
+
delimited(assignment)
|
75
|
+
end
|
76
|
+
|
77
|
+
end # Assign
|
78
|
+
|
79
|
+
end # Index
|
80
|
+
end # Send
|
81
|
+
end # Emitter
|
82
|
+
end # Unparser
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Unparser
|
2
|
+
class Emitter
|
3
|
+
class Send
|
4
|
+
# Emitter for unary sends
|
5
|
+
class Unary < self
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
MAP = IceNine.deep_freeze(
|
10
|
+
'-@' => '-',
|
11
|
+
'+@' => '+'
|
12
|
+
)
|
13
|
+
|
14
|
+
# Perform dispatch
|
15
|
+
#
|
16
|
+
# @return [undefined]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
#
|
20
|
+
def dispatch
|
21
|
+
name = selector
|
22
|
+
write(MAP.fetch(name, name))
|
23
|
+
emit_unambiguous_receiver
|
24
|
+
end
|
25
|
+
|
26
|
+
end # Unary
|
27
|
+
end # Send
|
28
|
+
end # Emitter
|
29
|
+
end # Unparser
|