Skip to content
This repository has been archived by the owner on Jan 2, 2025. It is now read-only.

Commit

Permalink
integrate DefineDataVisitor
Browse files Browse the repository at this point in the history
  • Loading branch information
euglena1215 committed Jun 10, 2024
1 parent f6519c6 commit e97d206
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 95 deletions.
3 changes: 2 additions & 1 deletion lib/rbs_inline_data/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ def run(args)
targets.uniq!

targets.each do |file|
definitions = Parser.parse(file)
result = Prism.parse_file(file.to_s)
definitions = Parser.parse(result)
Writer.write(file, definitions)
end
end
Expand Down
158 changes: 72 additions & 86 deletions lib/rbs_inline_data/parser.rb
Original file line number Diff line number Diff line change
@@ -1,78 +1,7 @@
require 'prism'

module RbsInlineData
class Parser
class DefineDataVisitor < Prism::Visitor
# @rbs @definitions: Array[RbsInlineData::Parser::TypedDefinition]
# @rbs @surronding_class_or_module: Array[Symbol]

def initialize(definitions)
@definitions = definitions
@surronding_class_or_module = []
end

# @rbs override
def visit_class_node(node)
record_surrounding_class_or_module(node) { super }
end

# @rbs override
def visit_module_node(node)
record_surrounding_class_or_module(node) { super }
end

# @rbs override
def visit_constant_write_node(node)
if define_data?(node)
definition = extract_definition(node)
@definitions << definition if definition
end

super
end

private

#:: (Prism::ClassNode | Prism::ModuleNode) { (Prism::ClassNode | Prism::ModuleNode) -> void } -> void
def record_surrounding_class_or_module(node)
@surronding_class_or_module.push(node.constant_path.name)
yield(node)
ensure
@surronding_class_or_module.pop
end

#:: (Prism::ConstantWriteNode) -> bool
def define_data?(node)
node in {
value: Prism::CallNode[
receiver: (
Prism::ConstantReadNode[name: :Data] |
Prism::ConstantPathNode[parent: nil, name: :Data]
),
name: :define,
]
}
end

#:: (Prism::ConstantWriteNode) -> RbsInlineData::Parser::TypedDefinition?
def extract_definition(node)
source = node.slice
_, class_name, field_text = source.match(/\A([a-zA-Z]+) = Data\.define\(([\n\s\w\W]+)\)\z/).to_a
return nil if field_text.nil? || class_name.nil?

class_name = @surronding_class_or_module.join("::") + "::" + class_name

fields = field_text.split("\n").map(&:strip).map do |str|
str.match(/:(\w+), #:: ([\w\[\]]+)/)&.to_a
end.compact.map { |_, field_name, type| TypedField.new(field_name: field_name, type: type) }

TypedDefinition.new(
class_name: class_name,
fields: fields,
)
end
end

class Parser < Prism::Visitor
# @rbs skip
TypedDefinition = Data.define(
:class_name, #:: String
Expand All @@ -84,26 +13,83 @@ def extract_definition(node)
:type, #:: String
)

# @rbs @file: Pathname
# @rbs @definitions: Array[RbsInlineData::Parser::TypedDefinition]
# @rbs @surronding_class_or_module: Array[Symbol]

#:: (Pathname) -> void
def initialize(file)
@file = file
#:: (Array[RbsInlineData::Parser::TypedDefinition]) -> void
def initialize(definitions)
@definitions = definitions
@surronding_class_or_module = []
end

#:: (Pathname) -> Array[RbsInlineData::Parser::TypedDefinition]
def self.parse(file)
new(file).parse
end

#:: () -> Array[RbsInlineData::Parser::TypedDefinition]
def parse
result = Prism.parse_file(@file.to_s)

#:: (Prism::ParseResult) -> Array[RbsInlineData::Parser::TypedDefinition]
def self.parse(result)
# @type var definitions: Array[RbsInlineData::Parser::TypedDefinition]
definitions = []
result.value.accept(DefineDataVisitor.new(definitions))
instance = self.new(definitions)
result.value.accept(instance)
definitions
end

# @rbs override
def visit_class_node(node)
record_surrounding_class_or_module(node) { super }
end

# @rbs override
def visit_module_node(node)
record_surrounding_class_or_module(node) { super }
end

# @rbs override
def visit_constant_write_node(node)
if define_data?(node)
definition = extract_definition(node)
@definitions << definition if definition
end

super
end

private

#:: (Prism::ClassNode | Prism::ModuleNode) { (Prism::ClassNode | Prism::ModuleNode) -> void } -> void
def record_surrounding_class_or_module(node)
@surronding_class_or_module.push(node.constant_path.name)
yield(node)
ensure
@surronding_class_or_module.pop
end

#:: (Prism::ConstantWriteNode) -> bool
def define_data?(node)
node in {
value: Prism::CallNode[
receiver: (
Prism::ConstantReadNode[name: :Data] |
Prism::ConstantPathNode[parent: nil, name: :Data]
),
name: :define,
]
}
end

#:: (Prism::ConstantWriteNode) -> RbsInlineData::Parser::TypedDefinition?
def extract_definition(node)
source = node.slice
_, class_name, field_text = source.match(/\A([a-zA-Z]+) = Data\.define\(([\n\s\w\W]+)\)\z/).to_a
return nil if field_text.nil? || class_name.nil?

class_name = @surronding_class_or_module.join("::") + "::" + class_name

fields = field_text.split("\n").map(&:strip).map do |str|
str.match(/:(\w+), #:: ([\w\[\]]+)/)&.to_a
end.compact.map { |_, field_name, type| TypedField.new(field_name: field_name, type: type) }

TypedDefinition.new(
class_name: class_name,
fields: fields,
)
end
end
end
35 changes: 27 additions & 8 deletions sig/generated/rbs_inline_data/parser.rbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Generated from lib/rbs_inline_data/parser.rb with RBS::Inline

module RbsInlineData
class Parser
class Parser < Prism::Visitor
class DefineDataVisitor < Prism::Visitor
@definitions: Array[RbsInlineData::Parser::TypedDefinition]

Expand Down Expand Up @@ -30,15 +30,34 @@ module RbsInlineData
def extract_definition: (Prism::ConstantWriteNode) -> RbsInlineData::Parser::TypedDefinition?
end

@file: Pathname
@definitions: Array[RbsInlineData::Parser::TypedDefinition]

# :: (Pathname) -> void
def initialize: (Pathname) -> void
@surronding_class_or_module: Array[Symbol]

# :: (Pathname) -> Array[RbsInlineData::Parser::TypedDefinition]
def self.parse: (Pathname) -> Array[RbsInlineData::Parser::TypedDefinition]
# :: (Array[RbsInlineData::Parser::TypedDefinition]) -> void
def initialize: (Array[RbsInlineData::Parser::TypedDefinition]) -> void

# :: () -> Array[RbsInlineData::Parser::TypedDefinition]
def parse: () -> Array[RbsInlineData::Parser::TypedDefinition]
# :: (Prism::ParseResult) -> Array[RbsInlineData::Parser::TypedDefinition]
def self.parse: (Prism::ParseResult) -> Array[RbsInlineData::Parser::TypedDefinition]

# @rbs override
def visit_class_node: ...

# @rbs override
def visit_module_node: ...

# @rbs override
def visit_constant_write_node: ...

private

# :: (Prism::ClassNode | Prism::ModuleNode) { (Prism::ClassNode | Prism::ModuleNode) -> void } -> void
def record_surrounding_class_or_module: (Prism::ClassNode | Prism::ModuleNode) { (Prism::ClassNode | Prism::ModuleNode) -> void } -> void

# :: (Prism::ConstantWriteNode) -> bool
def define_data?: (Prism::ConstantWriteNode) -> bool

# :: (Prism::ConstantWriteNode) -> RbsInlineData::Parser::TypedDefinition?
def extract_definition: (Prism::ConstantWriteNode) -> RbsInlineData::Parser::TypedDefinition?
end
end

0 comments on commit e97d206

Please sign in to comment.