tree_haver 3.1.2 → 3.2.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.
data/lib/tree_haver.rb CHANGED
@@ -15,11 +15,33 @@ require_relative "tree_haver/language_registry"
15
15
  # Provides a unified API for parsing source code across MRI Ruby, JRuby, and TruffleRuby
16
16
  # using tree-sitter grammars or language-specific native parsers.
17
17
  #
18
+ # == Backends
19
+ #
18
20
  # Supports 10 backends:
19
21
  # - Tree-sitter: MRI (C), Rust, FFI, Java
20
22
  # - Native parsers: Prism (Ruby), Psych (YAML), Commonmarker (Markdown), Markly (GFM)
21
23
  # - Pure Ruby: Citrus (portable fallback)
22
24
  #
25
+ # == Platform Compatibility
26
+ #
27
+ # Not all backends work on all Ruby platforms:
28
+ #
29
+ # | Backend | MRI | JRuby | TruffleRuby |
30
+ # |--------------|-----|-------|-------------|
31
+ # | MRI (C ext) | ✓ | ✗ | ✗ |
32
+ # | Rust | ✓ | ✗ | ✗ |
33
+ # | FFI | ✓ | ✓ | ✗ |
34
+ # | Java | ✗ | ✓ | ✗ |
35
+ # | Prism | ✓ | ✓ | ✓ |
36
+ # | Psych | ✓ | ✓ | ✓ |
37
+ # | Citrus | ✓ | ✓ | ✓ |
38
+ # | Commonmarker | ✓ | ✗ | ? |
39
+ # | Markly | ✓ | ✗ | ? |
40
+ #
41
+ # - JRuby: Cannot load native C/Rust extensions; use FFI, Java, or pure Ruby backends
42
+ # - TruffleRuby: FFI doesn't support STRUCT_BY_VALUE; magnus/rb-sys incompatible with C API;
43
+ # use Prism, Psych, Citrus, or potentially Commonmarker/Markly
44
+ #
23
45
  # @example Basic usage with tree-sitter
24
46
  # # Load a language grammar
25
47
  # language = TreeHaver::Language.from_library(
@@ -131,6 +153,20 @@ module TreeHaver
131
153
  # # Now you can test backend conflicts (at risk of segfaults)
132
154
  class BackendConflict < Error; end
133
155
 
156
+ # Default Citrus configurations for known languages
157
+ #
158
+ # These are used by {TreeHaver.parser_for} when no explicit citrus_config is provided
159
+ # and tree-sitter backends are not available (e.g., on TruffleRuby).
160
+ #
161
+ # @api private
162
+ CITRUS_DEFAULTS = {
163
+ toml: {
164
+ gem_name: "toml-rb",
165
+ grammar_const: "TomlRB::Document",
166
+ require_path: "toml-rb",
167
+ },
168
+ }.freeze
169
+
134
170
  # Namespace for backend implementations
135
171
  #
136
172
  # TreeHaver provides multiple backends to support different Ruby implementations:
@@ -545,6 +581,66 @@ module TreeHaver
545
581
  mod
546
582
  end
547
583
 
584
+ # Native tree-sitter backends that support loading shared libraries (.so files)
585
+ # These backends wrap the tree-sitter C library via various bindings.
586
+ # Pure Ruby backends (Citrus, Prism, Psych, Commonmarker, Markly) are excluded.
587
+ NATIVE_BACKENDS = %i[mri rust ffi java].freeze
588
+
589
+ # Resolve a native tree-sitter backend module (for from_library)
590
+ #
591
+ # This method is similar to resolve_backend_module but ONLY considers
592
+ # backends that support loading shared libraries (.so files):
593
+ # - MRI (ruby_tree_sitter C extension)
594
+ # - Rust (tree_stump)
595
+ # - FFI (ffi gem with libtree-sitter)
596
+ # - Java (jtreesitter on JRuby)
597
+ #
598
+ # Pure Ruby backends (Citrus, Prism, Psych, Commonmarker, Markly) are NOT
599
+ # considered because they don't support from_library.
600
+ #
601
+ # @param explicit_backend [Symbol, String, nil] explicitly requested backend
602
+ # @return [Module, nil] the backend module or nil if none available
603
+ # @raise [BackendConflict] if the backend conflicts with previously used backends
604
+ def resolve_native_backend_module(explicit_backend = nil)
605
+ # Short-circuit on TruffleRuby: no native backends work
606
+ # - MRI: C extension, MRI only
607
+ # - Rust: magnus requires MRI's C API
608
+ # - FFI: STRUCT_BY_VALUE not supported
609
+ # - Java: requires JRuby's Java interop
610
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "truffleruby"
611
+ return unless explicit_backend # Auto-select: no backends available
612
+ # If explicit backend requested, let it fail with proper error below
613
+ end
614
+
615
+ # Get the effective backend (considers thread-local and global settings)
616
+ requested = resolve_effective_backend(explicit_backend)
617
+
618
+ # If the effective backend is a native backend, use it
619
+ if NATIVE_BACKENDS.include?(requested)
620
+ return resolve_backend_module(requested)
621
+ end
622
+
623
+ # If a specific non-native backend was explicitly requested, return nil
624
+ # (from_library only works with native backends that load .so files)
625
+ return if explicit_backend
626
+
627
+ # If effective backend is :auto, auto-select from native backends in priority order
628
+ # Note: non-native backends set via with_backend are NOT used here because
629
+ # from_library only works with native backends
630
+ native_priority = if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
631
+ %i[java ffi] # JRuby: Java first, then FFI
632
+ else
633
+ %i[mri rust ffi] # MRI: MRI first, then Rust, then FFI
634
+ end
635
+
636
+ native_priority.each do |backend|
637
+ mod = resolve_backend_module(backend)
638
+ return mod if mod
639
+ end
640
+
641
+ nil # No native backend available
642
+ end
643
+
548
644
  # Determine the concrete backend module to use
549
645
  #
550
646
  # This method performs backend auto-selection when backend is :auto.
@@ -804,19 +900,25 @@ module TreeHaver
804
900
 
805
901
  # Step 3: Try Citrus fallback if tree-sitter failed
806
902
  unless language
807
- citrus_config ||= {}
808
- begin
809
- citrus_finder = CitrusGrammarFinder.new(
810
- language: name,
811
- gem_name: citrus_config[:gem_name],
812
- grammar_const: citrus_config[:grammar_const],
813
- )
814
- if citrus_finder.available?
815
- citrus_finder.register!
816
- language = Language.public_send(name)
903
+ # Use explicit config, or fall back to built-in defaults for known languages
904
+ citrus_config ||= CITRUS_DEFAULTS[name] || {}
905
+
906
+ # Only attempt if we have the required configuration
907
+ if citrus_config[:gem_name] && citrus_config[:grammar_const]
908
+ begin
909
+ citrus_finder = CitrusGrammarFinder.new(
910
+ language: name,
911
+ gem_name: citrus_config[:gem_name],
912
+ grammar_const: citrus_config[:grammar_const],
913
+ require_path: citrus_config[:require_path],
914
+ )
915
+ if citrus_finder.available?
916
+ citrus_finder.register!
917
+ language = Language.public_send(name)
918
+ end
919
+ rescue NotAvailable, ArgumentError, LoadError, NameError, TypeError
920
+ language = nil
817
921
  end
818
- rescue NotAvailable, ArgumentError, LoadError, NameError
819
- language = nil
820
922
  end
821
923
  end
822
924
 
@@ -912,13 +1014,18 @@ module TreeHaver
912
1014
  end
913
1015
  end
914
1016
 
915
- mod = TreeHaver.resolve_backend_module(backend)
1017
+ # from_library only works with tree-sitter backends that support .so files
1018
+ # Pure Ruby backends (Citrus, Prism, Psych, Commonmarker, Markly) don't support from_library
1019
+ mod = TreeHaver.resolve_native_backend_module(backend)
916
1020
 
917
1021
  if mod.nil?
918
1022
  if backend
919
- raise NotAvailable, "Requested backend #{backend.inspect} is not available"
1023
+ raise NotAvailable, "Requested backend #{backend.inspect} is not available or does not support shared libraries"
920
1024
  else
921
- raise NotAvailable, "No TreeHaver backend is available"
1025
+ raise NotAvailable,
1026
+ "No native tree-sitter backend is available for loading shared libraries. " \
1027
+ "Available native backends (MRI, Rust, FFI, Java) require platform-specific setup. " \
1028
+ "For pure-Ruby parsing, use backend-specific Language classes directly (e.g., Prism, Psych, Citrus)."
922
1029
  end
923
1030
  end
924
1031
 
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tree_haver
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.2
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -289,10 +289,10 @@ licenses:
289
289
  - MIT
290
290
  metadata:
291
291
  homepage_uri: https://tree-haver.galtzo.com/
292
- source_code_uri: https://github.com/kettle-rb/tree_haver/tree/v3.1.2
293
- changelog_uri: https://github.com/kettle-rb/tree_haver/blob/v3.1.2/CHANGELOG.md
292
+ source_code_uri: https://github.com/kettle-rb/tree_haver/tree/v3.2.0
293
+ changelog_uri: https://github.com/kettle-rb/tree_haver/blob/v3.2.0/CHANGELOG.md
294
294
  bug_tracker_uri: https://github.com/kettle-rb/tree_haver/issues
295
- documentation_uri: https://www.rubydoc.info/gems/tree_haver/3.1.2
295
+ documentation_uri: https://www.rubydoc.info/gems/tree_haver/3.2.0
296
296
  funding_uri: https://github.com/sponsors/pboling
297
297
  wiki_uri: https://github.com/kettle-rb/tree_haver/wiki
298
298
  news_uri: https://www.railsbling.com/tags/tree_haver
metadata.gz.sig CHANGED
Binary file