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

Inherits:
Object
  • Object
show all
Includes:
Comparable, Enumerable
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: rule name (Symbol) - used as type

  • offset: byte position

  • length: byte length

  • string: matched text

  • matches: child matches

  • captures: named groups

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

Instance Method Summary collapse

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.



286
287
288
289
# File 'lib/tree_haver/backends/citrus.rb', line 286

def initialize(match, source)
  @match = 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.



284
285
286
# File 'lib/tree_haver/backends/citrus.rb', line 284

def match
  @match
end

#sourceObject (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.



284
285
286
# File 'lib/tree_haver/backends/citrus.rb', line 284

def source
  @source
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.



451
452
453
454
455
456
# File 'lib/tree_haver/backends/citrus.rb', line 451

def child(index)
  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.



447
448
449
# File 'lib/tree_haver/backends/citrus.rb', line 447

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.



458
459
460
461
# File 'lib/tree_haver/backends/citrus.rb', line 458

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

#each(&block) ⇒ 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.



463
464
465
466
# File 'lib/tree_haver/backends/citrus.rb', line 463

def each(&block)
  return to_enum(__method__) unless block_given?
  children.each(&block)
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.



395
396
397
# File 'lib/tree_haver/backends/citrus.rb', line 395

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

#end_lineInteger

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 the 1-based line number where this node ends

Returns:

  • (Integer)

    1-based line number



417
418
419
# File 'lib/tree_haver/backends/citrus.rb', line 417

def end_line
  end_point[:row] + 1
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.



403
404
405
# File 'lib/tree_haver/backends/citrus.rb', line 403

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

#first_childNode?

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 the first child node

Returns:

  • (Node, nil)

    First child or nil



439
440
441
# File 'lib/tree_haver/backends/citrus.rb', line 439

def first_child
  child(0)
end

#has_error?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.

Returns:

  • (Boolean)


468
469
470
# File 'lib/tree_haver/backends/citrus.rb', line 468

def has_error?
  false  # Citrus raises on parse error, so successful parse has no errors
end

#missing?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.

Returns:

  • (Boolean)


472
473
474
# File 'lib/tree_haver/backends/citrus.rb', line 472

def missing?
  false  # Citrus doesn't have the concept of missing nodes
end

#named?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.

Returns:

  • (Boolean)


476
477
478
# File 'lib/tree_haver/backends/citrus.rb', line 476

def named?
  true  # Citrus matches are typically "named" in tree-sitter terminology
end

#source_positionHash{Symbol => Integer}

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 position information as a hash

Returns a hash with 1-based line numbers and 0-based columns. Compatible with *-merge gems’ FileAnalysisBase.

Returns:

  • (Hash{Symbol => Integer})

    Position hash



427
428
429
430
431
432
433
434
# File 'lib/tree_haver/backends/citrus.rb', line 427

def source_position
  {
    start_line: start_line,
    end_line: end_line,
    start_column: start_point[:column],
    end_column: end_point[:column],
  }
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.



391
392
393
# File 'lib/tree_haver/backends/citrus.rb', line 391

def start_byte
  @match.offset
end

#start_lineInteger

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 the 1-based line number where this node starts

Returns:

  • (Integer)

    1-based line number



410
411
412
# File 'lib/tree_haver/backends/citrus.rb', line 410

def start_line
  start_point[:row] + 1
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.



399
400
401
# File 'lib/tree_haver/backends/citrus.rb', line 399

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



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/tree_haver/backends/citrus.rb', line 317

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.



443
444
445
# File 'lib/tree_haver/backends/citrus.rb', line 443

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



302
303
304
305
306
307
308
# File 'lib/tree_haver/backends/citrus.rb', line 302

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