зеркало из https://github.com/github/ruby.git
[ruby/yarp] Move dispatcher into its own autoload
https://github.com/ruby/yarp/commit/52bd001ea2
This commit is contained in:
Родитель
be861053c5
Коммит
af8d475281
|
@ -542,6 +542,12 @@ module YARP
|
|||
# annoying for testing since you have to const_get it to access the methods,
|
||||
# but at least this way it's clear it's not meant for consumers.
|
||||
private_constant :Debug
|
||||
|
||||
# There are many files in YARP that are templated to handle every node type,
|
||||
# which means the files can end up being quite large. We autoload them to make
|
||||
# our require speed faster since consuming libraries are unlikely to use all
|
||||
# of these features.
|
||||
autoload :Dispatcher, "yarp/dispatcher"
|
||||
end
|
||||
|
||||
require_relative "yarp/lex_compat"
|
||||
|
|
|
@ -60,6 +60,7 @@ Gem::Specification.new do |spec|
|
|||
"include/yarp/version.h",
|
||||
"lib/yarp.rb",
|
||||
"lib/yarp/desugar_visitor.rb",
|
||||
"lib/yarp/dispatcher.rb",
|
||||
"lib/yarp/ffi.rb",
|
||||
"lib/yarp/lex_compat.rb",
|
||||
"lib/yarp/mutation_visitor.rb",
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
module YARP
|
||||
# The dispatcher class fires events for nodes that are found while walking an
|
||||
# AST to all registered listeners. It's useful for performing different types
|
||||
# of analysis on the AST while only having to walk the tree once.
|
||||
#
|
||||
# To use the dispatcher, you would first instantiate it and register listeners
|
||||
# for the events you're interested in:
|
||||
#
|
||||
# class OctalListener
|
||||
# def on_integer_node_enter(node)
|
||||
# if node.octal? && !node.slice.start_with?("0o")
|
||||
# warn("Octal integers should be written with the 0o prefix")
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# dispatcher = Dispatcher.new
|
||||
# dispatcher.register(listener, :on_integer_node_enter)
|
||||
#
|
||||
# Then, you can walk any number of trees and dispatch events to the listeners:
|
||||
#
|
||||
# result = YARP.parse("001 + 002 + 003")
|
||||
# dispatcher.dispatch(result.value)
|
||||
#
|
||||
# Optionally, you can also use `#dispatch_once` to dispatch enter and leave
|
||||
# events for a single node without recursing further down the tree. This can
|
||||
# be useful in circumstances where you want to reuse the listeners you already
|
||||
# have registers but want to stop walking the tree at a certain point.
|
||||
#
|
||||
# integer = result.value.statements.body.first.receiver.receiver
|
||||
# dispatcher.dispatch_once(integer)
|
||||
#
|
||||
class Dispatcher < Visitor
|
||||
# attr_reader listeners: Hash[Symbol, Array[Listener]]
|
||||
attr_reader :listeners
|
||||
|
||||
def initialize
|
||||
@listeners = {}
|
||||
end
|
||||
|
||||
# Register a listener for one or more events
|
||||
#
|
||||
# def register: (Listener, *Symbol) -> void
|
||||
def register(listener, *events)
|
||||
events.each { |event| (listeners[event] ||= []) << listener }
|
||||
end
|
||||
|
||||
# Walks `root` dispatching events to all registered listeners
|
||||
#
|
||||
# def dispatch: (Node) -> void
|
||||
alias dispatch visit
|
||||
|
||||
# Dispatches a single event for `node` to all registered listeners
|
||||
#
|
||||
# def dispatch_once: (Node) -> void
|
||||
def dispatch_once(node)
|
||||
node.accept(DispatchOnce.new(listeners))
|
||||
end
|
||||
<%- nodes.each do |node| -%>
|
||||
|
||||
# Dispatch enter and leave events for <%= node.name %> nodes and continue
|
||||
# walking the tree.
|
||||
def visit_<%= node.human %>(node)
|
||||
listeners[:on_<%= node.human %>_enter]&.each { |listener| listener.on_<%= node.human %>_enter(node) }
|
||||
super
|
||||
listeners[:on_<%= node.human %>_leave]&.each { |listener| listener.on_<%= node.human %>_leave(node) }
|
||||
end
|
||||
<%- end -%>
|
||||
|
||||
class DispatchOnce < Visitor
|
||||
attr_reader :listeners
|
||||
|
||||
def initialize(listeners)
|
||||
@listeners = listeners
|
||||
end
|
||||
<%- nodes.each do |node| -%>
|
||||
|
||||
# Dispatch enter and leave events for <%= node.name %> nodes.
|
||||
def visit_<%= node.human %>(node)
|
||||
listeners[:on_<%= node.human %>_enter]&.each { |listener| listener.on_<%= node.human %>_enter(node) }
|
||||
listeners[:on_<%= node.human %>_leave]&.each { |listener| listener.on_<%= node.human %>_leave(node) }
|
||||
end
|
||||
<%- end -%>
|
||||
end
|
||||
|
||||
private_constant :DispatchOnce
|
||||
end
|
||||
end
|
|
@ -182,90 +182,6 @@ module YARP
|
|||
<%- end -%>
|
||||
end
|
||||
|
||||
# The dispatcher class fires events for nodes that are found while walking an
|
||||
# AST to all registered listeners. It's useful for performing different types
|
||||
# of analysis on the AST while only having to walk the tree once.
|
||||
#
|
||||
# To use the dispatcher, you would first instantiate it and register listeners
|
||||
# for the events you're interested in:
|
||||
#
|
||||
# class OctalListener
|
||||
# def on_integer_node_enter(node)
|
||||
# if node.octal? && !node.slice.start_with?("0o")
|
||||
# warn("Octal integers should be written with the 0o prefix")
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# dispatcher = Dispatcher.new
|
||||
# dispatcher.register(listener, :on_integer_node_enter)
|
||||
#
|
||||
# Then, you can walk any number of trees and dispatch events to the listeners:
|
||||
#
|
||||
# result = YARP.parse("001 + 002 + 003")
|
||||
# dispatcher.dispatch(result.value)
|
||||
#
|
||||
# Optionally, you can also use `#dispatch_once` to dispatch enter and leave
|
||||
# events for a single node without recursing further down the tree. This can
|
||||
# be useful in circumstances where you want to reuse the listeners you already
|
||||
# have registers but want to stop walking the tree at a certain point.
|
||||
#
|
||||
# integer = result.value.statements.body.first.receiver.receiver
|
||||
# dispatcher.dispatch_once(integer)
|
||||
#
|
||||
class Dispatcher < Visitor
|
||||
# attr_reader listeners: Hash[Symbol, Array[Listener]]
|
||||
attr_reader :listeners
|
||||
|
||||
def initialize
|
||||
@listeners = {}
|
||||
end
|
||||
|
||||
# Register a listener for one or more events
|
||||
#
|
||||
# def register: (Listener, *Symbol) -> void
|
||||
def register(listener, *events)
|
||||
events.each { |event| (listeners[event] ||= []) << listener }
|
||||
end
|
||||
|
||||
# Walks `root` dispatching events to all registered listeners
|
||||
#
|
||||
# def dispatch: (Node) -> void
|
||||
alias dispatch visit
|
||||
|
||||
# Dispatches a single event for `node` to all registered listeners
|
||||
#
|
||||
# def dispatch_once: (Node) -> void
|
||||
def dispatch_once(node)
|
||||
node.accept(DispatchOnce.new(listeners))
|
||||
end
|
||||
<%- nodes.each do |node| -%>
|
||||
|
||||
def visit_<%= node.human %>(node)
|
||||
listeners[:on_<%= node.human %>_enter]&.each { |listener| listener.on_<%= node.human %>_enter(node) }
|
||||
super
|
||||
listeners[:on_<%= node.human %>_leave]&.each { |listener| listener.on_<%= node.human %>_leave(node) }
|
||||
end
|
||||
<%- end -%>
|
||||
|
||||
class DispatchOnce < Visitor
|
||||
attr_reader :listeners
|
||||
|
||||
def initialize(listeners)
|
||||
@listeners = listeners
|
||||
end
|
||||
<%- nodes.each do |node| -%>
|
||||
|
||||
def visit_<%= node.human %>(node)
|
||||
listeners[:on_<%= node.human %>_enter]&.each { |listener| listener.on_<%= node.human %>_enter(node) }
|
||||
listeners[:on_<%= node.human %>_leave]&.each { |listener| listener.on_<%= node.human %>_leave(node) }
|
||||
end
|
||||
<%- end -%>
|
||||
end
|
||||
|
||||
private_constant :DispatchOnce
|
||||
end
|
||||
|
||||
module DSL
|
||||
private
|
||||
|
||||
|
|
|
@ -366,6 +366,7 @@ module YARP
|
|||
"java/org/yarp/Loader.java",
|
||||
"java/org/yarp/Nodes.java",
|
||||
"java/org/yarp/AbstractNodeVisitor.java",
|
||||
"lib/yarp/dispatcher.rb",
|
||||
"lib/yarp/mutation_visitor.rb",
|
||||
"lib/yarp/node.rb",
|
||||
"lib/yarp/serialize.rb",
|
||||
|
|
Загрузка…
Ссылка в новой задаче