Class: TreeHaver::Backends::Citrus::Node Private

Inherits:
TreeHaver::Base::Node show all
Defined in:
lib/tree_haver/backends/citrus.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Citrus node wrapper

Wraps Citrus::Match objects to provide tree-sitter-compatible node API.

Citrus::Match provides:

  • events[0]: rule name (Symbol) - used as type
  • offset: byte position
  • length: byte length
  • string: matched text
  • matches: child matches
  • captures: named groups

Inherits from Base::Node to get shared methods like #first_child, #last_child,
#to_s, #inspect, #==, #<=>, #source_position, #start_line, #end_line, etc.

Language-specific helpers can be mixed in for convenience:
require “tree_haver/backends/citrus/toml_helpers”
TreeHaver::Backends::Citrus::Node.include(TreeHaver::Backends::Citrus::TomlHelpers)

Instance Attribute Summary collapse

Attributes inherited from TreeHaver::Base::Node

#inner_node, #lines, #source

Instance Method Summary collapse

Methods inherited from TreeHaver::Base::Node

#<=>, #==, #child_by_field_name, #each, #end_line, #first_child, #has_error?, #inspect, #last_child, #missing?, #named?, #next_sibling, #parent, #prev_sibling, #source_position, #start_line, #to_s

Constructor Details

#initialize(match, source) ⇒ Node

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Node.



318
319
320
321
# File 'lib/tree_haver/backends/citrus.rb', line 318

def initialize(match, source)
  @match = match
  super(match, source: source)
end

Instance Attribute Details

#matchObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



316
317
318
# File 'lib/tree_haver/backends/citrus.rb', line 316

def match
  @match
end

Instance Method Details

#child(index) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Override child to handle negative indices properly



380
381
382
383
384
385
386
# File 'lib/tree_haver/backends/citrus.rb', line 380

def child(index)
  return if index.negative?
  return unless @match.respond_to?(:matches)
  return if index >= @match.matches.size

  Node.new(@match.matches[index], @source)
end

#child_countObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Override child_count for efficiency (avoid building full children array)



375
376
377
# File 'lib/tree_haver/backends/citrus.rb', line 375

def child_count
  @match.respond_to?(:matches) ? @match.matches.size : 0
end

#childrenObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



352
353
354
355
# File 'lib/tree_haver/backends/citrus.rb', line 352

def children
  return [] unless @match.respond_to?(:matches)
  @match.matches.map { |m| Node.new(m, @source) }
end

#end_byteObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



348
349
350
# File 'lib/tree_haver/backends/citrus.rb', line 348

def end_byte
  @match.offset + @match.length
end

#end_pointObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Override end_point to calculate from source



365
366
367
# File 'lib/tree_haver/backends/citrus.rb', line 365

def end_point
  calculate_point(@match.offset + @match.length)
end

#start_byteObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



344
345
346
# File 'lib/tree_haver/backends/citrus.rb', line 344

def start_byte
  @match.offset
end

#start_pointObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Override start_point to calculate from source



360
361
362
# File 'lib/tree_haver/backends/citrus.rb', line 360

def start_point
  calculate_point(@match.offset)
end

#structural?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if this node represents a structural element vs a terminal/token

Uses Citrus grammar’s terminal? method to determine if this is
a structural rule (like “table”, “keyvalue”) vs a terminal token
(like “[”, “=”, whitespace).

Returns:

  • (Boolean)

    true if this is a structural (non-terminal) node



395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
# File 'lib/tree_haver/backends/citrus.rb', line 395

def structural?
  return false unless @match.respond_to?(:events)
  return false if @match.events.empty?

  first_event = @match.events.first

  # Check if event has terminal? method (Citrus rule object)
  if first_event.respond_to?(:terminal?)
    return !first_event.terminal?
  end

  # For Symbol events, try to look up in grammar
  if first_event.is_a?(Symbol) && @match.respond_to?(:grammar)
    grammar = @match.grammar
    if grammar.respond_to?(:rules) && grammar.rules.key?(first_event)
      rule = grammar.rules[first_event]
      return !rule.terminal? if rule.respond_to?(:terminal?)
    end
  end

  # Default: assume structural if not a simple string/regex terminal
  true
end

#textObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Override text to use Citrus match string



370
371
372
# File 'lib/tree_haver/backends/citrus.rb', line 370

def text
  @match.string
end

#typeString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get node type from Citrus rule name

Uses Citrus grammar introspection to dynamically determine node types.
Works with any Citrus grammar without language-specific knowledge.

Strategy:

  1. Check if first event has a .name method (returns Symbol) - use that
  2. If first event is a Symbol directly - use that
  3. For compound rules (Repeat, Choice), recurse into first match

Returns:

  • (String)

    rule name from grammar



336
337
338
339
340
341
342
# File 'lib/tree_haver/backends/citrus.rb', line 336

def type
  return "unknown" unless @match.respond_to?(:events)
  return "unknown" unless @match.events.is_a?(Array)
  return "unknown" if @match.events.empty?

  extract_type_from_event(@match.events.first)
end