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.



257
258
259
260
# File 'lib/tree_haver/backends/citrus.rb', line 257

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.



255
256
257
# File 'lib/tree_haver/backends/citrus.rb', line 255

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.



255
256
257
# File 'lib/tree_haver/backends/citrus.rb', line 255

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.



422
423
424
425
426
427
# File 'lib/tree_haver/backends/citrus.rb', line 422

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.



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

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.



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

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.



434
435
436
437
# File 'lib/tree_haver/backends/citrus.rb', line 434

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.



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

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



388
389
390
# File 'lib/tree_haver/backends/citrus.rb', line 388

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.



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

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



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

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)


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

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)


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

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)


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

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



398
399
400
401
402
403
404
405
# File 'lib/tree_haver/backends/citrus.rb', line 398

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.



362
363
364
# File 'lib/tree_haver/backends/citrus.rb', line 362

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



381
382
383
# File 'lib/tree_haver/backends/citrus.rb', line 381

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.



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

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



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/tree_haver/backends/citrus.rb', line 288

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.



414
415
416
# File 'lib/tree_haver/backends/citrus.rb', line 414

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



273
274
275
276
277
278
279
# File 'lib/tree_haver/backends/citrus.rb', line 273

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