Skip to content

Commit f895364

Browse files
committed
Move namespaced symbol construction to RFunction ctors
1 parent 4f29b30 commit f895364

File tree

2 files changed

+62
-60
lines changed

2 files changed

+62
-60
lines changed

crates/ark/tests/help.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,12 @@ fn test_help_comm() {
8282
assert_eq!(handled, false);
8383

8484
// Figure out which port the R help server is running on (or would run on)
85-
let r_help_port =
86-
r_task(|| unsafe { RFunction::new("tools", "httpdPort").call()?.to::<u16>() }).unwrap();
85+
let r_help_port = r_task(|| unsafe {
86+
RFunction::new_internal("tools", "httpdPort")
87+
.call()?
88+
.to::<u16>()
89+
})
90+
.unwrap();
8791

8892
// Send a request to show a help URL with a valid help URL. This one should
8993
// be handled.

crates/harp/src/exec.rs

Lines changed: 56 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,14 @@ use crate::vector::CharacterVector;
3030
use crate::vector::Vector;
3131

3232
pub struct RCall {
33-
package: String,
34-
function: String,
33+
function: RObject,
3534
arguments: Vec<RArgument>,
3635
}
3736

3837
impl RCall {
39-
pub fn new(package: &str, function: &str) -> Self {
38+
pub fn new(function: impl Into<RObject>) -> Self {
4039
Self {
41-
package: package.to_string(),
42-
function: function.to_string(),
40+
function: function.into(),
4341
arguments: Vec::new(),
4442
}
4543
}
@@ -60,22 +58,11 @@ impl RCall {
6058
unsafe {
6159
let mut protect = RProtect::new();
6260

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-
7461
// Now, build the actual call to be evaluated
7562
let size = (1 + self.arguments.len()) as R_xlen_t;
7663
let call = protect.add(Rf_allocVector(LANGSXP, size));
7764
SET_TAG(call, R_NilValue);
78-
SETCAR(call, fun);
65+
SETCAR(call, self.function.sexp);
7966

8067
// Append arguments to the call
8168
let mut slot = CDR(call);
@@ -103,23 +90,71 @@ impl RCall {
10390
RObject::new(call)
10491
}
10592
}
93+
}
94+
95+
pub struct RArgument {
96+
pub name: String,
97+
pub value: RObject,
98+
}
99+
100+
impl RArgument {
101+
pub fn new(name: &str, value: RObject) -> Self {
102+
Self {
103+
name: name.to_string(),
104+
value,
105+
}
106+
}
107+
}
108+
109+
pub struct RFunction {
110+
pub call: RCall,
111+
is_namespaced: bool,
112+
}
113+
114+
impl RFunction {
115+
pub fn new(package: &str, function: &str) -> Self {
116+
Self::new_ext(package, function, false)
117+
}
118+
119+
pub fn new_internal(package: &str, function: &str) -> Self {
120+
Self::new_ext(package, function, true)
121+
}
122+
123+
fn new_ext(package: &str, function: &str, internal: bool) -> Self {
124+
unsafe {
125+
let is_namespaced = !package.is_empty();
126+
127+
let fun = if is_namespaced {
128+
let op = if internal { ":::" } else { "::" };
129+
Rf_lang3(r_symbol!(op), r_symbol!(package), r_symbol!(function))
130+
} else {
131+
r_symbol!(function)
132+
};
133+
let fun = RObject::new(fun);
134+
135+
RFunction {
136+
call: RCall::new(fun),
137+
is_namespaced,
138+
}
139+
}
140+
}
106141

107142
pub fn call(&mut self) -> Result<RObject> {
108143
// FIXME: Once we have ArkFunction (see
109144
// https://github.com/posit-dev/positron/issues/2324), we no longer need
110145
// 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 {
146+
let env = if self.is_namespaced {
114147
R_ENVS.base
148+
} else {
149+
R_ENVS.global
115150
};
116151

117152
self.call_in(env)
118153
}
119154

120155
pub fn call_in(&mut self, env: SEXP) -> Result<RObject> {
121156
unsafe {
122-
let call = self.build();
157+
let call = self.call.build();
123158

124159
let mut protect = RProtect::new();
125160

@@ -152,43 +187,6 @@ impl RCall {
152187
}
153188
}
154189

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-
192190
impl From<&str> for RFunction {
193191
fn from(function: &str) -> Self {
194192
RFunction::new("", function)

0 commit comments

Comments
 (0)