@@ -28,106 +28,60 @@ use crate::utils::r_stringify;
28
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
31
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
-
45
- pub struct RFunction {
32
+ pub struct RCall {
46
33
package : String ,
47
34
function : String ,
48
35
arguments : Vec < RArgument > ,
49
36
}
50
37
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
- }
55
-
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
62
- }
63
-
64
- fn add ( & mut self , value : Option < T > ) -> & mut Self {
65
- if let Some ( value) = value {
66
- self . _add ( "" , value. into ( ) ) ;
67
- }
68
- self
69
- }
70
- }
71
-
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
- }
77
-
78
- fn add ( & mut self , value : T ) -> & mut Self {
79
- let value: RObject = value. into ( ) ;
80
- return self . _add ( "" , value) ;
81
- }
82
- }
83
-
84
- impl RFunction {
38
+ impl RCall {
85
39
pub fn new ( package : & str , function : & str ) -> Self {
86
- RFunction {
40
+ Self {
87
41
package : package. to_string ( ) ,
88
42
function : function. to_string ( ) ,
89
43
arguments : Vec :: new ( ) ,
90
44
}
91
45
}
92
46
93
- fn _add ( & mut self , name : & str , value : RObject ) -> & mut Self {
47
+ pub fn param ( & mut self , name : & str , value : impl Into < RObject > ) -> & mut Self {
94
48
self . arguments . push ( RArgument {
95
49
name : name. to_string ( ) ,
96
- value,
50
+ value : value . into ( ) ,
97
51
} ) ;
98
52
self
99
53
}
100
54
101
- pub fn call ( & mut self ) -> Result < RObject > {
102
- let env = if self . package . is_empty ( ) {
103
- R_ENVS . global
104
- } else {
105
- R_ENVS . base
106
- } ;
107
-
108
- self . call_in ( env)
55
+ pub fn add ( & mut self , value : impl Into < RObject > ) -> & mut Self {
56
+ self . param ( "" , value)
109
57
}
110
58
111
- pub fn call_in ( & mut self , env : SEXP ) -> Result < RObject > {
59
+ pub fn build ( & self ) -> RObject {
112
60
unsafe {
113
61
let mut protect = RProtect :: new ( ) ;
114
62
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
63
+ let fun = if self . package . is_empty ( ) {
64
+ r_symbol ! ( self . function)
65
+ } else {
66
+ Rf_lang3 (
67
+ r_symbol ! ( "::" ) ,
68
+ r_symbol ! ( self . package) ,
69
+ r_symbol ! ( self . function) ,
70
+ )
71
+ } ;
72
+ protect. add ( fun) ;
73
+
74
+ // Now, build the actual call to be evaluated
122
75
let size = ( 1 + self . arguments . len ( ) ) as R_xlen_t ;
123
76
let call = protect. add ( Rf_allocVector ( LANGSXP , size) ) ;
124
77
SET_TAG ( call, R_NilValue ) ;
125
- SETCAR ( call, lhs ) ;
78
+ SETCAR ( call, fun ) ;
126
79
127
- // append arguments to the call
80
+ // Append arguments to the call
128
81
let mut slot = CDR ( call) ;
129
82
for argument in self . arguments . iter ( ) {
130
- // quote language objects by default
83
+ // Quote language objects by default
84
+ // FIXME: Shouldn't this be done by the caller?
131
85
let mut sexp = argument. value . sexp ;
132
86
if matches ! ( r_typeof( sexp) , LANGSXP | SYMSXP | EXPRSXP ) {
133
87
let quote = protect. add ( Rf_lang3 (
@@ -146,6 +100,29 @@ impl RFunction {
146
100
slot = CDR ( slot) ;
147
101
}
148
102
103
+ RObject :: new ( call)
104
+ }
105
+ }
106
+
107
+ pub fn call ( & mut self ) -> Result < RObject > {
108
+ // FIXME: Once we have ArkFunction (see
109
+ // https://github.com/posit-dev/positron/issues/2324), we no longer need
110
+ // this logic to call in global. This probably shouldn't be the default?
111
+ let env = if self . package . is_empty ( ) {
112
+ R_ENVS . global
113
+ } else {
114
+ R_ENVS . base
115
+ } ;
116
+
117
+ self . call_in ( env)
118
+ }
119
+
120
+ pub fn call_in ( & mut self , env : SEXP ) -> Result < RObject > {
121
+ unsafe {
122
+ let call = self . build ( ) ;
123
+
124
+ let mut protect = RProtect :: new ( ) ;
125
+
149
126
// now, wrap call in tryCatch, so that errors don't longjmp
150
127
let try_catch = protect. add ( Rf_lang3 (
151
128
r_symbol ! ( "::" ) ,
@@ -154,7 +131,7 @@ impl RFunction {
154
131
) ) ;
155
132
let call = protect. add ( Rf_lang4 (
156
133
try_catch,
157
- call,
134
+ call. sexp ,
158
135
r_symbol ! ( "identity" ) ,
159
136
r_symbol ! ( "identity" ) ,
160
137
) ) ;
@@ -175,6 +152,43 @@ impl RFunction {
175
152
}
176
153
}
177
154
155
+ pub struct RArgument {
156
+ pub name : String ,
157
+ pub value : RObject ,
158
+ }
159
+
160
+ impl RArgument {
161
+ pub fn new ( name : & str , value : RObject ) -> Self {
162
+ Self {
163
+ name : name. to_string ( ) ,
164
+ value,
165
+ }
166
+ }
167
+ }
168
+
169
+ pub struct RFunction {
170
+ call : RCall ,
171
+ }
172
+
173
+ // TODO: Should be replaced by RCall. Then RFunction could become an enum
174
+ // representation of LANGSXP's CAR (with symbolic and inline variants?),
175
+ // consistently with RArgument being a representation of a LISTSXP's CAR/TAG.
176
+ impl RFunction {
177
+ pub fn new ( package : & str , function : & str ) -> Self {
178
+ RFunction {
179
+ call : RCall :: new ( package, function) ,
180
+ }
181
+ }
182
+
183
+ pub fn call_in ( & mut self , env : SEXP ) -> Result < RObject > {
184
+ self . call . call_in ( env)
185
+ }
186
+
187
+ pub fn call ( & mut self ) -> Result < RObject > {
188
+ self . call . call ( )
189
+ }
190
+ }
191
+
178
192
impl From < & str > for RFunction {
179
193
fn from ( function : & str ) -> Self {
180
194
RFunction :: new ( "" , function)
@@ -187,6 +201,41 @@ impl From<String> for RFunction {
187
201
}
188
202
}
189
203
204
+ // NOTE: Having to import this trait cause a bit of friction during
205
+ // development. Can we do without?
206
+ pub trait RFunctionExt < T > {
207
+ fn param ( & mut self , name : & str , value : T ) -> & mut Self ;
208
+ fn add ( & mut self , value : T ) -> & mut Self ;
209
+ }
210
+
211
+ impl < T : Into < RObject > > RFunctionExt < Option < T > > for RFunction {
212
+ fn param ( & mut self , name : & str , value : Option < T > ) -> & mut Self {
213
+ if let Some ( value) = value {
214
+ self . call . param ( name, value. into ( ) ) ;
215
+ }
216
+ self
217
+ }
218
+
219
+ fn add ( & mut self , value : Option < T > ) -> & mut Self {
220
+ if let Some ( value) = value {
221
+ self . call . add ( value. into ( ) ) ;
222
+ }
223
+ self
224
+ }
225
+ }
226
+
227
+ impl < T : Into < RObject > > RFunctionExt < T > for RFunction {
228
+ fn param ( & mut self , name : & str , value : T ) -> & mut Self {
229
+ self . call . param ( name, value) ;
230
+ self
231
+ }
232
+
233
+ fn add ( & mut self , value : T ) -> & mut Self {
234
+ self . call . add ( value) ;
235
+ self
236
+ }
237
+ }
238
+
190
239
pub fn geterrmessage ( ) -> String {
191
240
// SAFETY: Returns pointer to static memory buffer owned by R.
192
241
let buffer = unsafe { R_curErrorBuf ( ) } ;
0 commit comments