@@ -17,11 +17,13 @@ use harp::external_ptr::ExternalPointer;
17
17
use harp:: object:: RObject ;
18
18
use harp:: protect:: RProtect ;
19
19
use harp:: r_symbol;
20
+ use harp:: utils:: r_is_null;
20
21
use harp:: utils:: r_symbol_quote_invalid;
21
22
use harp:: utils:: r_symbol_valid;
22
23
use harp:: vector:: CharacterVector ;
23
24
use harp:: vector:: Vector ;
24
25
use libR_sys:: * ;
26
+ use libc:: c_void;
25
27
use stdext:: * ;
26
28
use tower_lsp:: lsp_types:: Diagnostic ;
27
29
use tower_lsp:: lsp_types:: DiagnosticSeverity ;
@@ -635,78 +637,72 @@ impl<'a> TreeSitterCall<'a> {
635
637
}
636
638
}
637
639
638
- // FIXME: Can't directly switch to `r_task()`
639
- // rustc [E0277]: `*const tree_sitter::ffi::TSTree` cannot be shared between threads safely
640
- // within `tree_sitter::Node<'_>`, the trait `Sync` is not implemented for `*const tree_sitter::ffi::TSTree`
641
- // required for `&tree_sitter::Node<'_>` to implement `Send`
642
- // rustc [E0277]: `*const c_void` cannot be shared between threads safely
643
-
644
- // fn recurse_call_arguments_custom(
645
- // node: Node,
646
- // context: &mut DiagnosticContext,
647
- // diagnostics: &mut Vec<Diagnostic>,
648
- // function: &str,
649
- // diagnostic_function: &str,
650
- // ) -> Result<()> {
651
- // r_lock! {
652
- // // Build a call that mixes treesitter nodes (as external pointers)
653
- // // library(foo, pos = 2 + 2)
654
- // // ->
655
- // // library([0, <node0>], pos = [1, <node1>])
656
- // // where:
657
- // // - node0 is an external pointer to a treesitter Node for the identifier `foo`
658
- // // - node1 is an external pointer to a treesitter Node for the call `2 + 2`
659
- // //
660
- // // The TreeSitterCall object holds on to the nodes, so that they can be
661
- // // safely passed down to the R side as external pointers
662
- // let call = TreeSitterCall::new(node, function, context)?;
663
-
664
- // let custom_diagnostics = RFunction::from(diagnostic_function)
665
- // .add(&call)
666
- // .add(ExternalPointer::new(&context.source))
667
- // .call()?;
668
-
669
- // if !r_is_null(*custom_diagnostics) {
670
- // let n = XLENGTH(*custom_diagnostics);
671
- // for i in 0..n {
672
- // // diag is a list with:
673
- // // - The kind of diagnostic: skip, default, simple
674
- // // - The node external pointer, i.e. the ones made in TreeSitterCall::new
675
- // // - The message, when kind is "simple"
676
- // let diag = VECTOR_ELT(*custom_diagnostics, i);
677
-
678
- // let kind: String = RObject::view(VECTOR_ELT(diag, 0)).try_into()?;
679
-
680
- // if kind == "skip" {
681
- // // skip the diagnostic entirely, e.g.
682
- // // library(foo)
683
- // // ^^^
684
- // continue;
685
- // }
686
-
687
- // let ptr = VECTOR_ELT(diag, 1);
688
- // let value = *(R_ExternalPtrAddr(ptr) as *const c_void as *const Node);
689
-
690
- // if kind == "default" {
691
- // // the R side gives up, so proceed as normal, e.g.
692
- // // library(foo, pos = ...)
693
- // // ^^^
694
- // recurse(value, context, diagnostics)?;
695
- // } else if kind == "simple" {
696
- // // Simple diagnostic from R, e.g.
697
- // // library("ggplot3")
698
- // // ^^^^^^^ Package 'ggplot3' is not installed
699
- // let message: String = RObject::view(VECTOR_ELT(diag, 2)).try_into()?;
700
- // let range: Range = value.range().into();
701
- // let diagnostic = Diagnostic::new_simple(range.into(), message.into());
702
- // diagnostics.push(diagnostic);
703
- // }
704
- // }
705
- // }
706
-
707
- // ().ok()
708
- // }
709
- // }
640
+ fn recurse_call_arguments_custom (
641
+ node : Node ,
642
+ context : & mut DiagnosticContext ,
643
+ diagnostics : & mut Vec < Diagnostic > ,
644
+ function : & str ,
645
+ diagnostic_function : & str ,
646
+ ) -> Result < ( ) > {
647
+ r_task ( || unsafe {
648
+ // Build a call that mixes treesitter nodes (as external pointers)
649
+ // library(foo, pos = 2 + 2)
650
+ // ->
651
+ // library([0, <node0>], pos = [1, <node1>])
652
+ // where:
653
+ // - node0 is an external pointer to a treesitter Node for the identifier `foo`
654
+ // - node1 is an external pointer to a treesitter Node for the call `2 + 2`
655
+ //
656
+ // The TreeSitterCall object holds on to the nodes, so that they can be
657
+ // safely passed down to the R side as external pointers
658
+ let call = TreeSitterCall :: new ( node, function, context) ?;
659
+
660
+ let custom_diagnostics = RFunction :: from ( diagnostic_function)
661
+ . add ( & call)
662
+ . add ( ExternalPointer :: new ( & context. source ) )
663
+ . call ( ) ?;
664
+
665
+ if !r_is_null ( * custom_diagnostics) {
666
+ let n = XLENGTH ( * custom_diagnostics) ;
667
+ for i in 0 ..n {
668
+ // diag is a list with:
669
+ // - The kind of diagnostic: skip, default, simple
670
+ // - The node external pointer, i.e. the ones made in TreeSitterCall::new
671
+ // - The message, when kind is "simple"
672
+ let diag = VECTOR_ELT ( * custom_diagnostics, i) ;
673
+
674
+ let kind: String = RObject :: view ( VECTOR_ELT ( diag, 0 ) ) . try_into ( ) ?;
675
+
676
+ if kind == "skip" {
677
+ // skip the diagnostic entirely, e.g.
678
+ // library(foo)
679
+ // ^^^
680
+ continue ;
681
+ }
682
+
683
+ let ptr = VECTOR_ELT ( diag, 1 ) ;
684
+ let value = * ( R_ExternalPtrAddr ( ptr) as * const c_void as * const Node ) ;
685
+
686
+ if kind == "default" {
687
+ // the R side gives up, so proceed as normal, e.g.
688
+ // library(foo, pos = ...)
689
+ // ^^^
690
+ recurse ( value, context, diagnostics) ?;
691
+ } else if kind == "simple" {
692
+ // Simple diagnostic from R, e.g.
693
+ // library("ggplot3")
694
+ // ^^^^^^^ Package 'ggplot3' is not installed
695
+ let message: String = RObject :: view ( VECTOR_ELT ( diag, 2 ) ) . try_into ( ) ?;
696
+ let range: Range = value. range ( ) . into ( ) ;
697
+ let diagnostic = Diagnostic :: new_simple ( range. into ( ) , message. into ( ) ) ;
698
+ diagnostics. push ( diagnostic) ;
699
+ }
700
+ }
701
+ }
702
+
703
+ ( ) . ok ( )
704
+ } )
705
+ }
710
706
711
707
fn recurse_call (
712
708
node : Node ,
@@ -726,30 +722,25 @@ fn recurse_call(
726
722
// things like 'local({ ... })'.
727
723
let fun = callee. utf8_text ( context. source . as_bytes ( ) ) ?;
728
724
match fun {
729
- // FIXME: These are currently disabled because they use the R
730
- // runtime to match arguments with an approach that meshes R and
731
- // treesitter objects. This is not compatible with `r_task()`
732
- // because treesitter objects are not Send/Sync.
733
-
734
- // // TODO: there should be some sort of registration mechanism so
735
- // // that functions can declare that they know how to generate
736
- // // diagnostics, i.e. ggplot2::aes() would skip diagnostics
737
-
738
- // // special case to deal with library() and require() nse
739
- // "library" => recurse_call_arguments_custom(
740
- // node,
741
- // context,
742
- // diagnostics,
743
- // "library",
744
- // ".ps.diagnostics.custom.library",
745
- // )?,
746
- // "require" => recurse_call_arguments_custom(
747
- // node,
748
- // context,
749
- // diagnostics,
750
- // "require",
751
- // ".ps.diagnostics.custom.require",
752
- // )?,
725
+ // TODO: there should be some sort of registration mechanism so
726
+ // that functions can declare that they know how to generate
727
+ // diagnostics, i.e. ggplot2::aes() would skip diagnostics
728
+
729
+ // special case to deal with library() and require() nse
730
+ "library" => recurse_call_arguments_custom (
731
+ node,
732
+ context,
733
+ diagnostics,
734
+ "library" ,
735
+ ".ps.diagnostics.custom.library" ,
736
+ ) ?,
737
+ "require" => recurse_call_arguments_custom (
738
+ node,
739
+ context,
740
+ diagnostics,
741
+ "require" ,
742
+ ".ps.diagnostics.custom.require" ,
743
+ ) ?,
753
744
754
745
// default case: recurse into each argument
755
746
_ => recurse_call_arguments_default ( node, context, diagnostics) ?,
0 commit comments