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.
89 90 91 92 93 94 |
# File 'lib/ast/merge/ast_node.rb', line 89 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.
79 80 81 |
# File 'lib/ast/merge/ast_node.rb', line 79 def location @location end |
#slice ⇒ String (readonly)
Returns The source text for this node.
82 83 84 |
# File 'lib/ast/merge/ast_node.rb', line 82 def slice @slice end |
Instance Method Details
#<=>(other) ⇒ Integer?
Comparable: compare nodes by position
Note: Inherits Comparable from TreeHaver::Base::Node
251 252 253 254 255 256 257 258 |
# File 'lib/ast/merge/ast_node.rb', line 251 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)
185 186 187 |
# File 'lib/ast/merge/ast_node.rb', line 185 def child(index) children[index] end |
#child_count ⇒ Integer
TreeHaver::Node protocol: child_count
178 179 180 |
# File 'lib/ast/merge/ast_node.rb', line 178 def child_count children.size end |
#children ⇒ Array<AstNode>
TreeHaver::Node protocol: children
172 173 174 |
# File 'lib/ast/merge/ast_node.rb', line 172 def children [] end |
#each {|AstNode| ... } ⇒ Enumerator?
TreeHaver::Node protocol: each
Iterate over children
226 227 228 229 |
# File 'lib/ast/merge/ast_node.rb', line 226 def each(&block) return to_enum(__method__) unless block_given? children.each(&block) end |
#end_byte ⇒ Integer
TreeHaver::Node protocol: end_byte
144 145 146 |
# File 'lib/ast/merge/ast_node.rb', line 144 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
163 164 165 166 167 168 |
# File 'lib/ast/merge/ast_node.rb', line 163 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
209 210 211 |
# File 'lib/ast/merge/ast_node.rb', line 209 def has_error? false end |
#inspect ⇒ String
Returns Human-readable representation.
261 262 263 |
# File 'lib/ast/merge/ast_node.rb', line 261 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”
217 218 219 |
# File 'lib/ast/merge/ast_node.rb', line 217 def missing? false end |
#named? ⇒ Boolean
TreeHaver::Node protocol: named?
Synthetic nodes are always “named” (structural) nodes
193 194 195 |
# File 'lib/ast/merge/ast_node.rb', line 193 def named? true end |
#normalized_content ⇒ String
Returns Normalized content for signature comparison.
242 243 244 |
# File 'lib/ast/merge/ast_node.rb', line 242 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.
237 238 239 |
# File 'lib/ast/merge/ast_node.rb', line 237 def signature [type.to_sym, normalized_content] end |
#source ⇒ String?
Override source to return stored value (not parent’s)
98 99 100 |
# File 'lib/ast/merge/ast_node.rb', line 98 def source @source || super end |
#start_byte ⇒ Integer
TreeHaver::Node protocol: start_byte
Calculates byte offset from source if available, otherwise estimates from lines
128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/ast/merge/ast_node.rb', line 128 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
152 153 154 155 156 157 |
# File 'lib/ast/merge/ast_node.rb', line 152 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
201 202 203 |
# File 'lib/ast/merge/ast_node.rb', line 201 def structural? true end |
#text ⇒ String
TreeHaver::Node protocol: text
120 121 122 |
# File 'lib/ast/merge/ast_node.rb', line 120 def text slice.to_s end |
#to_s ⇒ String
Returns The source text.
266 267 268 |
# File 'lib/ast/merge/ast_node.rb', line 266 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.
107 108 109 110 111 112 113 |
# File 'lib/ast/merge/ast_node.rb', line 107 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)
272 273 274 |
# File 'lib/ast/merge/ast_node.rb', line 272 def unwrap self end |