Class: TreeHaver::Backends::Java::Language
- Inherits:
-
Object
- Object
- TreeHaver::Backends::Java::Language
- Includes:
- Comparable
- Defined in:
- lib/tree_haver/backends/java.rb
Overview
Wrapper for java-tree-sitter Language
:nocov: All Java backend implementation classes require JRuby and cannot be tested on MRI/CRuby. JRuby-specific CI jobs would test this code.
Instance Attribute Summary collapse
-
#backend ⇒ Symbol
readonly
The backend this language is for.
-
#impl ⇒ Object
readonly
Returns the value of attribute impl.
-
#path ⇒ String?
readonly
The path this language was loaded from (if known).
-
#symbol ⇒ String?
readonly
The symbol name (if known).
Class Method Summary collapse
- .from_library(path, symbol: nil, name: nil) ⇒ Object (also: from_path)
-
.load_by_name(name) ⇒ Language
Load a language by name from java-tree-sitter grammar JARs.
Instance Method Summary collapse
-
#<=>(other) ⇒ Integer?
Compare languages for equality.
-
#hash ⇒ Integer
Hash value for this language (for use in Sets/Hashes).
-
#initialize(impl, path: nil, symbol: nil) ⇒ Language
constructor
private
A new instance of Language.
Constructor Details
#initialize(impl, path: nil, symbol: nil) ⇒ Language
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 Language.
248 249 250 251 252 253 |
# File 'lib/tree_haver/backends/java.rb', line 248 def initialize(impl, path: nil, symbol: nil) @impl = impl @backend = :java @path = path @symbol = symbol end |
Instance Attribute Details
#backend ⇒ Symbol (readonly)
The backend this language is for
237 238 239 |
# File 'lib/tree_haver/backends/java.rb', line 237 def backend @backend end |
#impl ⇒ Object (readonly)
Returns the value of attribute impl.
233 234 235 |
# File 'lib/tree_haver/backends/java.rb', line 233 def impl @impl end |
#path ⇒ String? (readonly)
The path this language was loaded from (if known)
241 242 243 |
# File 'lib/tree_haver/backends/java.rb', line 241 def path @path end |
#symbol ⇒ String? (readonly)
The symbol name (if known)
245 246 247 |
# File 'lib/tree_haver/backends/java.rb', line 245 def symbol @symbol end |
Class Method Details
.from_library(path, symbol: nil, name: nil) ⇒ Object Also known as: from_path
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'lib/tree_haver/backends/java.rb', line 310 def from_library(path, symbol: nil, name: nil) raise TreeHaver::NotAvailable, "Java backend not available" unless Java.available? # Derive symbol from name or path if not provided base_name = File.basename(path, ".*").sub(/^lib/, "") sym = symbol || "tree_sitter_#{name || base_name.sub(/^tree-sitter-/, "")}" begin arena = ::Java::JavaLangForeign::Arena.global symbol_lookup_class = ::Java::JavaLangForeign::SymbolLookup # IMPORTANT: Load libtree-sitter.so FIRST by name so its symbols are available # Grammar libraries need symbols like ts_language_version from the runtime # We cache this lookup at the module level unless Java.runtime_lookup # Use libraryLookup(String, Arena) to search LD_LIBRARY_PATH Java.runtime_lookup = symbol_lookup_class.libraryLookup("libtree-sitter.so", arena) end # Now load the grammar library if File.exist?(path) # Explicit path provided - use libraryLookup(Path, Arena) java_path = ::Java::JavaNioFile::Paths.get(path) grammar_lookup = symbol_lookup_class.libraryLookup(java_path, arena) else # Library name provided - use libraryLookup(String, Arena) to search # LD_LIBRARY_PATH / DYLD_LIBRARY_PATH / PATH grammar_lookup = symbol_lookup_class.libraryLookup(path, arena) end # Chain the lookups: grammar first, then runtime library for ts_* symbols # This makes ts_language_version available when Language.load() needs it combined_lookup = grammar_lookup.or(Java.runtime_lookup) java_lang = Java.java_classes[:Language].load(combined_lookup, sym) new(java_lang, path: path, symbol: symbol) rescue ::Java::JavaLang::RuntimeException => e cause = e.cause root_cause = cause&.cause || cause error_msg = "Failed to load language '#{sym}' from #{path}: #{e.}" if root_cause.is_a?(::Java::JavaLang::UnsatisfiedLinkError) unresolved = root_cause..to_s if unresolved.include?("ts_language_version") # This specific symbol was renamed in tree-sitter 0.24 error_msg += "\n\nVersion mismatch detected: The grammar was built against " \ "tree-sitter < 0.24 (uses ts_language_version), but your runtime library " \ "is tree-sitter >= 0.24 (uses ts_language_abi_version).\n\n" \ "Solutions:\n" \ "1. Rebuild the grammar against your version of tree-sitter\n" \ "2. Install a matching version of tree-sitter (< 0.24)\n" \ "3. Find a pre-built grammar compatible with tree-sitter 0.24+" elsif unresolved.include?("ts_language") || unresolved.include?("ts_parser") error_msg += "\n\nThe grammar library has unresolved tree-sitter symbols. " \ "Ensure libtree-sitter.so is in LD_LIBRARY_PATH and version-compatible " \ "with the grammar." end end raise TreeHaver::NotAvailable, error_msg rescue ::Java::JavaLang::UnsatisfiedLinkError => e raise TreeHaver::NotAvailable, "Native library error loading #{path}: #{e.}. " \ "Ensure the library is in LD_LIBRARY_PATH." rescue ::Java::JavaLang::IllegalArgumentException => e raise TreeHaver::NotAvailable, "Could not find library '#{path}': #{e.}. " \ "Ensure it's in LD_LIBRARY_PATH or provide an absolute path." end end |
.load_by_name(name) ⇒ Language
Load a language by name from java-tree-sitter grammar JARs
This method loads grammars that are packaged as java-tree-sitter JARs from Maven Central. These JARs include the native grammar library pre-built for Java’s Foreign Function API.
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
# File 'lib/tree_haver/backends/java.rb', line 394 def load_by_name(name) raise TreeHaver::NotAvailable, "Java backend not available" unless Java.available? begin # java-tree-sitter's Language.load(String) searches for the language # in the classpath using standard naming conventions java_lang = Java.java_classes[:Language].load(name) new(java_lang, symbol: "tree_sitter_#{name}") rescue ::Java::JavaLang::RuntimeException => e raise TreeHaver::NotAvailable, "Failed to load language '#{name}': #{e.}. " \ "Ensure the grammar JAR (e.g., tree-sitter-#{name}-X.Y.Z.jar) " \ "is in TREE_SITTER_JAVA_JARS_DIR." end end |
Instance Method Details
#<=>(other) ⇒ Integer?
Compare languages for equality
Java languages are equal if they have the same backend, path, and symbol. Path and symbol uniquely identify a loaded language.
262 263 264 265 266 267 268 269 270 271 |
# File 'lib/tree_haver/backends/java.rb', line 262 def <=>(other) return unless other.is_a?(Language) return unless other.backend == @backend # Compare by path first, then symbol cmp = (@path || "") <=> (other.path || "") return cmp if cmp.nonzero? (@symbol || "") <=> (other.symbol || "") end |
#hash ⇒ Integer
Hash value for this language (for use in Sets/Hashes)
275 276 277 |
# File 'lib/tree_haver/backends/java.rb', line 275 def hash [@backend, @path, @symbol].hash end |