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.



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

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.



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

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.



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

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.



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

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.



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

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.



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

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.



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

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.



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

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



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

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.



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

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



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

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)


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

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)


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

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)


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

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



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

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.



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

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



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

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.



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

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



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

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.



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

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



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

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