ast 2.1.0 → 2.4.2
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 +5 -5
- data/lib/ast/node.rb +67 -31
- data/lib/ast/processor/mixin.rb +2 -2
- metadata +10 -64
- data/.gitignore +0 -8
- data/.travis.yml +0 -9
- data/.yardopts +0 -1
- data/CHANGELOG.md +0 -9
- data/Gemfile +0 -4
- data/README.md +0 -23
- data/Rakefile +0 -19
- data/ast.gemspec +0 -29
- data/test/helper.rb +0 -17
- data/test/test_ast.rb +0 -243
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8210d16488dff96abdba806c27ddc7d9640e737050096441ec93dcff222b624c
|
4
|
+
data.tar.gz: e01089e2ec37377bf49160eebd8a277c4f481877e9cdfc4af977d860e7b516f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc8e13d06da136e8de38ce6446f9260b35a1dbde3da47b558a256827df93a5d1bfa1130b07bc4fc326a0ac96dbdd112b330ec4b79a47cff647f7b48182803b65
|
7
|
+
data.tar.gz: 6afd93b25aa0d9061fdee5cebdd732303535107ecab668cc8dc37a49a0ee209d0906a9b8a415e1d4b62d4a5fd2b0f7da3263665a156aa9a57c24dd2f5ad89075
|
data/lib/ast/node.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module AST
|
2
4
|
# Node is an immutable class, instances of which represent abstract
|
3
5
|
# syntax tree nodes. It combines semantic information (i.e. anything
|
@@ -42,8 +44,17 @@ module AST
|
|
42
44
|
|
43
45
|
# Returns the children of this node.
|
44
46
|
# The returned value is frozen.
|
47
|
+
# The to_a alias is useful for decomposing nodes concisely.
|
48
|
+
# For example:
|
49
|
+
#
|
50
|
+
# node = s(:gasgn, :$foo, s(:integer, 1))
|
51
|
+
# var_name, value = *node
|
52
|
+
# p var_name # => :$foo
|
53
|
+
# p value # => (integer 1)
|
54
|
+
#
|
45
55
|
# @return [Array]
|
46
56
|
attr_reader :children
|
57
|
+
alias to_a children
|
47
58
|
|
48
59
|
# Returns the precomputed hash value for this node
|
49
60
|
# @return [Fixnum]
|
@@ -80,7 +91,7 @@ module AST
|
|
80
91
|
# By default, each entry in the `properties` hash is assigned to
|
81
92
|
# an instance variable in this instance of Node. A subclass should define
|
82
93
|
# attribute readers for such variables. The values passed in the hash
|
83
|
-
# are not frozen or whitelisted; such behavior can also be implemented
|
94
|
+
# are not frozen or whitelisted; such behavior can also be implemented
|
84
95
|
# by subclassing Node and overriding this method.
|
85
96
|
#
|
86
97
|
# @return [nil]
|
@@ -104,6 +115,7 @@ module AST
|
|
104
115
|
def dup
|
105
116
|
self
|
106
117
|
end
|
118
|
+
alias :clone :dup
|
107
119
|
|
108
120
|
# Returns a new instance of Node where non-nil arguments replace the
|
109
121
|
# corresponding fields of `self`.
|
@@ -128,7 +140,9 @@ module AST
|
|
128
140
|
properties.nil?
|
129
141
|
self
|
130
142
|
else
|
131
|
-
|
143
|
+
copy = original_dup
|
144
|
+
copy.send :initialize, new_type, new_children, new_properties
|
145
|
+
copy
|
132
146
|
end
|
133
147
|
end
|
134
148
|
|
@@ -166,58 +180,80 @@ module AST
|
|
166
180
|
|
167
181
|
alias << append
|
168
182
|
|
169
|
-
# Converts `self` to a
|
183
|
+
# Converts `self` to a pretty-printed s-expression.
|
170
184
|
#
|
185
|
+
# @param [Integer] indent Base indentation level.
|
171
186
|
# @return [String]
|
172
|
-
def
|
173
|
-
"
|
174
|
-
|
187
|
+
def to_sexp(indent=0)
|
188
|
+
indented = " " * indent
|
189
|
+
sexp = "#{indented}(#{fancy_type}"
|
175
190
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
children
|
191
|
+
children.each do |child|
|
192
|
+
if child.is_a?(Node)
|
193
|
+
sexp += "\n#{child.to_sexp(indent + 1)}"
|
194
|
+
else
|
195
|
+
sexp += " #{child.inspect}"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
sexp += ")"
|
200
|
+
|
201
|
+
sexp
|
188
202
|
end
|
189
203
|
|
190
|
-
|
204
|
+
alias to_s to_sexp
|
205
|
+
|
206
|
+
# Converts `self` to a s-expression ruby string.
|
207
|
+
# The code return will recreate the node, using the sexp module s()
|
191
208
|
#
|
192
209
|
# @param [Integer] indent Base indentation level.
|
193
210
|
# @return [String]
|
194
|
-
def
|
211
|
+
def inspect(indent=0)
|
195
212
|
indented = " " * indent
|
196
|
-
sexp = "#{indented}(
|
213
|
+
sexp = "#{indented}s(:#{@type}"
|
197
214
|
|
198
|
-
|
199
|
-
child.is_a?(Node)
|
200
|
-
|
201
|
-
|
202
|
-
children.each_with_index do |child, idx|
|
203
|
-
if child.is_a?(Node) && idx >= first_node_child
|
204
|
-
sexp << "\n#{child.to_sexp(indent + 1)}"
|
215
|
+
children.each do |child|
|
216
|
+
if child.is_a?(Node)
|
217
|
+
sexp += ",\n#{child.inspect(indent + 1)}"
|
205
218
|
else
|
206
|
-
sexp
|
219
|
+
sexp += ", #{child.inspect}"
|
207
220
|
end
|
208
221
|
end
|
209
222
|
|
210
|
-
sexp
|
223
|
+
sexp += ")"
|
211
224
|
|
212
225
|
sexp
|
213
226
|
end
|
214
|
-
alias :inspect :to_sexp
|
215
227
|
|
216
228
|
# @return [AST::Node] self
|
217
229
|
def to_ast
|
218
230
|
self
|
219
231
|
end
|
220
232
|
|
233
|
+
# Converts `self` to an Array where the first element is the type as a Symbol,
|
234
|
+
# and subsequent elements are the same representation of its children.
|
235
|
+
#
|
236
|
+
# @return [Array<Symbol, [...Array]>]
|
237
|
+
def to_sexp_array
|
238
|
+
children_sexp_arrs = children.map do |child|
|
239
|
+
if child.is_a?(Node)
|
240
|
+
child.to_sexp_array
|
241
|
+
else
|
242
|
+
child
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
[type, *children_sexp_arrs]
|
247
|
+
end
|
248
|
+
|
249
|
+
# Enables matching for Node, where type is the first element
|
250
|
+
# and the children are remaining items.
|
251
|
+
#
|
252
|
+
# @return [Array]
|
253
|
+
def deconstruct
|
254
|
+
[type, *children]
|
255
|
+
end
|
256
|
+
|
221
257
|
protected
|
222
258
|
|
223
259
|
# Returns `@type` with all underscores replaced by dashes. This allows
|
data/lib/ast/processor/mixin.rb
CHANGED
@@ -23,7 +23,7 @@ module AST
|
|
23
23
|
# into a variable named `<string-literal>`,
|
24
24
|
# * `(load <string-literal>)`: loads value of a variable named
|
25
25
|
# `<string-literal>`,
|
26
|
-
# * `(each <node> ...)
|
26
|
+
# * `(each <node> ...)`: computes each of the `<node>`s and
|
27
27
|
# prints the result.
|
28
28
|
#
|
29
29
|
# All AST nodes have the same Ruby class, and therefore they don't
|
@@ -37,7 +37,7 @@ module AST
|
|
37
37
|
# require 'ast'
|
38
38
|
#
|
39
39
|
# class ArithmeticsProcessor
|
40
|
-
# include AST::Processor::
|
40
|
+
# include AST::Processor::Mixin
|
41
41
|
# # This method traverses any binary operators such as (add)
|
42
42
|
# # or (multiply).
|
43
43
|
# def process_binary_op(node)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ast
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- whitequark
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '12.3'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '12.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bacon
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -68,60 +68,18 @@ dependencies:
|
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: coveralls
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: json_pure
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: mime-types
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '1.25'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '1.25'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: rest-client
|
113
71
|
requirement: !ruby/object:Gem::Requirement
|
114
72
|
requirements:
|
115
73
|
- - "~>"
|
116
74
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
75
|
+
version: 0.8.23
|
118
76
|
type: :development
|
119
77
|
prerelease: false
|
120
78
|
version_requirements: !ruby/object:Gem::Requirement
|
121
79
|
requirements:
|
122
80
|
- - "~>"
|
123
81
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
82
|
+
version: 0.8.23
|
125
83
|
- !ruby/object:Gem::Dependency
|
126
84
|
name: yard
|
127
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -157,28 +115,18 @@ executables: []
|
|
157
115
|
extensions: []
|
158
116
|
extra_rdoc_files: []
|
159
117
|
files:
|
160
|
-
- ".gitignore"
|
161
|
-
- ".travis.yml"
|
162
|
-
- ".yardopts"
|
163
|
-
- CHANGELOG.md
|
164
|
-
- Gemfile
|
165
118
|
- LICENSE.MIT
|
166
119
|
- README.YARD.md
|
167
|
-
- README.md
|
168
|
-
- Rakefile
|
169
|
-
- ast.gemspec
|
170
120
|
- lib/ast.rb
|
171
121
|
- lib/ast/node.rb
|
172
122
|
- lib/ast/processor.rb
|
173
123
|
- lib/ast/processor/mixin.rb
|
174
124
|
- lib/ast/sexp.rb
|
175
|
-
- test/helper.rb
|
176
|
-
- test/test_ast.rb
|
177
125
|
homepage: https://whitequark.github.io/ast/
|
178
126
|
licenses:
|
179
127
|
- MIT
|
180
128
|
metadata: {}
|
181
|
-
post_install_message:
|
129
|
+
post_install_message:
|
182
130
|
rdoc_options: []
|
183
131
|
require_paths:
|
184
132
|
- lib
|
@@ -193,10 +141,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
193
141
|
- !ruby/object:Gem::Version
|
194
142
|
version: '0'
|
195
143
|
requirements: []
|
196
|
-
|
197
|
-
|
198
|
-
signing_key:
|
144
|
+
rubygems_version: 3.2.3
|
145
|
+
signing_key:
|
199
146
|
specification_version: 4
|
200
147
|
summary: A library for working with Abstract Syntax Trees.
|
201
148
|
test_files: []
|
202
|
-
has_rdoc:
|
data/.gitignore
DELETED
data/.travis.yml
DELETED
data/.yardopts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
-r README.YARD.md -m markdown --protected
|
data/CHANGELOG.md
DELETED
data/Gemfile
DELETED
data/README.md
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
# AST
|
2
|
-
|
3
|
-
[](https://travis-ci.org/whitequark/ast)
|
4
|
-
[](https://codeclimate.com/github/whitequark/ast)
|
5
|
-
[](https://coveralls.io/r/whitequark/ast)
|
6
|
-
|
7
|
-
AST is a small library for working with immutable abstract syntax trees.
|
8
|
-
|
9
|
-
## Installation
|
10
|
-
|
11
|
-
$ gem install ast
|
12
|
-
|
13
|
-
## Usage
|
14
|
-
|
15
|
-
See the documentation at [GitHub](http://whitequark.github.com/ast/frames.html) or [rdoc.info](http://rdoc.info/gems/ast).
|
16
|
-
|
17
|
-
## Contributing
|
18
|
-
|
19
|
-
1. Fork it
|
20
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
21
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
22
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
23
|
-
5. Create new Pull Request
|
data/Rakefile
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'bundler/gem_tasks'
|
2
|
-
require 'bundler/setup'
|
3
|
-
|
4
|
-
task :default => :test
|
5
|
-
|
6
|
-
desc "Run test suite"
|
7
|
-
task :test do
|
8
|
-
sh "bacon -Itest -a"
|
9
|
-
end
|
10
|
-
|
11
|
-
PAGES_REPO = 'git@github.com:whitequark/ast'
|
12
|
-
|
13
|
-
desc "Build and deploy documentation to GitHub pages"
|
14
|
-
task :pages do
|
15
|
-
system "git clone #{PAGES_REPO} gh-temp/ -b gh-pages; rm gh-temp/* -rf; touch gh-temp/.nojekyll" or abort
|
16
|
-
system "yardoc -o gh-temp/;" or abort
|
17
|
-
system "cd gh-temp/; git add -A; git commit -m 'Updated pages.'; git push -f origin gh-pages" or abort
|
18
|
-
FileUtils.rm_rf 'gh-temp'
|
19
|
-
end
|
data/ast.gemspec
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
Gem::Specification.new do |s|
|
2
|
-
s.name = 'ast'
|
3
|
-
s.version = '2.1.0'
|
4
|
-
s.license = 'MIT'
|
5
|
-
s.authors = ["whitequark"]
|
6
|
-
s.email = ["whitequark@whitequark.org"]
|
7
|
-
s.homepage = "https://whitequark.github.io/ast/"
|
8
|
-
s.summary = %q{A library for working with Abstract Syntax Trees.}
|
9
|
-
s.description = s.summary
|
10
|
-
|
11
|
-
s.files = `git ls-files`.split("\n")
|
12
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
13
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
|
-
s.require_paths = ["lib"]
|
15
|
-
|
16
|
-
s.add_development_dependency 'rake', '~> 10.0'
|
17
|
-
|
18
|
-
s.add_development_dependency 'bacon', '~> 1.2'
|
19
|
-
s.add_development_dependency 'bacon-colored_output'
|
20
|
-
s.add_development_dependency 'simplecov'
|
21
|
-
|
22
|
-
s.add_development_dependency 'coveralls'
|
23
|
-
s.add_development_dependency 'json_pure' # for coveralls on 1.9.2
|
24
|
-
s.add_development_dependency 'mime-types', '~> 1.25' # for coveralls on 1.8.7
|
25
|
-
s.add_development_dependency 'rest-client', '~> 1.6.7' # 1.8.7
|
26
|
-
|
27
|
-
s.add_development_dependency 'yard'
|
28
|
-
s.add_development_dependency 'kramdown'
|
29
|
-
end
|
data/test/helper.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'bacon'
|
2
|
-
require 'bacon/colored_output'
|
3
|
-
|
4
|
-
require 'simplecov'
|
5
|
-
require 'coveralls'
|
6
|
-
|
7
|
-
SimpleCov.start do
|
8
|
-
self.formatter = SimpleCov::Formatter::MultiFormatter[
|
9
|
-
SimpleCov::Formatter::HTMLFormatter,
|
10
|
-
Coveralls::SimpleCov::Formatter
|
11
|
-
]
|
12
|
-
|
13
|
-
# Exclude the testsuite itself.
|
14
|
-
add_filter "/test/"
|
15
|
-
end
|
16
|
-
|
17
|
-
require 'ast'
|
data/test/test_ast.rb
DELETED
@@ -1,243 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe AST::Node do
|
4
|
-
extend AST::Sexp
|
5
|
-
|
6
|
-
class MetaNode < AST::Node
|
7
|
-
attr_reader :meta
|
8
|
-
end
|
9
|
-
|
10
|
-
before do
|
11
|
-
@node = AST::Node.new(:node, [ 0, 1 ])
|
12
|
-
@metanode = MetaNode.new(:node, [ 0, 1 ], :meta => 'value')
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'should have accessors for type and children' do
|
16
|
-
@node.type.should.equal :node
|
17
|
-
@node.children.should.equal [0, 1]
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'should set metadata' do
|
21
|
-
@metanode.meta.should.equal 'value'
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'should be frozen' do
|
25
|
-
@node.frozen?.should.be.true
|
26
|
-
@node.children.frozen?.should.be.true
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'should return self when duping' do
|
30
|
-
@node.dup.should.equal? @node
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should return an updated node, but only if needed' do
|
34
|
-
@node.updated().should.be.identical_to @node
|
35
|
-
@node.updated(:node).should.be.identical_to @node
|
36
|
-
@node.updated(nil, [0, 1]).should.be.identical_to @node
|
37
|
-
|
38
|
-
updated = @node.updated(:other_node)
|
39
|
-
updated.should.not.be.identical_to @node
|
40
|
-
updated.type.should.equal :other_node
|
41
|
-
updated.children.should.equal @node.children
|
42
|
-
|
43
|
-
updated.frozen?.should.be.true
|
44
|
-
|
45
|
-
updated = @node.updated(nil, [1, 1])
|
46
|
-
updated.should.not.be.identical_to @node
|
47
|
-
updated.type.should.equal @node.type
|
48
|
-
updated.children.should.equal [1, 1]
|
49
|
-
|
50
|
-
updated = @metanode.updated(nil, nil, :meta => 'other_value')
|
51
|
-
updated.meta.should.equal 'other_value'
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'should use fancy type in to_s' do
|
55
|
-
node = AST::Node.new(:ast_node)
|
56
|
-
node.to_s.should.equal '(ast-node ...)'
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'should format to_sexp correctly' do
|
60
|
-
AST::Node.new(:a, [ :sym, [ 1, 2 ] ]).to_sexp.should.equal '(a :sym [1, 2])'
|
61
|
-
AST::Node.new(:a, [ :sym, @node ]).to_sexp.should.equal "(a :sym\n (node 0 1))"
|
62
|
-
AST::Node.new(:a, [ :sym,
|
63
|
-
AST::Node.new(:b, [ @node, @node ])
|
64
|
-
]).to_sexp.should.equal "(a :sym\n (b\n (node 0 1)\n (node 0 1)))"
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'should return self in to_ast' do
|
68
|
-
@node.to_ast.should.be.identical_to @node
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'should only use type and children to compute #hash' do
|
72
|
-
@node.hash.should.equal([@node.type, @node.children, @node.class].hash)
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'should only use type and children in #eql? comparisons' do
|
76
|
-
# Not identical but equivalent
|
77
|
-
@node.eql?(AST::Node.new(:node, [0, 1])).should.be.true
|
78
|
-
# Not identical and not equivalent
|
79
|
-
@node.eql?(AST::Node.new(:other, [0, 1])).should.be.false
|
80
|
-
# Not identical and not equivalent because of differend class
|
81
|
-
@node.eql?(@metanode).should.be.false
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'should only use type and children in #== comparisons' do
|
85
|
-
@node.should.equal @node
|
86
|
-
@node.should.equal @metanode
|
87
|
-
@node.should.not.equal :foo
|
88
|
-
|
89
|
-
mock_node = Object.new.tap do |obj|
|
90
|
-
def obj.to_ast
|
91
|
-
self
|
92
|
-
end
|
93
|
-
|
94
|
-
def obj.type
|
95
|
-
:node
|
96
|
-
end
|
97
|
-
|
98
|
-
def obj.children
|
99
|
-
[ 0, 1 ]
|
100
|
-
end
|
101
|
-
end
|
102
|
-
@node.should.equal mock_node
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'should allow to decompose nodes with a, b = *node' do
|
106
|
-
node = s(:gasgn, :$foo, s(:integer, 1))
|
107
|
-
|
108
|
-
var_name, value = *node
|
109
|
-
var_name.should.equal :$foo
|
110
|
-
value.should.equal s(:integer, 1)
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'should concatenate with arrays' do
|
114
|
-
node = s(:gasgn, :$foo)
|
115
|
-
(node + [s(:integer, 1)]).
|
116
|
-
should.equal s(:gasgn, :$foo, s(:integer, 1))
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'should append elements' do
|
120
|
-
node = s(:array)
|
121
|
-
(node << s(:integer, 1) << s(:string, "foo")).
|
122
|
-
should.equal s(:array, s(:integer, 1), s(:string, "foo"))
|
123
|
-
end
|
124
|
-
|
125
|
-
begin
|
126
|
-
eval <<-CODE
|
127
|
-
it 'should not trigger a rubinius bug' do
|
128
|
-
bar = [ s(:bar, 1) ]
|
129
|
-
baz = s(:baz, 2)
|
130
|
-
s(:foo, *bar, baz).should.equal s(:foo, s(:bar, 1), s(:baz, 2))
|
131
|
-
end
|
132
|
-
CODE
|
133
|
-
rescue SyntaxError
|
134
|
-
# Running on 1.8, ignore.
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
describe AST::Processor do
|
139
|
-
extend AST::Sexp
|
140
|
-
|
141
|
-
def have_sexp(text)
|
142
|
-
text = text.lines.map { |line| line.sub /^ +\|(.+)/, '\1' }.join.rstrip
|
143
|
-
lambda { |ast| ast.to_sexp == text }
|
144
|
-
end
|
145
|
-
|
146
|
-
class MockProcessor < AST::Processor
|
147
|
-
attr_reader :counts
|
148
|
-
|
149
|
-
def initialize
|
150
|
-
@counts = Hash.new(0)
|
151
|
-
end
|
152
|
-
|
153
|
-
def on_root(node)
|
154
|
-
count_node(node)
|
155
|
-
node.updated(nil, process_all(node.children))
|
156
|
-
end
|
157
|
-
alias on_body on_root
|
158
|
-
|
159
|
-
def on_def(node)
|
160
|
-
count_node(node)
|
161
|
-
name, arglist, body = node.children
|
162
|
-
node.updated(:def, [ name, process(arglist), process(body) ])
|
163
|
-
end
|
164
|
-
|
165
|
-
def handler_missing(node)
|
166
|
-
count_node(node)
|
167
|
-
end
|
168
|
-
|
169
|
-
def count_node(node)
|
170
|
-
@counts[node.type] += 1; nil
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
before do
|
175
|
-
@ast = AST::Node.new(:root, [
|
176
|
-
AST::Node.new(:def, [ :func,
|
177
|
-
AST::Node.new(:arglist, [ :foo, :bar ]),
|
178
|
-
AST::Node.new(:body, [
|
179
|
-
AST::Node.new(:invoke, [ :puts, "Hello world" ])
|
180
|
-
])
|
181
|
-
]),
|
182
|
-
AST::Node.new(:invoke, [ :func ])
|
183
|
-
])
|
184
|
-
|
185
|
-
@processor = MockProcessor.new
|
186
|
-
end
|
187
|
-
|
188
|
-
it 'should visit every node' do
|
189
|
-
@processor.process(@ast).should.equal @ast
|
190
|
-
@processor.counts.should.equal({
|
191
|
-
:root => 1,
|
192
|
-
:def => 1,
|
193
|
-
:arglist => 1,
|
194
|
-
:body => 1,
|
195
|
-
:invoke => 2,
|
196
|
-
})
|
197
|
-
end
|
198
|
-
|
199
|
-
it 'should be able to replace inner nodes' do
|
200
|
-
def @processor.on_arglist(node)
|
201
|
-
node.updated(:new_fancy_arglist)
|
202
|
-
end
|
203
|
-
|
204
|
-
@processor.process(@ast).should have_sexp(<<-SEXP)
|
205
|
-
|(root
|
206
|
-
| (def :func
|
207
|
-
| (new-fancy-arglist :foo :bar)
|
208
|
-
| (body
|
209
|
-
| (invoke :puts "Hello world")))
|
210
|
-
| (invoke :func))
|
211
|
-
SEXP
|
212
|
-
end
|
213
|
-
|
214
|
-
it 'should build sexps' do
|
215
|
-
s(:add,
|
216
|
-
s(:integer, 1),
|
217
|
-
s(:multiply,
|
218
|
-
s(:integer, 2),
|
219
|
-
s(:integer, 3))).should have_sexp(<<-SEXP)
|
220
|
-
|(add
|
221
|
-
| (integer 1)
|
222
|
-
| (multiply
|
223
|
-
| (integer 2)
|
224
|
-
| (integer 3)))
|
225
|
-
SEXP
|
226
|
-
end
|
227
|
-
|
228
|
-
it 'should return nil if passed nil' do
|
229
|
-
@processor.process(nil).should == nil
|
230
|
-
end
|
231
|
-
|
232
|
-
it 'should refuse to process non-nodes' do
|
233
|
-
lambda { @processor.process([]) }.should.raise NoMethodError, %r|to_ast|
|
234
|
-
end
|
235
|
-
|
236
|
-
it 'should allow to visit nodes with process_all(node)' do
|
237
|
-
@processor.process_all s(:foo, s(:bar), s(:integer, 1))
|
238
|
-
@processor.counts.should.equal({
|
239
|
-
:bar => 1,
|
240
|
-
:integer => 1,
|
241
|
-
})
|
242
|
-
end
|
243
|
-
end
|