Skip to content

Commit b4f4132

Browse files
committed
Fix up style violations
1 parent 999292b commit b4f4132

File tree

4 files changed

+196
-84
lines changed

4 files changed

+196
-84
lines changed

.rubocop.yml

+3
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ Naming/MethodParameterName:
4646
Naming/RescuedExceptionsVariableName:
4747
PreferredName: error
4848

49+
Style/CaseEquality:
50+
Enabled: false
51+
4952
Style/ExplicitBlockArgument:
5053
Enabled: false
5154

lib/syntax_tree/cli.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,8 @@ def run(item)
193193
class Expr < Action
194194
def run(item)
195195
program = item.handler.parse(item.source)
196-
if Program === program and expressions = program.statements.body and
197-
expressions.size == 1
196+
197+
if (expressions = program.statements.body) && expressions.size == 1
198198
puts expressions.first.construct_keys
199199
else
200200
warn("The input to `stree expr` must be a single expression.")

lib/syntax_tree/pattern.rb

+190-81
Original file line numberDiff line numberDiff line change
@@ -75,103 +75,212 @@ def compile
7575

7676
private
7777

78+
# Shortcut for combining two procs into one that returns true if both return
79+
# true.
7880
def combine_and(left, right)
79-
->(node) { left.call(node) && right.call(node) }
81+
->(other) { left.call(other) && right.call(other) }
8082
end
8183

84+
# Shortcut for combining two procs into one that returns true if either
85+
# returns true.
8286
def combine_or(left, right)
83-
->(node) { left.call(node) || right.call(node) }
87+
->(other) { left.call(other) || right.call(other) }
8488
end
8589

86-
def compile_node(root)
87-
if AryPtn === root and root.rest.nil? and root.posts.empty?
88-
constant = root.constant
89-
compiled_constant = compile_node(constant) if constant
90+
# Raise an error because the given node is not supported.
91+
def compile_error(node)
92+
raise CompilationError, PP.pp(node, +"").chomp
93+
end
9094

91-
preprocessed = root.requireds.map { |required| compile_node(required) }
95+
# There are a couple of nodes (string literals, dynamic symbols, and regexp)
96+
# that contain list of parts. This can include plain string content,
97+
# interpolated expressions, and interpolated variables. We only support
98+
# plain string content, so this method will extract out the plain string
99+
# content if it is the only element in the list.
100+
def extract_string(node)
101+
parts = node.parts
92102

93-
compiled_requireds = ->(node) do
94-
deconstructed = node.deconstruct
103+
if parts.length == 1 && (part = parts.first) && part.is_a?(TStringContent)
104+
part.value
105+
end
106+
end
95107

96-
deconstructed.length == preprocessed.length &&
97-
preprocessed
98-
.zip(deconstructed)
99-
.all? { |(matcher, value)| matcher.call(value) }
100-
end
108+
# in [foo, bar, baz]
109+
def compile_aryptn(node)
110+
compile_error(node) if !node.rest.nil? || node.posts.any?
101111

102-
if compiled_constant
103-
combine_and(compiled_constant, compiled_requireds)
104-
else
105-
compiled_requireds
106-
end
107-
elsif Binary === root and root.operator == :|
108-
combine_or(compile_node(root.left), compile_node(root.right))
109-
elsif Const === root and SyntaxTree.const_defined?(root.value)
110-
clazz = SyntaxTree.const_get(root.value)
111-
112-
->(node) { node.is_a?(clazz) }
113-
elsif Const === root and Object.const_defined?(root.value)
114-
clazz = Object.const_get(root.value)
115-
116-
->(node) { node.is_a?(clazz) }
117-
elsif ConstPathRef === root and VarRef === root.parent and
118-
Const === root.parent.value and
119-
root.parent.value.value == "SyntaxTree"
120-
compile_node(root.constant)
121-
elsif DynaSymbol === root and root.parts.empty?
112+
constant = node.constant
113+
compiled_constant = compile_node(constant) if constant
114+
115+
preprocessed = node.requireds.map { |required| compile_node(required) }
116+
117+
compiled_requireds = ->(other) do
118+
deconstructed = other.deconstruct
119+
120+
deconstructed.length == preprocessed.length &&
121+
preprocessed
122+
.zip(deconstructed)
123+
.all? { |(matcher, value)| matcher.call(value) }
124+
end
125+
126+
if compiled_constant
127+
combine_and(compiled_constant, compiled_requireds)
128+
else
129+
compiled_requireds
130+
end
131+
end
132+
133+
# in foo | bar
134+
def compile_binary(node)
135+
compile_error(node) if node.operator != :|
136+
137+
combine_or(compile_node(node.left), compile_node(node.right))
138+
end
139+
140+
# in Ident
141+
# in String
142+
def compile_const(node)
143+
value = node.value
144+
145+
if SyntaxTree.const_defined?(value)
146+
clazz = SyntaxTree.const_get(value)
147+
148+
->(other) { clazz === other }
149+
elsif Object.const_defined?(value)
150+
clazz = Object.const_get(value)
151+
152+
->(other) { clazz === other }
153+
else
154+
compile_error(node)
155+
end
156+
end
157+
158+
# in SyntaxTree::Ident
159+
def compile_const_path_ref(node)
160+
parent = node.parent
161+
compile_error(node) if !parent.is_a?(VarRef) || !parent.value.is_a?(Const)
162+
163+
if parent.value.value == "SyntaxTree"
164+
compile_node(node.constant)
165+
else
166+
compile_error(node)
167+
end
168+
end
169+
170+
# in :""
171+
# in :"foo"
172+
def compile_dyna_symbol(node)
173+
if node.parts.empty?
122174
symbol = :""
123175

124-
->(node) { node == symbol }
125-
elsif DynaSymbol === root and parts = root.parts and parts.size == 1 and
126-
TStringContent === parts[0]
127-
symbol = parts[0].value.to_sym
128-
129-
->(node) { node == symbol }
130-
elsif HshPtn === root and root.keyword_rest.nil?
131-
compiled_constant = compile_node(root.constant)
132-
133-
preprocessed =
134-
root.keywords.to_h do |keyword, value|
135-
unless keyword.is_a?(Label)
136-
raise CompilationError, PP.pp(root, +"").chomp
137-
end
138-
[keyword.value.chomp(":").to_sym, compile_node(value)]
139-
end
140-
141-
compiled_keywords = ->(node) do
142-
deconstructed = node.deconstruct_keys(preprocessed.keys)
143-
144-
preprocessed.all? do |keyword, matcher|
145-
matcher.call(deconstructed[keyword])
146-
end
176+
->(other) { symbol === other }
177+
elsif (value = extract_string(node))
178+
symbol = value.to_sym
179+
180+
->(other) { symbol === other }
181+
else
182+
compile_error(root)
183+
end
184+
end
185+
186+
# in Ident[value: String]
187+
# in { value: String }
188+
def compile_hshptn(node)
189+
compile_error(node) unless node.keyword_rest.nil?
190+
compiled_constant = compile_node(node.constant) if node.constant
191+
192+
preprocessed =
193+
node.keywords.to_h do |keyword, value|
194+
compile_error(node) unless keyword.is_a?(Label)
195+
[keyword.value.chomp(":").to_sym, compile_node(value)]
147196
end
148197

149-
if compiled_constant
150-
combine_and(compiled_constant, compiled_keywords)
151-
else
152-
compiled_keywords
198+
compiled_keywords = ->(other) do
199+
deconstructed = other.deconstruct_keys(preprocessed.keys)
200+
201+
preprocessed.all? do |keyword, matcher|
202+
matcher.call(deconstructed[keyword])
153203
end
154-
elsif RegexpLiteral === root and parts = root.parts and
155-
parts.size == 1 and TStringContent === parts[0]
156-
regexp = /#{parts[0].value}/
157-
158-
->(attribute) { regexp.match?(attribute) }
159-
elsif StringLiteral === root and root.parts.empty?
160-
->(attribute) { attribute == "" }
161-
elsif StringLiteral === root and parts = root.parts and
162-
parts.size == 1 and TStringContent === parts[0]
163-
value = parts[0].value
164-
->(attribute) { attribute == value }
165-
elsif SymbolLiteral === root
166-
symbol = root.value.value.to_sym
167-
168-
->(attribute) { attribute == symbol }
169-
elsif VarRef === root and Const === root.value
170-
compile_node(root.value)
171-
elsif VarRef === root and Kw === root.value and root.value.value.nil?
172-
->(attribute) { attribute.nil? }
204+
end
205+
206+
if compiled_constant
207+
combine_and(compiled_constant, compiled_keywords)
208+
else
209+
compiled_keywords
210+
end
211+
end
212+
213+
# in /foo/
214+
def compile_regexp_literal(node)
215+
if (value = extract_string(node))
216+
regexp = /#{value}/
217+
218+
->(attribute) { regexp === attribute }
219+
else
220+
compile_error(node)
221+
end
222+
end
223+
224+
# in ""
225+
# in "foo"
226+
def compile_string_literal(node)
227+
if node.parts.empty?
228+
->(attribute) { "" === attribute }
229+
elsif (value = extract_string(node))
230+
->(attribute) { value === attribute }
231+
else
232+
compile_error(node)
233+
end
234+
end
235+
236+
# in :+
237+
# in :foo
238+
def compile_symbol_literal(node)
239+
symbol = node.value.value.to_sym
240+
241+
->(attribute) { symbol === attribute }
242+
end
243+
244+
# in Foo
245+
# in nil
246+
def compile_var_ref(node)
247+
value = node.value
248+
249+
if value.is_a?(Const)
250+
compile_node(value)
251+
elsif value.is_a?(Kw) && value.value.nil?
252+
->(attribute) { nil === attribute }
253+
else
254+
compile_error(node)
255+
end
256+
end
257+
258+
# Compile any kind of node. Dispatch out to the individual compilation
259+
# methods based on the type of node.
260+
def compile_node(node)
261+
case node
262+
when AryPtn
263+
compile_aryptn(node)
264+
when Binary
265+
compile_binary(node)
266+
when Const
267+
compile_const(node)
268+
when ConstPathRef
269+
compile_const_path_ref(node)
270+
when DynaSymbol
271+
compile_dyna_symbol(node)
272+
when HshPtn
273+
compile_hshptn(node)
274+
when RegexpLiteral
275+
compile_regexp_literal(node)
276+
when StringLiteral
277+
compile_string_literal(node)
278+
when SymbolLiteral
279+
compile_symbol_literal(node)
280+
when VarRef
281+
compile_var_ref(node)
173282
else
174-
raise CompilationError, PP.pp(root, +"").chomp
283+
compile_error(node)
175284
end
176285
end
177286
end

test/idempotency_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
return unless ENV["CI"] and RUBY_ENGINE != "truffleruby"
3+
return if !ENV["CI"] || RUBY_ENGINE == "truffleruby"
44
require_relative "test_helper"
55

66
module SyntaxTree

0 commit comments

Comments
 (0)