Class: TreeHaver::Backends::Citrus::Language

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/tree_haver/backends/citrus.rb

Overview

Citrus grammar wrapper

Unlike tree-sitter which loads compiled .so files, Citrus uses Ruby modules
that define grammars. This class wraps a Citrus grammar module.

Examples:

# For TOML, use toml-rb's grammar
language = TreeHaver::Backends::Citrus::Language.new(TomlRB::Document)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(grammar_module) ⇒ Language

Returns a new instance of Language.

Parameters:

  • grammar_module (Module)

    A Citrus grammar module with a parse method



103
104
105
106
107
108
109
110
111
# File 'lib/tree_haver/backends/citrus.rb', line 103

def initialize(grammar_module)
  unless grammar_module.respond_to?(:parse)
    raise TreeHaver::NotAvailable,
      "Grammar module must respond to :parse. " \
        "Expected a Citrus grammar module (e.g., TomlRB::Document)."
  end
  @grammar_module = grammar_module
  @backend = :citrus
end

Instance Attribute Details

#backendSymbol (readonly)

The backend this language is for

Returns:

  • (Symbol)


100
101
102
# File 'lib/tree_haver/backends/citrus.rb', line 100

def backend
  @backend
end

#grammar_moduleModule (readonly)

The Citrus grammar module

Returns:

  • (Module)

    Citrus grammar module (e.g., TomlRB::Document)



96
97
98
# File 'lib/tree_haver/backends/citrus.rb', line 96

def grammar_module
  @grammar_module
end

Class Method Details

.from_library(path = nil, symbol: nil, name: nil) ⇒ Object Also known as: from_path



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/tree_haver/backends/citrus.rb', line 170

def from_library(path = nil, symbol: nil, name: nil)
  # Derive language name from path, symbol, or explicit name
  lang_name = name&.to_sym ||
    symbol&.to_s&.sub(/^tree_sitter_/, "")&.to_sym ||
    path && TreeHaver::LibraryPathUtils.derive_language_name_from_path(path)&.to_sym

  unless lang_name
    raise TreeHaver::NotAvailable,
      "Citrus backend requires a language name. " \
        "Provide name: parameter or register a grammar with TreeHaver.register_language."
  end

  # Look up registered Citrus grammar
  registration = TreeHaver::LanguageRegistry.registered(lang_name, :citrus)

  unless registration
    raise TreeHaver::NotAvailable,
      "No Citrus grammar registered for #{lang_name.inspect}. " \
        "Register one with: TreeHaver.register_language(:#{lang_name}, grammar_module: YourGrammar)"
  end

  grammar_module = registration[:grammar_module]
  new(grammar_module)
end

Instance Method Details

#<=>(other) ⇒ Integer?

Compare languages for equality

Citrus languages are equal if they have the same backend and grammar_module.
Grammar module uniquely identifies a Citrus language.

Parameters:

  • other (Object)

    object to compare with

Returns:

  • (Integer, nil)

    -1, 0, 1, or nil if not comparable



136
137
138
139
140
141
142
# File 'lib/tree_haver/backends/citrus.rb', line 136

def <=>(other)
  return unless other.is_a?(Language)
  return unless other.backend == @backend

  # Compare by grammar_module name (modules are compared by object_id by default)
  @grammar_module.name <=> other.grammar_module.name
end

#hashInteger

Hash value for this language (for use in Sets/Hashes)

Returns:

  • (Integer)


146
147
148
# File 'lib/tree_haver/backends/citrus.rb', line 146

def hash
  [@backend, @grammar_module.name].hash
end

#language_nameSymbol Also known as: name

Get the language name

Derives a name from the grammar module name.

Returns:

  • (Symbol)

    language name



118
119
120
121
122
123
124
# File 'lib/tree_haver/backends/citrus.rb', line 118

def language_name
  # Derive name from grammar module (e.g., TomlRB::Document -> :toml)
  return :unknown unless @grammar_module.respond_to?(:name) && @grammar_module.name

  name = @grammar_module.name.to_s.split("::").first.downcase
  name.sub(/rb$/, "").to_sym
end