1use crate::interpreter::value::*;
7use indexmap::IndexMap;
8use minir_macros::builtin;
9
10#[builtin(min_args = 1, names = ["as.double"])]
17fn builtin_as_numeric(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
18 match args.first() {
19 Some(RValue::Vector(v)) => Ok(RValue::vec(Vector::Double(v.to_doubles().into()))),
20 Some(RValue::Null) => Ok(RValue::vec(Vector::Double(vec![].into()))),
21 _ => Ok(RValue::vec(Vector::Double(vec![None].into()))),
22 }
23}
24
25#[builtin(min_args = 1)]
32fn builtin_as_integer(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
33 match args.first() {
34 Some(RValue::Vector(v)) => Ok(RValue::vec(Vector::Integer(v.to_integers().into()))),
35 Some(RValue::Null) => Ok(RValue::vec(Vector::Integer(vec![].into()))),
36 _ => Ok(RValue::vec(Vector::Integer(vec![None].into()))),
37 }
38}
39
40#[builtin(min_args = 1)]
48fn builtin_as_character(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
49 match args.first() {
50 Some(RValue::Vector(v)) => {
51 if is_factor(v) {
53 return factor_to_character(v);
54 }
55 Ok(RValue::vec(Vector::Character(v.to_characters().into())))
56 }
57 Some(RValue::Null) => Ok(RValue::vec(Vector::Character(vec![].into()))),
58 _ => Ok(RValue::vec(Vector::Character(vec![None].into()))),
59 }
60}
61
62fn is_factor(v: &RVector) -> bool {
64 if let Some(RValue::Vector(cls_vec)) = v.get_attr("class") {
65 if let Vector::Character(cls) = &cls_vec.inner {
66 return cls.iter().any(|c| c.as_deref() == Some("factor"));
67 }
68 }
69 false
70}
71
72fn factor_to_character(v: &RVector) -> Result<RValue, RError> {
74 let levels: Vec<Option<String>> = match v.get_attr("levels") {
75 Some(RValue::Vector(lv)) => match &lv.inner {
76 Vector::Character(c) => c.to_vec(),
77 _ => vec![],
78 },
79 _ => vec![],
80 };
81
82 let codes = v.inner.to_integers();
83 let labels: Vec<Option<String>> = codes
84 .iter()
85 .map(|code| {
86 code.and_then(|i| {
87 let idx = usize::try_from(i).ok()?.checked_sub(1)?;
88 levels.get(idx).cloned().flatten()
89 })
90 })
91 .collect();
92
93 Ok(RValue::vec(Vector::Character(labels.into())))
94}
95
96#[builtin(min_args = 1)]
101fn builtin_as_logical(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
102 match args.first() {
103 Some(RValue::Vector(v)) => Ok(RValue::vec(Vector::Logical(v.to_logicals().into()))),
104 Some(RValue::Null) => Ok(RValue::vec(Vector::Logical(vec![].into()))),
105 _ => Ok(RValue::vec(Vector::Logical(vec![None].into()))),
106 }
107}
108
109#[builtin(min_args = 1)]
116fn builtin_as_list(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
117 match args.first() {
118 Some(RValue::List(l)) => Ok(RValue::List(l.clone())),
119 Some(RValue::Vector(v)) => {
120 let values: Vec<(Option<String>, RValue)> = match &v.inner {
121 Vector::Raw(vals) => vals
122 .iter()
123 .map(|&x| (None, RValue::vec(Vector::Raw(vec![x]))))
124 .collect(),
125 Vector::Double(vals) => vals
126 .iter_opt()
127 .map(|x| (None, RValue::vec(Vector::Double(vec![x].into()))))
128 .collect(),
129 Vector::Integer(vals) => vals
130 .iter_opt()
131 .map(|x| (None, RValue::vec(Vector::Integer(vec![x].into()))))
132 .collect(),
133 Vector::Logical(vals) => vals
134 .iter()
135 .map(|x| (None, RValue::vec(Vector::Logical(vec![*x].into()))))
136 .collect(),
137 Vector::Complex(vals) => vals
138 .iter()
139 .map(|x| (None, RValue::vec(Vector::Complex(vec![*x].into()))))
140 .collect(),
141 Vector::Character(vals) => vals
142 .iter()
143 .map(|x| (None, RValue::vec(Vector::Character(vec![x.clone()].into()))))
144 .collect(),
145 };
146 Ok(RValue::List(RList::new(values)))
147 }
148 Some(RValue::Null) => Ok(RValue::List(RList::new(vec![]))),
149 _ => Ok(RValue::List(RList::new(vec![]))),
150 }
151}
152
153#[builtin(name = "as.matrix", min_args = 1)]
162fn builtin_as_matrix(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
163 match args.first() {
164 Some(RValue::Vector(v)) => {
165 let len = v.len();
166 let mut rv = v.clone();
167 rv.set_attr(
168 "dim".to_string(),
169 RValue::vec(Vector::Integer(
170 vec![Some(i64::try_from(len)?), Some(1)].into(),
171 )),
172 );
173 Ok(RValue::Vector(rv))
174 }
175 Some(RValue::List(list)) => {
176 let ncol = list.values.len();
178 if ncol == 0 {
179 return Ok(RValue::vec(Vector::Double(vec![].into())));
180 }
181 let nrow = list
182 .values
183 .first()
184 .map(|(_, v)| match v {
185 RValue::Vector(rv) => rv.len(),
186 _ => 1,
187 })
188 .unwrap_or(0);
189
190 let mut data: Vec<Option<f64>> = Vec::with_capacity(nrow * ncol);
191 for (_, val) in &list.values {
192 if let Some(v) = val.as_vector() {
193 let doubles = v.to_doubles();
194 data.extend(&doubles);
195 } else {
196 for _ in 0..nrow {
197 data.push(None);
198 }
199 }
200 }
201 let mut rv = RVector::from(Vector::Double(data.into()));
202 rv.set_attr(
203 "dim".to_string(),
204 RValue::vec(Vector::Integer(
205 vec![Some(i64::try_from(nrow)?), Some(i64::try_from(ncol)?)].into(),
206 )),
207 );
208 let col_names: Vec<Option<String>> =
210 list.values.iter().map(|(n, _)| n.clone()).collect();
211 if col_names.iter().any(|n| n.is_some()) {
212 let dimnames = RValue::List(RList::new(vec![
213 (None, RValue::Null),
214 (None, RValue::vec(Vector::Character(col_names.into()))),
215 ]));
216 rv.set_attr("dimnames".to_string(), dimnames);
217 }
218 Ok(RValue::Vector(rv))
219 }
220 Some(RValue::Null) => Ok(RValue::vec(Vector::Double(vec![].into()))),
221 _ => Ok(RValue::vec(Vector::Double(vec![None].into()))),
222 }
223}
224
225#[builtin(name = "as.data.frame", min_args = 1)]
232fn builtin_as_data_frame(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
233 match args.first() {
234 Some(RValue::List(list)) => {
235 let mut list = list.clone();
237 let mut attrs = *list.attrs.take().unwrap_or_default();
238 attrs.insert(
239 "class".to_string(),
240 RValue::vec(Vector::Character(
241 vec![Some("data.frame".to_string())].into(),
242 )),
243 );
244 if !attrs.contains_key("row.names") {
246 let nrow = list
247 .values
248 .first()
249 .map(|(_, v)| match v {
250 RValue::Vector(rv) => rv.len(),
251 _ => 1,
252 })
253 .unwrap_or(0);
254 attrs.insert(
255 "row.names".to_string(),
256 RValue::vec(Vector::Integer(
257 (1..=nrow as i64).map(Some).collect::<Vec<_>>().into(),
258 )),
259 );
260 }
261 list.attrs = Some(Box::new(attrs));
262 Ok(RValue::List(list))
263 }
264 Some(RValue::Vector(v)) => {
265 let col_name = named
267 .iter()
268 .find(|(n, _)| n == "col.names")
269 .and_then(|(_, v)| v.as_vector()?.as_character_scalar())
270 .unwrap_or_else(|| "V1".to_string());
271 let nrow = v.len();
272 let mut list = RList::new(vec![(Some(col_name.clone()), RValue::Vector(v.clone()))]);
273 let mut attrs: IndexMap<String, RValue> = IndexMap::new();
274 attrs.insert(
275 "class".to_string(),
276 RValue::vec(Vector::Character(
277 vec![Some("data.frame".to_string())].into(),
278 )),
279 );
280 attrs.insert(
281 "names".to_string(),
282 RValue::vec(Vector::Character(vec![Some(col_name)].into())),
283 );
284 attrs.insert(
285 "row.names".to_string(),
286 RValue::vec(Vector::Integer(
287 (1..=nrow as i64).map(Some).collect::<Vec<_>>().into(),
288 )),
289 );
290 list.attrs = Some(Box::new(attrs));
291 Ok(RValue::List(list))
292 }
293 Some(RValue::Null) => {
294 let list = RList::new(vec![]);
295 let mut attrs: IndexMap<String, RValue> = IndexMap::new();
296 attrs.insert(
297 "class".to_string(),
298 RValue::vec(Vector::Character(
299 vec![Some("data.frame".to_string())].into(),
300 )),
301 );
302 attrs.insert(
303 "row.names".to_string(),
304 RValue::vec(Vector::Integer(vec![].into())),
305 );
306 let mut list = list;
307 list.attrs = Some(Box::new(attrs));
308 Ok(RValue::List(list))
309 }
310 _ => Err(RError::new(
311 RErrorKind::Argument,
312 "cannot coerce to data.frame".to_string(),
313 )),
314 }
315}
316
317#[builtin(name = "as.factor", min_args = 1)]
323fn builtin_as_factor(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
324 let chars = match args.first() {
326 Some(RValue::Vector(v)) => {
327 if is_factor(v) {
328 return Ok(RValue::Vector(v.clone()));
329 }
330 v.to_characters()
331 }
332 _ => vec![],
333 };
334
335 let mut levels: Vec<String> = Vec::new();
337 for s in chars.iter().flatten() {
338 if !levels.contains(s) {
339 levels.push(s.clone());
340 }
341 }
342 levels.sort();
343
344 let codes: Vec<Option<i64>> = chars
346 .iter()
347 .map(|c| {
348 c.as_ref()
349 .and_then(|s| levels.iter().position(|l| l == s).map(|i| (i + 1) as i64))
350 })
351 .collect();
352
353 let mut rv = RVector::from(Vector::Integer(codes.into()));
354 rv.set_attr(
355 "levels".to_string(),
356 RValue::vec(Vector::Character(
357 levels.into_iter().map(Some).collect::<Vec<_>>().into(),
358 )),
359 );
360 rv.set_attr(
361 "class".to_string(),
362 RValue::vec(Vector::Character(vec![Some("factor".to_string())].into())),
363 );
364 Ok(RValue::Vector(rv))
365}
366
367#[builtin(name = "as.name", min_args = 1, names = ["as.symbol"])]
373fn builtin_as_name(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
374 let name = match args.first() {
375 Some(RValue::Vector(v)) => v.as_character_scalar().unwrap_or_default(),
376 _ => String::new(),
377 };
378 Ok(RValue::Language(Language::new(
379 crate::parser::ast::Expr::Symbol(name),
380 )))
381}
382
383#[builtin(name = "as.call", min_args = 1)]
392fn builtin_as_call(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
393 use crate::parser::ast::{Arg, Expr};
394 let list = match args.first() {
395 Some(RValue::List(l)) => l,
396 _ => {
397 return Err(RError::new(
398 RErrorKind::Argument,
399 "as.call: argument must be a list".to_string(),
400 ))
401 }
402 };
403 if list.values.is_empty() {
404 return Err(RError::new(
405 RErrorKind::Argument,
406 "as.call: list must have at least one element (the function)".to_string(),
407 ));
408 }
409
410 let (_, func_val) = &list.values[0];
412 let func_expr = rvalue_to_expr(func_val);
413
414 let call_args: Vec<Arg> = list.values[1..]
416 .iter()
417 .map(|(name, val)| Arg {
418 name: name.clone(),
419 value: Some(rvalue_to_expr(val)),
420 })
421 .collect();
422
423 let call = Expr::Call {
424 func: Box::new(func_expr),
425 args: call_args,
426 span: None,
427 };
428 Ok(RValue::Language(Language::new(call)))
429}
430
431fn rvalue_to_expr(val: &RValue) -> crate::parser::ast::Expr {
433 use crate::parser::ast::Expr;
434 match val {
435 RValue::Null => Expr::Null,
436 RValue::Vector(rv) => match &rv.inner {
437 Vector::Logical(l) if l.len() == 1 => match l[0] {
438 Some(true) => Expr::Bool(true),
439 Some(false) => Expr::Bool(false),
440 None => Expr::Na(crate::parser::ast::NaType::Logical),
441 },
442 Vector::Integer(i) if i.len() == 1 => match i.get_opt(0) {
443 Some(v) => Expr::Integer(v),
444 None => Expr::Na(crate::parser::ast::NaType::Integer),
445 },
446 Vector::Double(d) if d.len() == 1 => match d.get_opt(0) {
447 Some(v) => Expr::Double(v),
448 None => Expr::Na(crate::parser::ast::NaType::Real),
449 },
450 Vector::Character(c) if c.len() == 1 => match &c[0] {
451 Some(s) => Expr::String(s.clone()),
452 None => Expr::Na(crate::parser::ast::NaType::Character),
453 },
454 _ => Expr::Null,
455 },
456 RValue::Language(lang) => lang.inner.as_ref().clone(),
457 RValue::Function(_) => Expr::Symbol("<function>".to_string()),
458 _ => Expr::Null,
459 }
460}
461
462#[builtin(name = "as.pairlist", min_args = 1)]
468fn builtin_as_pairlist(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
469 match args.first() {
471 Some(RValue::List(l)) => Ok(RValue::List(l.clone())),
472 Some(RValue::Null) => Ok(RValue::Null),
473 Some(other) => Ok(other.clone()),
474 None => Ok(RValue::Null),
475 }
476}
477
478#[builtin(name = "match.fun", min_args = 1)]
484fn builtin_match_fun(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
485 match args.first() {
486 Some(RValue::Function(_)) => Ok(args[0].clone()),
487 Some(RValue::Vector(v)) => {
488 let name = v.as_character_scalar().ok_or_else(|| {
489 RError::new(
490 RErrorKind::Argument,
491 "'FUN' must be a function or a character string".to_string(),
492 )
493 })?;
494 Err(RError::new(
497 RErrorKind::Other,
498 format!(
499 "match.fun cannot resolve '{}' — pass the function directly",
500 name
501 ),
502 ))
503 }
504 _ => Err(RError::new(
505 RErrorKind::Argument,
506 "'FUN' must be a function or a character string".to_string(),
507 )),
508 }
509}
510
511#[builtin(min_args = 1)]
516fn builtin_as_vector(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
517 match args.first() {
518 Some(RValue::Vector(v)) => {
519 let mut v = v.clone();
520 v.attrs = None;
521 Ok(RValue::Vector(v))
522 }
523 Some(RValue::List(items)) => {
524 let mut items = items.clone();
525 items.attrs = None;
526 Ok(RValue::List(items))
527 }
528 Some(RValue::Null) => Ok(RValue::Null),
529 _ => Ok(args.first().cloned().unwrap_or(RValue::Null)),
530 }
531}