class Parser
The Ruby source code parser.
Definitions
def definitions_for(source, &block)
Extract definitions from the given input file.
Implementation
def definitions_for(source, &block)
top, comments = self.parse_source(source)
if top
walk_definitions(top, comments, &block)
end
end
def walk_definitions(node, comments, parent = nil, &block)
Walk over the syntax tree and extract relevant definitions with their associated comments.
Implementation
def walk_definitions(node, comments, parent = nil, &block)
case node.type
when :module
definition = Module.new(
node, nested_name_for(node.children[0]),
comments: extract_comments_for(node, comments),
parent: parent,
language: @language, visibility: :public
)
assign_definition(parent, definition)
yield definition
if children = node.children[1]
with_visibility do
walk_definitions(children, comments, definition, &block)
end
end
when :class
definition = Class.new(
node, nested_name_for(node.children[0]),
comments: extract_comments_for(node, comments),
parent: parent, language: @language, visibility: :public
)
assign_definition(parent, definition)
yield definition
if children = node.children[2]
with_visibility do
walk_definitions(children, comments, definition, &block)
end
end
when :sclass
if name = singleton_name_for(node.children[0])
definition = Singleton.new(
node, name,
comments: extract_comments_for(node, comments),
parent: parent, language: @language, visibility: :public
)
yield definition
if children = node.children[1]
walk_definitions(children, comments, definition, &block)
end
end
when :def
definition = Method.new(
node, node.children[0],
comments: extract_comments_for(node, comments),
parent: parent, language: @language, visibility: @visibility
)
yield definition
when :defs
extracted_comments = extract_comments_for(node, comments)
definition = Function.new(
node, node.children[1],
comments: extracted_comments,
parent: scope_for(extracted_comments, parent, &block),
language: @language, visibility: @visibility
)
yield definition
when :casgn
definition = Constant.new(
node, node.children[1],
comments: extract_comments_for(node, comments),
parent: parent, language: @language
)
yield definition
when :send
name = node.children[1]
case name
when :public, :protected, :private
@visibility = name
when :private_constant
constant_names_for(node.children[2..]) do |name|
if definition = lookup_definition(parent, name)
definition.visibility = :private
end
end
when :attr, :attr_reader, :attr_writer, :attr_accessor
definition = Attribute.new(
node, name_for(node.children[2]),
comments: extract_comments_for(node, comments),
parent: parent, language: @language
)
yield definition
else
extracted_comments = extract_comments_for(node, comments)
if kind = kind_for(node, extracted_comments)
definition = Call.new(
node, name_for(node, extracted_comments),
comments: extracted_comments,
parent: parent, language: @language
)
yield definition
end
end
when :block
extracted_comments = extract_comments_for(node, comments)
if name = name_for(node, extracted_comments)
definition = Block.new(
node, name,
comments: extracted_comments,
parent: scope_for(extracted_comments, parent, &block),
language: @language
)
if kind = kind_for(node, extracted_comments)
definition = definition.convert(kind)
end
yield definition
if children = node.children[2]
walk_definitions(children, comments, definition, &block)
end
end
else
node.children.each do |child|
if child.is_a?(::Parser::AST::Node)
walk_definitions(child, comments, parent, &block) if child
end
end
end
end
def segments_for(source, &block)
Extract segments from the given input file.
Implementation
def segments_for(source, &block)
top, comments = self.parse_source(source)
# We delete any leading comments:
line = 0
while comment = comments.first
if comment.location.line == line
comments.pop
line += 1
else
break
end
end
# Now we iterate over the syntax tree and generate segments:
walk_segments(top, comments, &block)
end