Skip to content

Commit 4f29b30

Browse files
committed
Move RFunction to RCall and extract build() method
1 parent 24746bb commit 4f29b30

File tree

1 file changed

+120
-71
lines changed

1 file changed

+120
-71
lines changed

crates/harp/src/exec.rs

Lines changed: 120 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -28,106 +28,60 @@ use crate::utils::r_stringify;
2828
use crate::utils::r_typeof;
2929
use crate::vector::CharacterVector;
3030
use crate::vector::Vector;
31-
pub struct RArgument {
32-
pub name: String,
33-
pub value: RObject,
34-
}
3531

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 {
4633
package: String,
4734
function: String,
4835
arguments: Vec<RArgument>,
4936
}
5037

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 {
8539
pub fn new(package: &str, function: &str) -> Self {
86-
RFunction {
40+
Self {
8741
package: package.to_string(),
8842
function: function.to_string(),
8943
arguments: Vec::new(),
9044
}
9145
}
9246

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 {
9448
self.arguments.push(RArgument {
9549
name: name.to_string(),
96-
value,
50+
value: value.into(),
9751
});
9852
self
9953
}
10054

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)
10957
}
11058

111-
pub fn call_in(&mut self, env: SEXP) -> Result<RObject> {
59+
pub fn build(&self) -> RObject {
11260
unsafe {
11361
let mut protect = RProtect::new();
11462

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
12275
let size = (1 + self.arguments.len()) as R_xlen_t;
12376
let call = protect.add(Rf_allocVector(LANGSXP, size));
12477
SET_TAG(call, R_NilValue);
125-
SETCAR(call, lhs);
78+
SETCAR(call, fun);
12679

127-
// append arguments to the call
80+
// Append arguments to the call
12881
let mut slot = CDR(call);
12982
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?
13185
let mut sexp = argument.value.sexp;
13286
if matches!(r_typeof(sexp), LANGSXP | SYMSXP | EXPRSXP) {
13387
let quote = protect.add(Rf_lang3(
@@ -146,6 +100,29 @@ impl RFunction {
146100
slot = CDR(slot);
147101
}
148102

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+
149126
// now, wrap call in tryCatch, so that errors don't longjmp
150127
let try_catch = protect.add(Rf_lang3(
151128
r_symbol!("::"),
@@ -154,7 +131,7 @@ impl RFunction {
154131
));
155132
let call = protect.add(Rf_lang4(
156133
try_catch,
157-
call,
134+
call.sexp,
158135
r_symbol!("identity"),
159136
r_symbol!("identity"),
160137
));
@@ -175,6 +152,43 @@ impl RFunction {
175152
}
176153
}
177154

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+
178192
impl From<&str> for RFunction {
179193
fn from(function: &str) -> Self {
180194
RFunction::new("", function)
@@ -187,6 +201,41 @@ impl From<String> for RFunction {
187201
}
188202
}
189203

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+
190239
pub fn geterrmessage() -> String {
191240
// SAFETY: Returns pointer to static memory buffer owned by R.
192241
let buffer = unsafe { R_curErrorBuf() };

0 commit comments

Comments
 (0)