Class: Ast::Merge::AstNode
- Inherits:
-
Object
- Object
- Ast::Merge::AstNode
- Includes:
- Comparable
- Defined in:
- lib/ast/merge/ast_node.rb
Overview
Base class for synthetic AST nodes in the ast-merge framework.
“Synthetic” nodes are nodes that aren’t backed by a real parser - they’re created by ast-merge for representing content that doesn’t have a native AST (comments, text lines, env file entries, etc.).
This class implements the TreeHaver::Node protocol, making it compatible with all code that expects TreeHaver nodes. This allows synthetic nodes to be used interchangeably with parser-backed nodes in merge operations.
Implements the TreeHaver::Node protocol:
-
type → String node type
-
text / slice → Source text content
-
start_byte / end_byte → Byte offsets
-
start_point / end_point → Point (row, column)
-
children → Array of child nodes
-
named? / structural? → Node classification
-
inner_node → Returns self (no wrapping layer for synthetic nodes)
Adds merge-specific methods:
-
signature → Array used for matching nodes across files
-
normalized_content → Cleaned text for comparison
Direct Known Subclasses
Comment::Block, Comment::Empty, Comment::Line, Text::LineNode, Text::WordNode
Defined Under Namespace
Instance Attribute Summary collapse
-
#location ⇒ Location
readonly
The location of this node in source.
-
#slice ⇒ String
readonly
The source text for this node.
-
#source ⇒ String?
readonly
The full source text (for text extraction).
Instance Method Summary collapse
-
#<=>(other) ⇒ Integer?
Comparable: compare nodes by position.
-
#child(index) ⇒ AstNode?
TreeHaver::Node protocol: child(index).
-
#child_count ⇒ Integer
TreeHaver::Node protocol: child_count.
-
#children ⇒ Array<AstNode>
TreeHaver::Node protocol: children.
-
#each {|AstNode| ... } ⇒ Enumerator?
TreeHaver::Node protocol: each Iterate over children.
-
#end_byte ⇒ Integer
TreeHaver::Node protocol: end_byte.
-
#end_point ⇒ Point
TreeHaver::Node protocol: end_point Returns a Point with row (0-based) and column.
-
#has_error? ⇒ Boolean
TreeHaver::Node protocol: has_error? Synthetic nodes don’t have parse errors.
-
#initialize(slice:, location:, source: nil) ⇒ AstNode
constructor
Initialize a new AstNode.
-
#inner_node ⇒ AstNode
TreeHaver::Node protocol: inner_node For synthetic nodes, this returns self (no wrapping layer).
-
#inspect ⇒ String
Human-readable representation.
-
#missing? ⇒ Boolean
TreeHaver::Node protocol: missing? Synthetic nodes are never “missing”.
-
#named? ⇒ Boolean
TreeHaver::Node protocol: named? Synthetic nodes are always “named” (structural) nodes.
-
#normalized_content ⇒ String
Normalized content for signature comparison.
-
#signature ⇒ Array
Generate a signature for this node for matching purposes.
-
#start_byte ⇒ Integer
TreeHaver::Node protocol: start_byte Calculates byte offset from source if available, otherwise estimates from lines.
-
#start_point ⇒ Point
TreeHaver::Node protocol: start_point Returns a Point with row (0-based) and column.
-
#structural? ⇒ Boolean
TreeHaver::Node protocol: structural? Synthetic nodes are always structural.
-
#text ⇒ String
TreeHaver::Node protocol: text.
-
#to_s ⇒ String
The source text.
-
#type ⇒ String
(also: #kind)
TreeHaver::Node protocol: type Returns the node type as a string.
-
#unwrap ⇒ AstNode
Support unwrap protocol (returns self for non-wrapper nodes).
Constructor Details
#initialize(slice:, location:, source: nil) ⇒ AstNode
Initialize a new AstNode.
94 95 96 97 98 |
# File 'lib/ast/merge/ast_node.rb', line 94 def initialize(slice:, location:, source: nil) @slice = slice @location = location @source = source end |
Instance Attribute Details
#location ⇒ Location (readonly)
Returns The location of this node in source.
81 82 83 |
# File 'lib/ast/merge/ast_node.rb', line 81 def location @location end |
#slice ⇒ String (readonly)
Returns The source text for this node.
84 85 86 |
# File 'lib/ast/merge/ast_node.rb', line 84 def slice @slice end |
#source ⇒ String? (readonly)
Returns The full source text (for text extraction).
87 88 89 |
# File 'lib/ast/merge/ast_node.rb', line 87 def source @source end |
Instance Method Details
#<=>(other) ⇒ Integer?
Comparable: compare nodes by position
255 256 257 258 259 260 261 262 |
# File 'lib/ast/merge/ast_node.rb', line 255 def <=>(other) return unless other.respond_to?(:start_byte) && other.respond_to?(:end_byte) cmp = start_byte <=> other.start_byte return cmp if cmp.nonzero? end_byte <=> other.end_byte end |
#child(index) ⇒ AstNode?
TreeHaver::Node protocol: child(index)
190 191 192 |
# File 'lib/ast/merge/ast_node.rb', line 190 def child(index) children[index] end |
#child_count ⇒ Integer
TreeHaver::Node protocol: child_count
183 184 185 |
# File 'lib/ast/merge/ast_node.rb', line 183 def child_count children.size end |
#children ⇒ Array<AstNode>
TreeHaver::Node protocol: children
177 178 179 |
# File 'lib/ast/merge/ast_node.rb', line 177 def children [] end |
#each {|AstNode| ... } ⇒ Enumerator?
TreeHaver::Node protocol: each Iterate over children
231 232 233 234 |
# File 'lib/ast/merge/ast_node.rb', line 231 def each(&block) return to_enum(__method__) unless block_given? children.each(&block) end |
#end_byte ⇒ Integer
TreeHaver::Node protocol: end_byte
149 150 151 |
# File 'lib/ast/merge/ast_node.rb', line 149 def end_byte start_byte + slice.to_s.bytesize end |
#end_point ⇒ Point
TreeHaver::Node protocol: end_point Returns a Point with row (0-based) and column
168 169 170 171 172 173 |
# File 'lib/ast/merge/ast_node.rb', line 168 def end_point Point.new( row: (location&.end_line || 1) - 1, # Convert to 0-based column: location&.end_column || 0, ) end |
#has_error? ⇒ Boolean
TreeHaver::Node protocol: has_error? Synthetic nodes don’t have parse errors
214 215 216 |
# File 'lib/ast/merge/ast_node.rb', line 214 def has_error? false end |
#inner_node ⇒ AstNode
TreeHaver::Node protocol: inner_node For synthetic nodes, this returns self (no wrapping layer)
104 105 106 |
# File 'lib/ast/merge/ast_node.rb', line 104 def inner_node self end |
#inspect ⇒ String
Returns Human-readable representation.
265 266 267 |
# File 'lib/ast/merge/ast_node.rb', line 265 def inspect "#<#{self.class.name} type=#{type} lines=#{location&.start_line}..#{location&.end_line}>" end |
#missing? ⇒ Boolean
TreeHaver::Node protocol: missing? Synthetic nodes are never “missing”
222 223 224 |
# File 'lib/ast/merge/ast_node.rb', line 222 def missing? false end |
#named? ⇒ Boolean
TreeHaver::Node protocol: named? Synthetic nodes are always “named” (structural) nodes
198 199 200 |
# File 'lib/ast/merge/ast_node.rb', line 198 def named? true end |
#normalized_content ⇒ String
Returns Normalized content for signature comparison.
247 248 249 |
# File 'lib/ast/merge/ast_node.rb', line 247 def normalized_content slice.to_s.strip end |
#signature ⇒ Array
Generate a signature for this node for matching purposes.
Override in subclasses for custom signature logic. Default returns the node type and a normalized form of the slice.
242 243 244 |
# File 'lib/ast/merge/ast_node.rb', line 242 def signature [type.to_sym, normalized_content] end |
#start_byte ⇒ Integer
TreeHaver::Node protocol: start_byte Calculates byte offset from source if available, otherwise estimates from lines
134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/ast/merge/ast_node.rb', line 134 def start_byte return 0 unless source && location # Calculate byte offset from line/column lines = source.lines byte_offset = 0 (0...(location.start_line - 1)).each do |i| byte_offset += lines[i]&.bytesize || 0 end byte_offset + (location.start_column || 0) end |
#start_point ⇒ Point
TreeHaver::Node protocol: start_point Returns a Point with row (0-based) and column
157 158 159 160 161 162 |
# File 'lib/ast/merge/ast_node.rb', line 157 def start_point Point.new( row: (location&.start_line || 1) - 1, # Convert to 0-based column: location&.start_column || 0, ) end |
#structural? ⇒ Boolean
TreeHaver::Node protocol: structural? Synthetic nodes are always structural
206 207 208 |
# File 'lib/ast/merge/ast_node.rb', line 206 def structural? true end |
#text ⇒ String
TreeHaver::Node protocol: text
126 127 128 |
# File 'lib/ast/merge/ast_node.rb', line 126 def text slice.to_s end |
#to_s ⇒ String
Returns The source text.
270 271 272 |
# File 'lib/ast/merge/ast_node.rb', line 270 def to_s slice.to_s end |
#type ⇒ String Also known as: kind
TreeHaver::Node protocol: type Returns the node type as a string. Subclasses should override this with specific type names.
113 114 115 116 117 118 119 |
# File 'lib/ast/merge/ast_node.rb', line 113 def type # Default: derive from class name (MyNode → "my_node") self.class.name.split("::").last .gsub(/([A-Z])/, '_\1') .downcase .sub(/^_/, "") end |
#unwrap ⇒ AstNode
Support unwrap protocol (returns self for non-wrapper nodes)
276 277 278 |
# File 'lib/ast/merge/ast_node.rb', line 276 def unwrap self end |