@@ -12,6 +12,7 @@ use std::os::raw::c_void;
12
12
13
13
use libr:: * ;
14
14
15
+ use crate :: call:: RCall ;
15
16
use crate :: environment:: R_ENVS ;
16
17
use crate :: error:: Error ;
17
18
use crate :: error:: Result ;
@@ -25,126 +26,67 @@ use crate::r_string;
25
26
use crate :: r_symbol;
26
27
use crate :: utils:: r_inherits;
27
28
use crate :: utils:: r_stringify;
28
- use crate :: utils:: r_typeof;
29
29
use crate :: vector:: CharacterVector ;
30
30
use crate :: vector:: Vector ;
31
- pub struct RArgument {
32
- pub name : String ,
33
- pub value : RObject ,
34
- }
35
-
36
- impl RArgument {
37
- pub fn new ( name : & str , value : RObject ) -> Self {
38
- Self {
39
- name : name. to_string ( ) ,
40
- value,
41
- }
42
- }
43
- }
44
31
45
32
pub struct RFunction {
46
- package : String ,
47
- function : String ,
48
- arguments : Vec < RArgument > ,
33
+ pub call : RCall ,
34
+ is_namespaced : bool ,
49
35
}
50
36
51
- pub trait RFunctionExt < T > {
52
- fn param ( & mut self , name : & str , value : T ) -> & mut Self ;
53
- fn add ( & mut self , value : T ) -> & mut Self ;
54
- }
37
+ impl RFunction {
38
+ pub fn new ( package : & str , function : & str ) -> Self {
39
+ Self :: new_ext ( package , function , false )
40
+ }
55
41
56
- impl < T : Into < RObject > > RFunctionExt < Option < T > > for RFunction {
57
- fn param ( & mut self , name : & str , value : Option < T > ) -> & mut Self {
58
- if let Some ( value) = value {
59
- self . _add ( name, value. into ( ) ) ;
60
- }
61
- self
42
+ pub fn new_internal ( package : & str , function : & str ) -> Self {
43
+ Self :: new_ext ( package, function, true )
62
44
}
63
45
64
- fn add ( & mut self , value : Option < T > ) -> & mut Self {
65
- if let Some ( value) = value {
66
- self . _add ( "" , value. into ( ) ) ;
46
+ pub fn new_inlined ( function : impl Into < RObject > ) -> Self {
47
+ RFunction {
48
+ call : RCall :: new ( function) ,
49
+ is_namespaced : false ,
67
50
}
68
- self
69
51
}
70
- }
71
52
72
- impl < T : Into < RObject > > RFunctionExt < T > for RFunction {
73
- fn param ( & mut self , name : & str , value : T ) -> & mut Self {
74
- let value: RObject = value. into ( ) ;
75
- return self . _add ( name, value) ;
76
- }
53
+ fn new_ext ( package : & str , function : & str , internal : bool ) -> Self {
54
+ unsafe {
55
+ let is_namespaced = !package. is_empty ( ) ;
77
56
78
- fn add ( & mut self , value : T ) -> & mut Self {
79
- let value: RObject = value. into ( ) ;
80
- return self . _add ( "" , value) ;
81
- }
82
- }
57
+ let fun = if is_namespaced {
58
+ let op = if internal { ":::" } else { "::" } ;
59
+ Rf_lang3 ( r_symbol ! ( op) , r_symbol ! ( package) , r_symbol ! ( function) )
60
+ } else {
61
+ r_symbol ! ( function)
62
+ } ;
63
+ let fun = RObject :: new ( fun) ;
83
64
84
- impl RFunction {
85
- pub fn new ( package : & str , function : & str ) -> Self {
86
- RFunction {
87
- package : package. to_string ( ) ,
88
- function : function. to_string ( ) ,
89
- arguments : Vec :: new ( ) ,
65
+ RFunction {
66
+ call : RCall :: new ( fun) ,
67
+ is_namespaced,
68
+ }
90
69
}
91
70
}
92
71
93
- fn _add ( & mut self , name : & str , value : RObject ) -> & mut Self {
94
- self . arguments . push ( RArgument {
95
- name : name. to_string ( ) ,
96
- value,
97
- } ) ;
98
- self
99
- }
100
-
101
72
pub fn call ( & mut self ) -> Result < RObject > {
102
- let env = if self . package . is_empty ( ) {
103
- R_ENVS . global
104
- } else {
73
+ // FIXME: Once we have ArkFunction (see
74
+ // https://github.com/posit-dev/positron/issues/2324), we no longer need
75
+ // this logic to call in global. This probably shouldn't be the default?
76
+ let env = if self . is_namespaced {
105
77
R_ENVS . base
78
+ } else {
79
+ R_ENVS . global
106
80
} ;
107
81
108
82
self . call_in ( env)
109
83
}
110
84
111
85
pub fn call_in ( & mut self , env : SEXP ) -> Result < RObject > {
112
86
unsafe {
113
- let mut protect = RProtect :: new ( ) ;
114
-
115
- // start building the call to be evaluated
116
- let mut lhs = r_symbol ! ( self . function) ;
117
- if !self . package . is_empty ( ) {
118
- lhs = protect. add ( Rf_lang3 ( r_symbol ! ( ":::" ) , r_symbol ! ( self . package) , lhs) ) ;
119
- }
120
-
121
- // now, build the actual call to be evaluated
122
- let size = ( 1 + self . arguments . len ( ) ) as R_xlen_t ;
123
- let call = protect. add ( Rf_allocVector ( LANGSXP , size) ) ;
124
- SET_TAG ( call, R_NilValue ) ;
125
- SETCAR ( call, lhs) ;
126
-
127
- // append arguments to the call
128
- let mut slot = CDR ( call) ;
129
- for argument in self . arguments . iter ( ) {
130
- // quote language objects by default
131
- let mut sexp = argument. value . sexp ;
132
- if matches ! ( r_typeof( sexp) , LANGSXP | SYMSXP | EXPRSXP ) {
133
- let quote = protect. add ( Rf_lang3 (
134
- r_symbol ! ( "::" ) ,
135
- r_symbol ! ( "base" ) ,
136
- r_symbol ! ( "quote" ) ,
137
- ) ) ;
138
- sexp = protect. add ( Rf_lang2 ( quote, sexp) ) ;
139
- }
87
+ let call = self . call . build ( ) ;
140
88
141
- SETCAR ( slot, sexp) ;
142
- if !argument. name . is_empty ( ) {
143
- SET_TAG ( slot, r_symbol ! ( argument. name) ) ;
144
- }
145
-
146
- slot = CDR ( slot) ;
147
- }
89
+ let mut protect = RProtect :: new ( ) ;
148
90
149
91
// now, wrap call in tryCatch, so that errors don't longjmp
150
92
let try_catch = protect. add ( Rf_lang3 (
@@ -154,7 +96,7 @@ impl RFunction {
154
96
) ) ;
155
97
let call = protect. add ( Rf_lang4 (
156
98
try_catch,
157
- call,
99
+ call. sexp ,
158
100
r_symbol ! ( "identity" ) ,
159
101
r_symbol ! ( "identity" ) ,
160
102
) ) ;
@@ -187,6 +129,41 @@ impl From<String> for RFunction {
187
129
}
188
130
}
189
131
132
+ // NOTE: Having to import this trait cause a bit of friction during
133
+ // development. Can we do without?
134
+ pub trait RFunctionExt < T > {
135
+ fn param ( & mut self , name : & str , value : T ) -> & mut Self ;
136
+ fn add ( & mut self , value : T ) -> & mut Self ;
137
+ }
138
+
139
+ impl < T : Into < RObject > > RFunctionExt < Option < T > > for RFunction {
140
+ fn param ( & mut self , name : & str , value : Option < T > ) -> & mut Self {
141
+ if let Some ( value) = value {
142
+ self . call . param ( name, value. into ( ) ) ;
143
+ }
144
+ self
145
+ }
146
+
147
+ fn add ( & mut self , value : Option < T > ) -> & mut Self {
148
+ if let Some ( value) = value {
149
+ self . call . add ( value. into ( ) ) ;
150
+ }
151
+ self
152
+ }
153
+ }
154
+
155
+ impl < T : Into < RObject > > RFunctionExt < T > for RFunction {
156
+ fn param ( & mut self , name : & str , value : T ) -> & mut Self {
157
+ self . call . param ( name, value) ;
158
+ self
159
+ }
160
+
161
+ fn add ( & mut self , value : T ) -> & mut Self {
162
+ self . call . add ( value) ;
163
+ self
164
+ }
165
+ }
166
+
190
167
pub fn geterrmessage ( ) -> String {
191
168
// SAFETY: Returns pointer to static memory buffer owned by R.
192
169
let buffer = unsafe { R_curErrorBuf ( ) } ;
@@ -495,6 +472,9 @@ pub fn r_source_exprs_in(exprs: impl Into<SEXP>, env: impl Into<SEXP>) -> crate:
495
472
let exprs = exprs. into ( ) ;
496
473
let env = env. into ( ) ;
497
474
475
+ // `exprs` is an EXPRSXP and doesn't need to be quoted when passed as
476
+ // literal argument. Only the R-level `eval()` function evaluates expression
477
+ // vectors.
498
478
RFunction :: new ( "base" , "source" )
499
479
. param ( "exprs" , exprs)
500
480
. param ( "local" , env)
@@ -681,6 +661,7 @@ mod tests {
681
661
use crate :: r_test;
682
662
use crate :: utils:: r_envir_remove;
683
663
use crate :: utils:: r_is_null;
664
+ use crate :: utils:: r_typeof;
684
665
685
666
#[ test]
686
667
fn test_basic_function ( ) {
0 commit comments