Last active
December 10, 2023 17:06
-
-
Save tompng/a065d8cf2475c9b6bde5cc6801b3e846 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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