Class: Ast::Merge::AstNode
- Inherits:
-
TreeHaver::Base::Node
- Object
- TreeHaver::Base::Node
- Ast::Merge::AstNode
- 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 inherits from TreeHaver::Base::Node, ensuring it stays in sync with the canonical Node API. 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.
Instance Method Summary collapse
-
#<=>(other) ⇒ Integer?
Comparable: compare nodes by position Note: Inherits Comparable from TreeHaver::Base::Node.
-
#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.
-
#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.
-
#source ⇒ String?
Override source to return stored value (not parent's).
-
#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.
100 101 102 103 104 105 |
# File 'lib/ast/merge/ast_node.rb', line 100 def initialize(slice:, location:, source: nil) @slice = slice @location = location # Call parent constructor with self as inner_node super(self, source: source) end |
Instance Attribute Details
#location ⇒ Location (readonly)
Returns The location of this node in source.
90 91 92 |
# File 'lib/ast/merge/ast_node.rb', line 90 def location @location end |
#slice ⇒ String (readonly)
Returns The source text for this node.
93 94 95 |
# File 'lib/ast/merge/ast_node.rb', line 93 def slice @slice end |
Instance Method Details
#<=>(other) ⇒ Integer?
Comparable: compare nodes by position Note: Inherits Comparable from TreeHaver::Base::Node
263 264 265 266 267 268 269 270 |
# File 'lib/ast/merge/ast_node.rb', line 263 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)
196 197 198 |
# File 'lib/ast/merge/ast_node.rb', line 196 def child(index) children[index] end |
#child_count ⇒ Integer
TreeHaver::Node protocol: child_count
189 190 191 |
# File 'lib/ast/merge/ast_node.rb', line 189 def child_count children.size end |
#children ⇒ Array<AstNode>
TreeHaver::Node protocol: children
183 184 185 |
# File 'lib/ast/merge/ast_node.rb', line 183 def children [] end |
#each {|AstNode| ... } ⇒ Enumerator?
TreeHaver::Node protocol: each Iterate over children
237 238 239 240 241 |
# File 'lib/ast/merge/ast_node.rb', line 237 def each(&block) return to_enum(__method__) unless block_given? children.each(&block) end |
#end_byte ⇒ Integer
TreeHaver::Node protocol: end_byte
155 156 157 |
# File 'lib/ast/merge/ast_node.rb', line 155 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
174 175 176 177 178 179 |
# File 'lib/ast/merge/ast_node.rb', line 174 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
220 221 222 |
# File 'lib/ast/merge/ast_node.rb', line 220 def has_error? false end |
#inspect ⇒ String
Returns Human-readable representation.
273 274 275 |
# File 'lib/ast/merge/ast_node.rb', line 273 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"
228 229 230 |
# File 'lib/ast/merge/ast_node.rb', line 228 def missing? false end |
#named? ⇒ Boolean
TreeHaver::Node protocol: named? Synthetic nodes are always "named" (structural) nodes
204 205 206 |
# File 'lib/ast/merge/ast_node.rb', line 204 def named? true end |
#normalized_content ⇒ String
Returns Normalized content for signature comparison.
254 255 256 |
# File 'lib/ast/merge/ast_node.rb', line 254 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.
249 250 251 |
# File 'lib/ast/merge/ast_node.rb', line 249 def signature [type.to_sym, normalized_content] end |
#source ⇒ String?
Override source to return stored value (not parent's)
109 110 111 |
# File 'lib/ast/merge/ast_node.rb', line 109 def source @source || super end |
#start_byte ⇒ Integer
TreeHaver::Node protocol: start_byte Calculates byte offset from source if available, otherwise estimates from lines
139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/ast/merge/ast_node.rb', line 139 def start_byte src = source return 0 unless src && location # Calculate byte offset from line/column lines = src.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
163 164 165 166 167 168 |
# File 'lib/ast/merge/ast_node.rb', line 163 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
212 213 214 |
# File 'lib/ast/merge/ast_node.rb', line 212 def structural? true end |
#text ⇒ String
TreeHaver::Node protocol: text
131 132 133 |
# File 'lib/ast/merge/ast_node.rb', line 131 def text slice.to_s end |
#to_s ⇒ String
Returns The source text.
278 279 280 |
# File 'lib/ast/merge/ast_node.rb', line 278 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.
118 119 120 121 122 123 124 |
# File 'lib/ast/merge/ast_node.rb', line 118 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)
284 285 286 |
# File 'lib/ast/merge/ast_node.rb', line 284 def unwrap self end |