tree_haver 7.0.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/LICENSE.md +13 -0
  4. data/README.md +1959 -0
  5. data/lib/tree_haver/backend_api.rb +392 -0
  6. data/lib/tree_haver/backend_registry.rb +153 -3
  7. data/lib/tree_haver/backends/citrus.rb +489 -0
  8. data/lib/tree_haver/backends/ffi.rb +1013 -0
  9. data/lib/tree_haver/backends/java.rb +909 -0
  10. data/lib/tree_haver/backends/mri.rb +367 -0
  11. data/lib/tree_haver/backends/parslet.rb +565 -0
  12. data/lib/tree_haver/backends/prism.rb +568 -0
  13. data/lib/tree_haver/backends/psych.rb +379 -0
  14. data/lib/tree_haver/backends/rust.rb +243 -0
  15. data/lib/tree_haver/backends/tslp.rb +274 -0
  16. data/lib/tree_haver/base/comment.rb +320 -0
  17. data/lib/tree_haver/base/language.rb +98 -0
  18. data/lib/tree_haver/base/node.rb +330 -0
  19. data/lib/tree_haver/base/parser.rb +28 -0
  20. data/lib/tree_haver/base/point.rb +48 -0
  21. data/lib/tree_haver/base/tree.rb +128 -0
  22. data/lib/tree_haver/citrus_grammar_finder.rb +213 -0
  23. data/lib/tree_haver/contracts.rb +661 -96
  24. data/lib/tree_haver/grammar_finder.rb +429 -0
  25. data/lib/tree_haver/kaitai_backend.rb +2 -2
  26. data/lib/tree_haver/language.rb +294 -0
  27. data/lib/tree_haver/language_pack.rb +17 -166
  28. data/lib/tree_haver/language_registry.rb +221 -0
  29. data/lib/tree_haver/library_path_utils.rb +80 -0
  30. data/lib/tree_haver/node.rb +588 -0
  31. data/lib/tree_haver/parser.rb +445 -0
  32. data/lib/tree_haver/parslet_grammar_finder.rb +217 -0
  33. data/lib/tree_haver/path_validator.rb +356 -0
  34. data/lib/tree_haver/peg_backends.rb +7 -7
  35. data/lib/tree_haver/point.rb +27 -0
  36. data/lib/tree_haver/rspec/dependency_tags.rb +52 -0
  37. data/lib/tree_haver/rspec.rb +3 -0
  38. data/lib/tree_haver/tree.rb +267 -0
  39. data/lib/tree_haver/version.rb +5 -3
  40. data/lib/tree_haver.rb +613 -8
  41. data/sig/tree_haver.rbs +6 -0
  42. data.tar.gz.sig +0 -0
  43. metadata +314 -13
  44. metadata.gz.sig +0 -0
data/lib/tree_haver.rb CHANGED
@@ -1,13 +1,618 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "tree_haver/version"
4
- require_relative "tree_haver/backend_registry"
5
- require_relative "tree_haver/backend_context"
6
- require_relative "tree_haver/contracts"
7
- require_relative "tree_haver/peg_backends"
8
- require_relative "tree_haver/kaitai_backend"
9
- require_relative "tree_haver/language_pack"
3
+ require 'version_gem'
4
+ require_relative 'tree_haver/version'
10
5
 
11
6
  module TreeHaver
12
- PACKAGE_NAME = "tree_haver"
7
+ PACKAGE_NAME = 'tree_haver'
8
+
9
+ class Error < StandardError; end
10
+ class NotAvailable < Error; end
11
+ class BackendConflict < Error; end
12
+ end
13
+
14
+ require_relative 'tree_haver/backend_registry'
15
+ require_relative 'tree_haver/backend_context'
16
+ require_relative 'tree_haver/contracts'
17
+ require_relative 'tree_haver/backend_api'
18
+ require_relative 'tree_haver/base/point'
19
+ require_relative 'tree_haver/base/language'
20
+ require_relative 'tree_haver/base/parser'
21
+ require_relative 'tree_haver/base/tree'
22
+ require_relative 'tree_haver/base/node'
23
+ require_relative 'tree_haver/base/comment'
24
+ require_relative 'tree_haver/point'
25
+ require_relative 'tree_haver/node'
26
+ require_relative 'tree_haver/tree'
27
+ require_relative 'tree_haver/language_registry'
28
+ require_relative 'tree_haver/path_validator'
29
+ require_relative 'tree_haver/library_path_utils'
30
+ require_relative 'tree_haver/backends/mri'
31
+ require_relative 'tree_haver/backends/ffi'
32
+ require_relative 'tree_haver/backends/rust'
33
+ require_relative 'tree_haver/backends/java'
34
+ require_relative 'tree_haver/backends/tslp'
35
+ require_relative 'tree_haver/grammar_finder'
36
+ require_relative 'tree_haver/citrus_grammar_finder'
37
+ require_relative 'tree_haver/parslet_grammar_finder'
38
+ require_relative 'tree_haver/peg_backends'
39
+ require_relative 'tree_haver/kaitai_backend'
40
+ require_relative 'tree_haver/language_pack'
41
+ require_relative 'tree_haver/backends/psych'
42
+ require_relative 'tree_haver/backends/prism'
43
+ require_relative 'tree_haver/backends/citrus'
44
+ require_relative 'tree_haver/backends/parslet'
45
+ require_relative 'tree_haver/language'
46
+ require_relative 'tree_haver/parser'
47
+
48
+ module TreeHaver
49
+ NATIVE_BACKENDS = %i[mri rust ffi java].freeze
50
+ RUBY_BACKENDS = %i[citrus parslet prism psych commonmarker markly rbs].freeze
51
+ VALID_NATIVE_BACKENDS = NATIVE_BACKENDS.map(&:to_s).freeze
52
+ VALID_RUBY_BACKENDS = RUBY_BACKENDS.map(&:to_s).freeze
53
+ VALID_BACKENDS = (VALID_NATIVE_BACKENDS + VALID_RUBY_BACKENDS + %w[auto none tslp kreuzberg-language-pack]).freeze
54
+ DEFAULT_BACKEND_ID = 'tslp'
55
+ NATIVE_BACKEND_REFERENCES = NATIVE_BACKENDS.to_h do |backend_name|
56
+ [
57
+ backend_name,
58
+ BackendReference.new(id: backend_name.to_s, family: 'tree-sitter').freeze
59
+ ]
60
+ end.freeze
61
+
62
+ NATIVE_BACKEND_REFERENCES.each_value { |backend_ref| BackendRegistry.register(backend_ref) }
63
+
64
+ module_function
65
+
66
+ def register_standard_dependency_tags!
67
+ BackendRegistry.register_tag(:mri_backend, category: :backend, backend_name: :mri) do
68
+ Backends::MRI.available?
69
+ end
70
+ BackendRegistry.register_tag(:ffi_backend, category: :backend, backend_name: :ffi) do
71
+ Backends::FFI.available?
72
+ end
73
+ BackendRegistry.register_tag(:rust_backend, category: :backend, backend_name: :rust) do
74
+ Backends::Rust.available?
75
+ end
76
+ BackendRegistry.register_tag(:java_backend, category: :backend, backend_name: :java) do
77
+ Backends::Java.available?
78
+ end
79
+ end
80
+
81
+ def default_backend_id
82
+ DEFAULT_BACKEND_ID
83
+ end
84
+
85
+ def backend
86
+ @backend ||= parse_single_backend_env
87
+ end
88
+
89
+ def backend=(name)
90
+ @backend = name&.to_sym
91
+ end
92
+
93
+ def reset_backend!(to: :auto)
94
+ @backend = to&.to_sym
95
+ @allowed_native_backends = nil
96
+ @allowed_ruby_backends = nil
97
+ nil
98
+ end
99
+
100
+ def backend_protect=(value)
101
+ backend_protect_mutex.synchronize { @backend_protect = value }
102
+ end
103
+
104
+ def backend_protect?
105
+ return @backend_protect if defined?(@backend_protect)
106
+
107
+ true
108
+ end
109
+
110
+ def backend_protect
111
+ backend_protect?
112
+ end
113
+
114
+ def backends_used
115
+ @backends_used ||= Set.new
116
+ end
117
+
118
+ def record_backend_usage(backend_name)
119
+ backends_used << backend_name.to_sym
120
+ nil
121
+ end
122
+
123
+ def conflicting_backends_for(backend_name)
124
+ blockers = {
125
+ mri: [],
126
+ rust: [],
127
+ ffi: [:mri],
128
+ java: [],
129
+ citrus: [],
130
+ parslet: [],
131
+ prism: [],
132
+ psych: []
133
+ }.fetch(backend_name.to_sym, [])
134
+ blockers & backends_used.to_a
135
+ end
136
+
137
+ def check_backend_conflict!(backend_name)
138
+ return unless backend_protect?
139
+
140
+ conflicts = conflicting_backends_for(backend_name)
141
+ return if conflicts.empty?
142
+
143
+ raise BackendConflict,
144
+ "Cannot use #{backend_name} backend: it is blocked by previously used backend(s): #{conflicts.join(', ')}."
145
+ end
146
+
147
+ def allowed_native_backends
148
+ @allowed_native_backends ||= parse_backend_list_env('TREE_HAVER_NATIVE_BACKEND', VALID_NATIVE_BACKENDS)
149
+ end
150
+
151
+ def allowed_ruby_backends
152
+ @allowed_ruby_backends ||= parse_backend_list_env('TREE_HAVER_RUBY_BACKEND', VALID_RUBY_BACKENDS)
153
+ end
154
+
155
+ def backend_allowed?(backend_name)
156
+ backend_sym = backend_name.to_sym
157
+ if VALID_NATIVE_BACKENDS.include?(backend_sym.to_s)
158
+ allowed = allowed_native_backends
159
+ return true if allowed == [:auto]
160
+ return false if allowed == [:none]
161
+
162
+ return allowed.include?(backend_sym)
163
+ end
164
+
165
+ if VALID_RUBY_BACKENDS.include?(backend_sym.to_s)
166
+ allowed = allowed_ruby_backends
167
+ return true if allowed == [:auto]
168
+ return false if allowed == [:none]
169
+
170
+ return allowed.include?(backend_sym)
171
+ end
172
+
173
+ true
174
+ end
175
+
176
+ def effective_backend
177
+ contextual = current_backend_id
178
+ return contextual.to_sym if contextual && !contextual.empty?
179
+
180
+ backend || :auto
181
+ end
182
+
183
+ def resolve_effective_backend(explicit_backend = nil)
184
+ return explicit_backend.to_sym if explicit_backend
185
+
186
+ effective_backend
187
+ end
188
+
189
+ def resolve_backend_module(explicit_backend = nil)
190
+ requested = resolve_effective_backend(explicit_backend)
191
+ return backend_module if requested == :auto
192
+ return if %i[tslp kreuzberg-language-pack].include?(requested)
193
+ return unless backend_allowed?(requested)
194
+
195
+ mod = backend_module_for(requested)
196
+ return unless mod
197
+
198
+ check_backend_conflict!(requested)
199
+ return if mod.respond_to?(:available?) && !mod.available?
200
+
201
+ record_backend_usage(requested)
202
+ mod
203
+ end
204
+
205
+ def resolve_native_backend_module(explicit_backend = nil)
206
+ requested = resolve_effective_backend(explicit_backend)
207
+ return resolve_backend_module(requested) if NATIVE_BACKENDS.include?(requested)
208
+ return if explicit_backend
209
+
210
+ native_backend_priority.each do |backend_name|
211
+ mod = resolve_backend_module(backend_name)
212
+ return mod if mod
213
+ rescue BackendConflict
214
+ next
215
+ end
216
+
217
+ nil
218
+ end
219
+
220
+ def backend_module
221
+ requested = effective_backend
222
+ return backend_module_for(requested) if requested != :auto && backend_module_available?(requested)
223
+
224
+ backend_priority.each do |backend_name|
225
+ next unless backend_allowed?(backend_name)
226
+
227
+ mod = backend_module_for(backend_name)
228
+ next unless mod
229
+ next if mod.respond_to?(:available?) && !mod.available?
230
+
231
+ return mod
232
+ rescue BackendConflict
233
+ next
234
+ end
235
+
236
+ nil
237
+ end
238
+
239
+ def capabilities
240
+ backend_module&.capabilities || {}
241
+ end
242
+
243
+ def register_backend(name, mod)
244
+ backend_module_registry[name.to_sym] = mod
245
+ nil
246
+ end
247
+
248
+ def registered_backend(name)
249
+ backend_module_registry[name.to_sym]
250
+ end
251
+
252
+ def registered_language(name)
253
+ LanguageRegistry.registered(name)
254
+ end
255
+
256
+ def register_language(name, path: nil, symbol: nil, grammar_module: nil, grammar_class: nil, backend_module: nil,
257
+ backend_type: nil, gem_name: nil, contract: nil)
258
+ LanguageRegistry.register(name, :tree_sitter, path: path, symbol: symbol, contract: contract) if path
259
+
260
+ if grammar_module
261
+ LanguageRegistry.register(name, :citrus, grammar_module: grammar_module, gem_name: gem_name, contract: contract)
262
+ end
263
+
264
+ if grammar_class
265
+ LanguageRegistry.register(name, :parslet, grammar_class: grammar_class, gem_name: gem_name, contract: contract)
266
+ end
267
+
268
+ if backend_module
269
+ LanguageRegistry.register(name, backend_type || backend_module.name.split('::').last.downcase.to_sym,
270
+ backend_module: backend_module, gem_name: gem_name, contract: contract)
271
+ register_backend(backend_type || backend_module.name.split('::').last.downcase.to_sym, backend_module)
272
+ end
273
+
274
+ if path.nil? && grammar_module.nil? && grammar_class.nil? && backend_module.nil?
275
+ raise ArgumentError, 'Provide path:, grammar_module:, grammar_class:, or backend_module:'
276
+ end
277
+
278
+ nil
279
+ end
280
+
281
+ def with_language_registration(name, backend_type, **config, &block)
282
+ raise ArgumentError, 'Block required' unless block
283
+
284
+ LanguageRegistry.with_registration(name, backend_type, **config, &block)
285
+ end
286
+
287
+ def registered_languages(name)
288
+ LanguageRegistry.registered(name) || {}
289
+ end
290
+
291
+ def parser_for(language_name, library_path: nil, symbol: nil, citrus_config: nil, parslet_config: nil,
292
+ backend_type: nil, contract: nil, preferred: nil)
293
+ name = language_name.to_sym
294
+
295
+ return parser_for_tree_sitter(name, library_path, symbol) if library_path
296
+
297
+ registrations = filter_language_registrations(
298
+ LanguageRegistry.registered(name) || {},
299
+ contract || backend_type
300
+ )
301
+ if (backend_type = requested_backend_type(registrations))
302
+ return parser_for_registered_backend(name, backend_type, registrations)
303
+ end
304
+
305
+ Array(preferred).each do |preferred_backend_type|
306
+ type = preferred_backend_type.to_sym
307
+ next unless registrations.key?(type)
308
+ next unless registered_backend_type_available?(type, registrations.fetch(type))
309
+
310
+ return parser_for_registered_backend(name, type, registrations)
311
+ end
312
+
313
+ if (config = registrations[:psych])
314
+ return parser_for_backend_module(config.fetch(:backend_module), name)
315
+ end
316
+
317
+ if (config = registrations[:prism])
318
+ return parser_for_backend_module(config.fetch(:backend_module), name)
319
+ end
320
+
321
+ if (config = registrations[:citrus]) || citrus_config
322
+ module_config = config || citrus_config
323
+ return parser_for_citrus(module_config.fetch(:grammar_module))
324
+ end
325
+
326
+ if (config = registrations[:parslet]) || parslet_config
327
+ class_config = config || parslet_config
328
+ return parser_for_parslet(class_config.fetch(:grammar_class))
329
+ end
330
+
331
+ if (config = registrations[:rbs])
332
+ return parser_for_backend_module(config.fetch(:backend_module), name)
333
+ end
334
+
335
+ if (config = registrations[:tree_sitter])
336
+ return parser_for_tree_sitter(name, config[:path], config[:symbol])
337
+ end
338
+
339
+ if (backend_type = first_available_registered_backend_type(registrations))
340
+ return parser_for_registered_backend(name, backend_type, registrations)
341
+ end
342
+
343
+ raise NotAvailable, "No parser registered for #{name}"
344
+ end
345
+
346
+ def ruby_reference_parser_backend_contract_report
347
+ {
348
+ report_id: 'ruby-tree-haver-parser-backend-contract',
349
+ reference_runtime: 'ruby',
350
+ contract_layer: 'tree_haver',
351
+ proves: [
352
+ {
353
+ capability: 'stable_node_spans',
354
+ fixture_roles: %w[portable_byte_location_contract node_span_source_fragment],
355
+ ruby_surface: 'TreeHaver::ByteRange and TreeHaver::SourceSpan',
356
+ portability: 'portable_contract'
357
+ },
358
+ {
359
+ capability: 'source_fragments',
360
+ fixture_roles: %w[source_fragment_extraction node_span_source_fragment],
361
+ ruby_surface: 'TreeHaver.extract_source_fragment',
362
+ portability: 'portable_contract'
363
+ },
364
+ {
365
+ capability: 'comments_when_backend_supports_them',
366
+ fixture_roles: %w[comment_capability],
367
+ ruby_surface: 'TreeHaver::Base::Comment',
368
+ portability: 'backend_restricted_contract'
369
+ },
370
+ {
371
+ capability: 'parser_diagnostics',
372
+ fixture_roles: %w[parse_error_tolerance parser_diagnostics],
373
+ ruby_surface: 'TreeHaver::ParseErrorTolerance and TreeHaver::ParserDiagnostics',
374
+ portability: 'portable_contract'
375
+ },
376
+ {
377
+ capability: 'backend_capability_reports',
378
+ fixture_roles: %w[backend_capability_report backend_availability provider_diagnostics],
379
+ ruby_surface: 'TreeHaver::BackendCapability',
380
+ portability: 'portable_contract'
381
+ },
382
+ {
383
+ capability: 'backend_selection_context',
384
+ fixture_roles: %w[backend_selection_context backend_registry],
385
+ ruby_surface: 'TreeHaver.with_backend and TreeHaver.current_backend_id',
386
+ portability: 'portable_contract_runtime_local_mechanism'
387
+ }
388
+ ],
389
+ release_status: 'ruby_reference_ready',
390
+ diagnostics: [
391
+ {
392
+ severity: 'info',
393
+ category: 'ruby_reference_contract',
394
+ message: 'Ruby tree_haver proves the parser/backend substrate needed by source-region extraction.'
395
+ }
396
+ ]
397
+ }
398
+ end
399
+
400
+ def requested_backend_type(registrations)
401
+ backend_id = current_backend_id || ENV['TREE_HAVER_BACKEND']
402
+ return if backend_id.to_s.empty?
403
+
404
+ backend_ref = BackendRegistry.fetch(backend_id.to_s)
405
+ type = if registrations.key?(backend_id.to_s.to_sym)
406
+ backend_id.to_s.to_sym
407
+ elsif (registered_type = registered_backend_type_for_requested_backend(backend_id, registrations))
408
+ registered_type
409
+ elsif backend_ref&.family == 'tree-sitter'
410
+ :tree_sitter
411
+ else
412
+ backend_id.to_s.to_sym
413
+ end
414
+ return type if registrations.key?(type)
415
+
416
+ raise NotAvailable, "No parser registered for backend #{backend_id}"
417
+ end
418
+ private_class_method :requested_backend_type
419
+
420
+ def filter_language_registrations(registrations, contract_filter)
421
+ contracts = Array(contract_filter).map { |contract| contract.to_s.tr('-', '_').to_sym }
422
+ return registrations if contracts.empty?
423
+
424
+ registrations.select do |backend_type, config|
425
+ contracts.include?(registration_contract(backend_type, config))
426
+ end
427
+ end
428
+ private_class_method :filter_language_registrations
429
+
430
+ def registration_contract(backend_type, config)
431
+ explicit = config[:contract]
432
+ return explicit.to_s.tr('-', '_').to_sym if explicit
433
+ return :tree_sitter if backend_type.to_sym == :tree_sitter
434
+
435
+ backend_ref = BackendRegistry.fetch(backend_type.to_s)
436
+ return :tree_sitter if backend_ref&.family == 'tree-sitter'
437
+
438
+ backend_type.to_sym
439
+ end
440
+ private_class_method :registration_contract
441
+
442
+ def registered_backend_type_for_requested_backend(backend_id, registrations)
443
+ requested_module = backend_module_for(backend_id)
444
+ return unless requested_module
445
+
446
+ registrations.find do |_backend_type, config|
447
+ config[:backend_module].equal?(requested_module)
448
+ end&.first
449
+ end
450
+ private_class_method :registered_backend_type_for_requested_backend
451
+
452
+ def parser_for_registered_backend(name, backend_type, registrations)
453
+ config = registrations.fetch(backend_type)
454
+ case backend_type
455
+ when :psych, :prism, :commonmarker, :markly, :rbs
456
+ parser_for_backend_module(config.fetch(:backend_module), name)
457
+ when :citrus
458
+ parser_for_citrus(config.fetch(:grammar_module))
459
+ when :parslet
460
+ parser_for_parslet(config.fetch(:grammar_class))
461
+ when :tree_sitter
462
+ parser_for_tree_sitter(name, config[:path], config[:symbol])
463
+ else
464
+ raise NotAvailable, "No parser registered for backend #{backend_type}" unless config[:backend_module]
465
+
466
+ parser_for_backend_module(config.fetch(:backend_module), name)
467
+
468
+ end
469
+ end
470
+ private_class_method :parser_for_registered_backend
471
+
472
+ def first_available_registered_backend_type(registrations)
473
+ registrations.each do |backend_type, config|
474
+ next unless registered_backend_type_available?(backend_type, config)
475
+
476
+ return backend_type
477
+ end
478
+
479
+ nil
480
+ end
481
+ private_class_method :first_available_registered_backend_type
482
+
483
+ def registered_backend_type_available?(backend_type, config)
484
+ return true if backend_type.to_sym == :tree_sitter && (config[:path] || config[:backend_module])
485
+ return false unless config[:backend_module]
486
+ return false unless backend_allowed?(backend_type)
487
+
488
+ backend_module = config.fetch(:backend_module)
489
+ return false if backend_module.respond_to?(:available?) && !backend_module.available?
490
+
491
+ true
492
+ end
493
+ private_class_method :registered_backend_type_available?
494
+
495
+ def parser_for_backend_module(backend_module, name)
496
+ parser = backend_module::Parser.new
497
+ language_factory = backend_module::Language
498
+ parser.language = if language_factory.respond_to?(name)
499
+ language_factory.public_send(name)
500
+ elsif language_factory.respond_to?(:from_library)
501
+ language_factory.from_library(nil, name: name)
502
+ else
503
+ language_factory.new(name)
504
+ end
505
+ parser
506
+ end
507
+ private_class_method :parser_for_backend_module
508
+
509
+ def parser_for_citrus(grammar_module)
510
+ parser = Backends::Citrus::Parser.new
511
+ parser.language = Backends::Citrus::Language.new(grammar_module)
512
+ parser
513
+ end
514
+ private_class_method :parser_for_citrus
515
+
516
+ def parser_for_parslet(grammar_class)
517
+ parser = Backends::Parslet::Parser.new
518
+ parser.language = Backends::Parslet::Language.new(grammar_class)
519
+ parser
520
+ end
521
+ private_class_method :parser_for_parslet
522
+
523
+ def parser_for_tree_sitter(name, library_path, symbol)
524
+ symbol ||= "tree_sitter_#{name}"
525
+ language = Language.from_library(library_path, symbol: symbol, name: name)
526
+ parser = Parser.new
527
+ parser.language = language
528
+ parser
529
+ end
530
+ private_class_method :parser_for_tree_sitter
531
+
532
+ def parse_single_backend_env
533
+ value = ENV['TREE_HAVER_BACKEND'].to_s.strip
534
+ return :auto if value.empty?
535
+
536
+ VALID_BACKENDS.include?(value) ? value.to_sym : :auto
537
+ end
538
+ private_class_method :parse_single_backend_env
539
+
540
+ def parse_backend_list_env(env_name, valid_backends)
541
+ normalized = ENV[env_name].to_s.strip.downcase
542
+ return [:auto] if normalized.empty? || normalized == 'auto'
543
+ return [:none] if normalized == 'none'
544
+
545
+ parsed = normalized.split(',').filter_map do |name|
546
+ candidate = name.strip
547
+ valid_backends.include?(candidate) ? candidate.to_sym : nil
548
+ end.uniq
549
+ parsed.empty? ? [:auto] : parsed
550
+ end
551
+ private_class_method :parse_backend_list_env
552
+
553
+ def backend_module_for(backend_name)
554
+ case backend_name.to_sym
555
+ when :mri
556
+ Backends::MRI
557
+ when :rust
558
+ Backends::Rust
559
+ when :ffi
560
+ Backends::FFI
561
+ when :java
562
+ Backends::Java
563
+ when :tslp, :"kreuzberg-language-pack"
564
+ Backends::Tslp
565
+ when :citrus
566
+ Backends::Citrus
567
+ when :parslet
568
+ Backends::Parslet
569
+ when :prism
570
+ Backends::Prism
571
+ when :psych
572
+ Backends::Psych
573
+ else
574
+ registered_backend(backend_name)
575
+ end
576
+ end
577
+ private_class_method :backend_module_for
578
+
579
+ def backend_module_available?(backend_name)
580
+ mod = backend_module_for(backend_name)
581
+ return false unless mod
582
+ return false unless backend_allowed?(backend_name)
583
+ return false if mod.respond_to?(:available?) && !mod.available?
584
+
585
+ true
586
+ end
587
+ private_class_method :backend_module_available?
588
+
589
+ def backend_priority
590
+ native_backend_priority + %i[prism psych citrus parslet]
591
+ end
592
+ private_class_method :backend_priority
593
+
594
+ def native_backend_priority
595
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
596
+ %i[java ffi]
597
+ else
598
+ %i[mri rust ffi]
599
+ end
600
+ end
601
+ private_class_method :native_backend_priority
602
+
603
+ def backend_module_registry
604
+ @backend_module_registry ||= {}
605
+ end
606
+ private_class_method :backend_module_registry
607
+
608
+ def backend_protect_mutex
609
+ @backend_protect_mutex ||= Mutex.new
610
+ end
611
+ private_class_method :backend_protect_mutex
612
+ end
613
+
614
+ TreeHaver.register_standard_dependency_tags!
615
+
616
+ TreeHaver::Version.class_eval do
617
+ extend VersionGem::Basic
13
618
  end
@@ -0,0 +1,6 @@
1
+ module TreeHaver
2
+ module Version
3
+ VERSION: String
4
+ end
5
+ VERSION: String
6
+ end
data.tar.gz.sig CHANGED
Binary file