Skip to content

Instantly share code, notes, and snippets.

@tompng
Last active December 10, 2023 17:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tompng/a065d8cf2475c9b6bde5cc6801b3e846 to your computer and use it in GitHub Desktop.
Save tompng/a065d8cf2475c9b6bde5cc6801b3e846 to your computer and use it in GitHub Desktop.
def run
$VERBOSE=nil
tokens = %w[1 + * ** a in ( ) [ ] = . .. => <<]
cnt = 0
output = {}
(2..8).each do |n|
cnt = 0
tokens.repeated_permutation(n).each do |tokens|
code = tokens.join('') # or join(' ')
# Ruby's bug already fixed in 3.3
next if code.end_with?('1.')
next if code.include?('..=') # a..==1
next if code.include?('..<<') # a..<<+1
a = begin;RubyVM::AbstractSyntaxTree.parse(code);true;rescue SyntaxError;false;end
b = Prism.parse_success?(code)
unless a == b
cnt += 1
v = Suppresser.new
v.visit(Prism.parse(code).value) if b
if v.matched
(output[v.matched] ||= []) << code
else
p [code, a, b]
end
end
end
p [n, cnt]
p output.transform_values(&:size).sort_by(&:last)
end
binding.irb
end
class Suppresser < Prism::Visitor
attr_reader :matched
def visit_call_node(node)
super
# + b = *c
@matched = __LINE__ if node in { opening_loc: nil, receiver: { depth:, value: Prism::SplatNode } }
# a b = *c
@matched = __LINE__ if node in { arguments: { arguments: [{ depth:, value: Prism::SplatNode }] } }
# a( a = * 1 )
@matched = __LINE__ if node in { arguments: { arguments: [{ depth:, value: Prism::SplatNode }] } }
# a 1 .. * 1
@matched = __LINE__ if node in { receiver: { receiver:, opening_loc: nil } }
# + ( * ) = 1
@matched = __LINE__ if node in { receiver: Prism::MultiWriteNode }
# a = b .. * c
@matched = __LINE__ if node in { receiver: Prism::LocalVariableWriteNode }
# ( + ( * ) )
@matched = __LINE__ if node in { receiver: Prism::MultiTargetNode }
# + 1 [ ] = * 1
@matched = __LINE__ if node in { opening_loc: nil, receiver: { name: /=\z/, arguments: { arguments: [Prism::SplatNode]} } }
# a a . a = * a
@matched = __LINE__ if node in { opening_loc: nil, arguments: { arguments: [{ name: /=\z/, arguments: { arguments: [Prism::SplatNode] } }] } }
end
def visit_call_operator_write_node(node)
super
# a.* += 1
@matched = __LINE__ if node in { write_name: /[-+*\/%&|<=>^]=\z/ }
# a.[] += 1
@matched = __LINE__ if node in { write_name: :[]=, call_operator_loc: Prism::Location }
end
def visit_arguments_node(node)
super
# ( a ( * ) )
# (a.b = ( * ))
@matched = __LINE__ if node in { arguments: [*, Prism::MultiTargetNode, *] }
# a ( * ) = b
# a[ ( * ) = 1 ]
@matched = __LINE__ if node in { arguments: [*, Prism::MultiWriteNode, *] }
# a[ * a = * 1 ]
@matched = __LINE__ if node in { arguments: [*, { expression: Prism::LocalVariableWriteNode }, *] }
end
def visit_hash_pattern_node(node)
super
# a in (**)
# a in [**]
@matched = __LINE__ if node in { opening_loc: nil }
end
def visit_array_node(node)
super
# [ a = * b ]
@matched = __LINE__ if node in { elements: [*, { depth:, value: Prism::SplatNode }, *] }
# [ ( * ) = a ]
@matched = __LINE__ if node in { elements: [*, Prism::MultiWriteNode, *] }
# [ * a = * b ]
# a = * a = * b
@matched = __LINE__ if node in { elements: [*, { expression: Prism::LocalVariableWriteNode }, *] }
end
def visit_assoc_splat_node(node)
super
# a(** a = * a)
@matched = __LINE__ if node in { value: { depth:, value: Prism::SplatNode } }
end
def visit_assoc_node(node)
super
# a a = * 1 => 1
@matched = __LINE__ if node in { key: { depth:, value: Prism::SplatNode } }
# a 1 => b = * c
@matched = __LINE__ if node in { value: { depth:, value: Prism::SplatNode } }
# a a 1 => 1 => 1
@matched = __LINE__ if node in { key: { receiver:, opening_loc: nil, arguments: [Prism::Node, *]} }
end
def visit_splat_node(node)
super
# * = * a = * 1
@matched = __LINE__ if node in { expression: { depth:, value: Prism::SplatNode } }
end
def visit_splat_node(node)
super
# a(* a = * a)
@matched = __LINE__ if node in { expression: { depth:, value: Prism::SplatNode } }
end
def visit_range_node(node)
super
# a .. b..
@matched = __LINE__ if node in { right: Prism::RangeNode }
# + .. a ..
# a + .. b ..
@matched = __LINE__ if node in { left: { receiver:, call_operator_loc: nil } }
# * = .. 1 ..
@matched = __LINE__ if node in { left: Prism::MultiWriteNode }
# a = .. 1 ..
@matched = __LINE__ if node in { left: Prism::LocalVariableWriteNode }
# a . b = .. 1 ..
@matched = __LINE__ if node in { left: { receiver:, name: /=\z/ } }
# a+=..1..
@matched = __LINE__ if node in { left: Prism::LocalVariableOperatorWriteNode }
# .. a = *b
@matched = __LINE__ if node in { right: { depth:, value: Prism::SplatNode } }
# ( .. ( * ) )
@matched = __LINE__ if node in { right: Prism::MultiTargetNode }
# .. ( * ) = 1
@matched = __LINE__ if node in { right: Prism::MultiWriteNode }
# .. 1 [ ] = * 1
@matched = __LINE__ if node in { right: { name: /=\z/, arguments: { arguments: [Prism::SplatNode] } } }
end
def visit_match_predicate_node(node)
super
# a, b = c in d
@matched = __LINE__ if node in { value: Prism::MultiWriteNode }
# a b in c
@matched = __LINE__ if node in { value: { receiver:, opening_loc: nil, arguments: [Prism::Node,] } }
# a = * 1 in 1
@matched = __LINE__ if node in { value: { depth:, value: { elements: [*, Prism::SplatNode, *] } } }
# a = b 1 in 1
@matched = __LINE__ if node in { value: { depth:, value: { receiver:, opening_loc: nil } } }
end
def visit_match_required_node(node)
super
# * = 1 => 1
@matched = __LINE__ if node in { value: Prism::MultiWriteNode }
# a 1 => 1 => 1
@matched = __LINE__ if node in { value: { receiver:, opening_loc: nil } }
# a = * 1 => 1
@matched = __LINE__ if node in { value: { depth:, value: { elements: [*, Prism::SplatNode, *] } } }
end
def visit_capture_pattern_node(node)
super
# 1 in a => a
@matched = __LINE__ if node in { value: { name: }, target: { name: ^name } }
# 1 in 1 => a => a
@matched = __LINE__ if node in { value: { target: { name: } }, target: { name: ^name } }
# 1 in a => b => a
@matched = __LINE__ if node in { value: { value: { name: } }, target: { name: ^name } }
# 1 in [a] => a
@matched = __LINE__ if node in { value: { requireds: [{ name: }] }, target: { name: ^name } }
# 1 in [a] => b => a
@matched = __LINE__ if node in { value: { value: { requireds: [{ name: }] } }, target: { name: ^name } }
end
def visit_splat_node(node)
super
# * ( * ) = 1
@matched = __LINE__ if node in { expression: Prism::MultiTargetNode}
end
def visit_local_variable_write_node(node)
super
# a = a = *a
@matched = __LINE__ if node in { value: { name:, value: Prism::SplatNode } }
# a = ( * ) = 1
@matched = __LINE__ if node in { value: Prism::MultiWriteNode }
# ( a = ( * ) )
@matched = __LINE__ if node in { value: Prism::MultiTargetNode }
# a = * a = * 1
@matched = __LINE__ if node in { value: { elements: []} }
end
def visit_multi_write_node(node)
super
# * = a = *a
@matched = __LINE__ if node in { value: { depth:, value: Prism::SplatNode } }
# * = ( * ) = 1
@matched = __LINE__ if node in { value: Prism::MultiWriteNode }
# ( * = ( * ) )
@matched = __LINE__ if node in { value: Prism::MultiTargetNode }
end
end
run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment