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

Inherits:
Object
  • Object
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: 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.



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

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.



252
253
254
# File 'lib/tree_haver/backends/citrus.rb', line 252

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.



252
253
254
# File 'lib/tree_haver/backends/citrus.rb', line 252

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.



419
420
421
422
423
424
# File 'lib/tree_haver/backends/citrus.rb', line 419

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.



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

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.



426
427
428
429
# File 'lib/tree_haver/backends/citrus.rb', line 426

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.



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

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.



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

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



385
386
387
# File 'lib/tree_haver/backends/citrus.rb', line 385

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.



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

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



407
408
409
# File 'lib/tree_haver/backends/citrus.rb', line 407

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)


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

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)


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

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)


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

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



395
396
397
398
399
400
401
402
# File 'lib/tree_haver/backends/citrus.rb', line 395

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.



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

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



378
379
380
# File 'lib/tree_haver/backends/citrus.rb', line 378

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.



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

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



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

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.



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

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



270
271
272
273
274
275
276
# File 'lib/tree_haver/backends/citrus.rb', line 270

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