unparser 0.1.10 → 0.1.11
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 +4 -4
- data/Changelog.md +4 -0
- data/Gemfile +0 -2
- data/Guardfile +3 -1
- data/config/flay.yml +1 -1
- data/lib/unparser/ast.rb +24 -51
- data/lib/unparser/ast/local_variable_scope.rb +93 -29
- data/lib/unparser/emitter.rb +10 -4
- data/lib/unparser/emitter/if.rb +1 -1
- data/lib/unparser/emitter/repetition.rb +1 -1
- data/lib/unparser/emitter/send.rb +1 -1
- data/spec/integration/unparser/corpus_spec.rb +3 -0
- data/unparser.gemspec +2 -2
- metadata +34 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e21010b4e759db5c1502593760f8480381ed63fd
|
4
|
+
data.tar.gz: c6549debc54796bf1151ee522d85caef6b6db7a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 342af109c4ede135af5f555073dcb2b10c1bdef9b1873598e5fc84dd5c57d517e8d6d5f51c4a856695f10fd0ead95ab68a19acd060c8acda82564bf95a5de2e0
|
7
|
+
data.tar.gz: 9abf7e144000af5631f23440abc8557210a67dbc935793ab3add786ba838ae77f19c5f5a428932f92c6a596c6892b68d7051c2dbd0a5afc32c07d4f1d91ff74c
|
data/Changelog.md
CHANGED
data/Gemfile
CHANGED
data/Guardfile
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
ENV['GUARD'] = '1'
|
4
|
+
|
3
5
|
guard :bundler do
|
4
6
|
watch('Gemfile')
|
5
7
|
end
|
6
8
|
|
7
|
-
guard :rspec, :all_on_start => false, :all_after_pass => false, :
|
9
|
+
guard :rspec, :all_on_start => false, :all_after_pass => false, :cmd => 'bundle exec rspec --fail-fast --seed 1' do
|
8
10
|
# run all specs if the spec_helper or supporting files files are modified
|
9
11
|
watch('spec/spec_helper.rb') { 'spec/unit' }
|
10
12
|
watch(%r{\Aspec/(?:lib|support|shared)/.+\.rb\z}) { 'spec/unit' }
|
data/config/flay.yml
CHANGED
data/lib/unparser/ast.rb
CHANGED
@@ -7,73 +7,46 @@ module Unparser
|
|
7
7
|
FIRST_CHILD = ->(node) { node.children.first }.freeze
|
8
8
|
TAUTOLOGY = ->(node) { true }.freeze
|
9
9
|
|
10
|
-
|
10
|
+
RESET_NODES = [:module, :class, :sclass, :def, :defs].freeze
|
11
|
+
INHERIT_NODES = [:block].freeze
|
12
|
+
CLOSE_NODES = (RESET_NODES + INHERIT_NODES).freeze
|
13
|
+
|
14
|
+
# Nodes that assign a local variable
|
15
|
+
#
|
16
|
+
# FIXME: Kwargs are missing.
|
17
|
+
#
|
18
|
+
ASSIGN_NODES = [:lvasgn, :arg, :optarg, :restarg].freeze
|
19
|
+
|
20
|
+
# Test for local variable inherited scope reset
|
11
21
|
#
|
12
|
-
# @param [Parser::AST::Node]
|
13
|
-
# @param [Parser::AST::Node] assignment
|
22
|
+
# @param [Parser::AST::Node] node
|
14
23
|
#
|
15
24
|
# @return [true]
|
16
|
-
# if local variable
|
25
|
+
# if local variable scope must NOT be reset
|
17
26
|
#
|
18
27
|
# @return [false]
|
19
28
|
# otherwise
|
20
29
|
#
|
21
30
|
# @api private
|
22
31
|
#
|
23
|
-
def self.
|
24
|
-
|
25
|
-
AST::LocalVariableScope.each(root) do |node, current, before|
|
26
|
-
if node.equal?(assignment) && current.include?(name) && !before.include?(name)
|
27
|
-
return true
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
false
|
32
|
+
def self.not_close_scope?(node)
|
33
|
+
!CLOSE_NODES.include?(node.type)
|
32
34
|
end
|
33
35
|
|
34
|
-
# Test
|
36
|
+
# Test for local variable scope reset
|
35
37
|
#
|
36
|
-
# @param [Parser::AST::Node] root
|
37
38
|
# @param [Parser::AST::Node] node
|
38
|
-
# @param [Symbol] name
|
39
39
|
#
|
40
40
|
# @return [true]
|
41
|
-
# if local variable
|
41
|
+
# if local variable scope must NOT be reset
|
42
42
|
#
|
43
43
|
# @return [false]
|
44
44
|
# otherwise
|
45
45
|
#
|
46
46
|
# @api private
|
47
47
|
#
|
48
|
-
def self.
|
49
|
-
|
50
|
-
if child.equal?(node) && current.include?(name)
|
51
|
-
return true
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
false
|
56
|
-
end
|
57
|
-
|
58
|
-
# Test if local variables where first assigned in body and read by conditional
|
59
|
-
#
|
60
|
-
# @param [Parser::AST::Node] root
|
61
|
-
# @param [Parser::AST::Node] conditional
|
62
|
-
# @param [Parser::AST::Node] body
|
63
|
-
#
|
64
|
-
# @api private
|
65
|
-
#
|
66
|
-
def self.first_assignment_in_body_and_used_in_condition?(root, body, condition)
|
67
|
-
condition_reads = local_variables_read_in_scope(condition)
|
68
|
-
|
69
|
-
candidates = AST.local_variable_assignments_in_scope(body).select do |node|
|
70
|
-
name = node.children.first
|
71
|
-
condition_reads.include?(name)
|
72
|
-
end
|
73
|
-
|
74
|
-
candidates.any? do |node|
|
75
|
-
first_assignment?(root, node)
|
76
|
-
end
|
48
|
+
def self.not_reset_scope?(node)
|
49
|
+
!RESET_NODES.include?(node.type)
|
77
50
|
end
|
78
51
|
|
79
52
|
# Return local variables that get assigned in scope
|
@@ -84,11 +57,11 @@ module Unparser
|
|
84
57
|
#
|
85
58
|
# @api private
|
86
59
|
#
|
87
|
-
def self.
|
60
|
+
def self.local_variable_assignments(node)
|
88
61
|
Enumerator.new(
|
89
62
|
node,
|
90
|
-
|
91
|
-
).types(
|
63
|
+
method(:not_reset_scope?)
|
64
|
+
).types(ASSIGN_NODES)
|
92
65
|
end
|
93
66
|
|
94
67
|
# Return local variables read
|
@@ -99,10 +72,10 @@ module Unparser
|
|
99
72
|
#
|
100
73
|
# @api private
|
101
74
|
#
|
102
|
-
def self.
|
75
|
+
def self.local_variable_reads(node)
|
103
76
|
Enumerator.new(
|
104
77
|
node,
|
105
|
-
|
78
|
+
method(:not_close_scope?)
|
106
79
|
).type(:lvar).map(&FIRST_CHILD).to_set
|
107
80
|
end
|
108
81
|
|
@@ -2,73 +2,137 @@
|
|
2
2
|
|
3
3
|
module Unparser
|
4
4
|
module AST
|
5
|
-
# Local variable scope enumerator
|
6
|
-
class LocalVariableScope
|
7
|
-
include Enumerable
|
8
5
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# Nodes that assign a local variable
|
14
|
-
#
|
15
|
-
# FIXME: Kwargs are missing.
|
16
|
-
#
|
17
|
-
ASSIGN_NODES = [:lvasgn, :arg, :optarg, :restarg].freeze
|
6
|
+
# Calculated local variable scope for a given node
|
7
|
+
class LocalVariableScope
|
8
|
+
include Enumerable, Adamantium, Concord.new(:node)
|
18
9
|
|
19
10
|
# Initialize object
|
20
11
|
#
|
12
|
+
# @param [Parser::AST::Node] node
|
13
|
+
#
|
21
14
|
# @return [undefined]
|
22
15
|
#
|
23
16
|
# @api private
|
24
17
|
#
|
25
|
-
def initialize
|
26
|
-
|
18
|
+
def initialize(node)
|
19
|
+
items = []
|
20
|
+
LocalVariableScopeEnumerator.each(node) do |*scope|
|
21
|
+
items << scope
|
22
|
+
end
|
23
|
+
@items = items
|
24
|
+
@node = node
|
27
25
|
end
|
28
26
|
|
29
|
-
#
|
27
|
+
# Test if local variable was first at given assignment
|
30
28
|
#
|
31
29
|
# @param [Parser::AST::Node] node
|
32
30
|
#
|
33
|
-
# @return [
|
31
|
+
# @return [true]
|
32
|
+
# if local variable was firstly introduced in body
|
33
|
+
#
|
34
|
+
# @return [false]
|
35
|
+
# otherwise
|
34
36
|
#
|
35
37
|
# @api private
|
36
38
|
#
|
37
|
-
def
|
38
|
-
|
39
|
-
|
39
|
+
def first_assignment?(node)
|
40
|
+
name = node.children.first
|
41
|
+
match(node) do |current, before|
|
42
|
+
current.include?(name) && !before.include?(name)
|
43
|
+
end
|
40
44
|
end
|
41
45
|
|
42
|
-
# Test
|
46
|
+
# Test if local variable is defined for given node
|
43
47
|
#
|
44
48
|
# @param [Parser::AST::Node] node
|
49
|
+
# @param [Symbol] name
|
45
50
|
#
|
46
51
|
# @return [true]
|
47
|
-
# if local variable
|
52
|
+
# if local variable is defined
|
48
53
|
#
|
49
54
|
# @return [false]
|
50
55
|
# otherwise
|
51
56
|
#
|
52
57
|
# @api private
|
53
58
|
#
|
54
|
-
def
|
55
|
-
|
59
|
+
def local_variable_defined_for_node?(node, name)
|
60
|
+
match(node) do |current|
|
61
|
+
current.include?(name)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Test if local variables where first assigned in body and read by conditional
|
66
|
+
#
|
67
|
+
# @param [Parser::AST::Node] conditional
|
68
|
+
# @param [Parser::AST::Node] body
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
#
|
72
|
+
def first_assignment_in_body_and_used_in_condition?(body, condition)
|
73
|
+
condition_reads = AST.local_variable_reads(condition)
|
74
|
+
|
75
|
+
candidates = AST.local_variable_assignments(body).select do |node|
|
76
|
+
name = node.children.first
|
77
|
+
condition_reads.include?(name)
|
78
|
+
end
|
79
|
+
|
80
|
+
candidates.any? do |node|
|
81
|
+
first_assignment?(node)
|
82
|
+
end
|
56
83
|
end
|
57
84
|
|
58
|
-
|
85
|
+
private
|
86
|
+
|
87
|
+
# Match node
|
59
88
|
#
|
60
89
|
# @param [Parser::AST::Node] node
|
90
|
+
# if block given
|
61
91
|
#
|
62
92
|
# @return [true]
|
63
|
-
# if
|
93
|
+
# if found an matched
|
64
94
|
#
|
65
95
|
# @return [false]
|
66
96
|
# otherwise
|
67
97
|
#
|
68
98
|
# @api private
|
69
99
|
#
|
70
|
-
def
|
71
|
-
|
100
|
+
def match(neddle)
|
101
|
+
@items.each do |node, current, before|
|
102
|
+
if node.equal?(neddle)
|
103
|
+
return yield(current, before)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
false
|
107
|
+
end
|
108
|
+
|
109
|
+
end # LocalVariableScope
|
110
|
+
|
111
|
+
# Local variable scope enumerator
|
112
|
+
class LocalVariableScopeEnumerator
|
113
|
+
include Enumerable
|
114
|
+
|
115
|
+
# Initialize object
|
116
|
+
#
|
117
|
+
# @return [undefined]
|
118
|
+
#
|
119
|
+
# @api private
|
120
|
+
#
|
121
|
+
def initialize
|
122
|
+
@stack = [Set.new]
|
123
|
+
end
|
124
|
+
|
125
|
+
# Enumerate each node with its local variable scope
|
126
|
+
#
|
127
|
+
# @param [Parser::AST::Node] node
|
128
|
+
#
|
129
|
+
# @return [self]
|
130
|
+
#
|
131
|
+
# @api private
|
132
|
+
#
|
133
|
+
def self.each(node, &block)
|
134
|
+
new.each(node, &block)
|
135
|
+
self
|
72
136
|
end
|
73
137
|
|
74
138
|
# Enumerate local variable scope scope
|
@@ -109,7 +173,7 @@ module Unparser
|
|
109
173
|
def visit(node, &block)
|
110
174
|
before = current.dup
|
111
175
|
enter(node)
|
112
|
-
yield node, current, before
|
176
|
+
yield node, current.dup, before
|
113
177
|
node.children.each do |child|
|
114
178
|
if child.kind_of?(Parser::AST::Node)
|
115
179
|
visit(child, &block)
|
@@ -193,6 +257,6 @@ module Unparser
|
|
193
257
|
@stack.pop
|
194
258
|
end
|
195
259
|
|
196
|
-
end #
|
260
|
+
end # LocalVariableScopeEnumerator
|
197
261
|
end # AST
|
198
262
|
end # Unparser
|
data/lib/unparser/emitter.rb
CHANGED
@@ -15,8 +15,14 @@ module Unparser
|
|
15
15
|
#
|
16
16
|
# @api private
|
17
17
|
#
|
18
|
-
def
|
19
|
-
node
|
18
|
+
def local_variable_scope
|
19
|
+
AST::LocalVariableScope.new(node)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(descendant)
|
23
|
+
descendant.class_eval do
|
24
|
+
memoize :local_variable_scope
|
25
|
+
end
|
20
26
|
end
|
21
27
|
|
22
28
|
end
|
@@ -27,8 +33,8 @@ module Unparser
|
|
27
33
|
#
|
28
34
|
# @api private
|
29
35
|
#
|
30
|
-
def
|
31
|
-
parent.
|
36
|
+
def local_variable_scope
|
37
|
+
parent.local_variable_scope
|
32
38
|
end
|
33
39
|
|
34
40
|
# Registry for node emitters
|
data/lib/unparser/emitter/if.rb
CHANGED
@@ -40,7 +40,7 @@ module Unparser
|
|
40
40
|
|
41
41
|
body = if_branch || else_branch
|
42
42
|
|
43
|
-
|
43
|
+
local_variable_scope.first_assignment_in_body_and_used_in_condition?(body, condition)
|
44
44
|
end
|
45
45
|
|
46
46
|
# Emit in postcondition style
|
@@ -70,7 +70,7 @@ module Unparser
|
|
70
70
|
#
|
71
71
|
def postcontrol?
|
72
72
|
return false unless body
|
73
|
-
|
73
|
+
local_variable_scope.first_assignment_in_body_and_used_in_condition?(body, condition)
|
74
74
|
end
|
75
75
|
|
76
76
|
# Emit keyword
|
@@ -7,6 +7,9 @@ describe 'Unparser on ruby corpus' do
|
|
7
7
|
if RUBY_VERSION == '1.9.3'
|
8
8
|
pending 'Corpus test not active for 1.9.3 because of limitations in encoding singalling, see Readme'
|
9
9
|
end
|
10
|
+
if ENV['GUARD']
|
11
|
+
pending 'Do not execute corpus spec under guard'
|
12
|
+
end
|
10
13
|
end
|
11
14
|
ROOT = Pathname.new(__FILE__).parent.parent.parent.parent
|
12
15
|
|
data/unparser.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = 'unparser'
|
5
|
-
gem.version = '0.1.
|
5
|
+
gem.version = '0.1.11'
|
6
6
|
|
7
7
|
gem.authors = ['Markus Schirp']
|
8
8
|
gem.email = 'mbj@schir-dso.com'
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |gem|
|
|
19
19
|
|
20
20
|
gem.required_ruby_version
|
21
21
|
|
22
|
-
gem.add_dependency('parser', '~> 2.1
|
22
|
+
gem.add_dependency('parser', '~> 2.1')
|
23
23
|
gem.add_dependency('procto', '~> 0.0.2')
|
24
24
|
gem.add_dependency('concord', '~> 0.1.4')
|
25
25
|
gem.add_dependency('adamantium', '~> 0.2.0')
|
metadata
CHANGED
@@ -1,99 +1,99 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unparser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Schirp
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
15
|
-
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.1
|
20
|
-
|
19
|
+
version: '2.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
23
|
requirements:
|
22
24
|
- - ~>
|
23
25
|
- !ruby/object:Gem::Version
|
24
|
-
version: 2.1
|
25
|
-
prerelease: false
|
26
|
-
type: :runtime
|
26
|
+
version: '2.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: procto
|
29
|
-
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 0.0.2
|
34
|
-
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
35
37
|
requirements:
|
36
38
|
- - ~>
|
37
39
|
- !ruby/object:Gem::Version
|
38
40
|
version: 0.0.2
|
39
|
-
prerelease: false
|
40
|
-
type: :runtime
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: concord
|
43
|
-
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 0.1.4
|
48
|
-
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
49
51
|
requirements:
|
50
52
|
- - ~>
|
51
53
|
- !ruby/object:Gem::Version
|
52
54
|
version: 0.1.4
|
53
|
-
prerelease: false
|
54
|
-
type: :runtime
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: adamantium
|
57
|
-
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 0.2.0
|
62
|
-
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
65
|
requirements:
|
64
66
|
- - ~>
|
65
67
|
- !ruby/object:Gem::Version
|
66
68
|
version: 0.2.0
|
67
|
-
prerelease: false
|
68
|
-
type: :runtime
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: equalizer
|
71
|
-
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ~>
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: 0.0.9
|
76
|
-
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
79
|
requirements:
|
78
80
|
- - ~>
|
79
81
|
- !ruby/object:Gem::Version
|
80
82
|
version: 0.0.9
|
81
|
-
prerelease: false
|
82
|
-
type: :runtime
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: abstract_type
|
85
|
-
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ~>
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: 0.0.7
|
90
|
-
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
93
|
requirements:
|
92
94
|
- - ~>
|
93
95
|
- !ruby/object:Gem::Version
|
94
96
|
version: 0.0.7
|
95
|
-
prerelease: false
|
96
|
-
type: :runtime
|
97
97
|
description: Generate equivalent source for parser gem AST nodes
|
98
98
|
email: mbj@schir-dso.com
|
99
99
|
executables:
|
@@ -209,7 +209,7 @@ homepage: http://github.com/mbj/unparser
|
|
209
209
|
licenses:
|
210
210
|
- MIT
|
211
211
|
metadata: {}
|
212
|
-
post_install_message:
|
212
|
+
post_install_message:
|
213
213
|
rdoc_options: []
|
214
214
|
require_paths:
|
215
215
|
- lib
|
@@ -224,9 +224,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
224
224
|
- !ruby/object:Gem::Version
|
225
225
|
version: '0'
|
226
226
|
requirements: []
|
227
|
-
rubyforge_project:
|
228
|
-
rubygems_version: 2.
|
229
|
-
signing_key:
|
227
|
+
rubyforge_project:
|
228
|
+
rubygems_version: 2.0.14
|
229
|
+
signing_key:
|
230
230
|
specification_version: 4
|
231
231
|
summary: Generate equivalent source for parser gem AST nodes
|
232
232
|
test_files:
|
@@ -247,3 +247,4 @@ test_files:
|
|
247
247
|
- spec/unit/unparser/comments/take_eol_comments_spec.rb
|
248
248
|
- spec/unit/unparser/emitter/class_methods/handle_spec.rb
|
249
249
|
- spec/unit/unparser_spec.rb
|
250
|
+
has_rdoc:
|