1use crate::interpreter::value::*;
7use crate::parser::ast::Expr;
8use minir_macros::builtin;
9
10use super::{get_dim_ints, has_class};
11
12#[builtin(min_args = 1)]
17fn builtin_is_null(args: &[RValue], _named: &[(String, RValue)]) -> Result<RValue, RError> {
18 let r = matches!(args.first(), Some(RValue::Null));
19 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
20}
21
22#[builtin(min_args = 1)]
27fn builtin_is_ordered(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
28 let r = args.first().is_some_and(|v| has_class(v, "ordered"));
29 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
30}
31
32#[builtin(min_args = 1)]
41fn builtin_is_call(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
42 let r = matches!(
43 args.first(),
44 Some(RValue::Language(lang)) if !matches!(*lang.inner, Expr::Symbol(_))
45 );
46 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
47}
48
49#[builtin(min_args = 1, names = ["is.name"])]
57fn builtin_is_symbol(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
58 let r = matches!(
59 args.first(),
60 Some(RValue::Language(lang)) if matches!(*lang.inner, Expr::Symbol(_))
61 );
62 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
63}
64
65#[builtin(min_args = 1)]
73fn builtin_is_expression(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
74 let r = args.first().is_some_and(|v| has_class(v, "expression"));
75 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
76}
77
78#[builtin(min_args = 1)]
87fn builtin_is_pairlist(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
88 let r = matches!(args.first(), Some(RValue::Null));
89 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
90}
91
92#[builtin(name = "is.environment", min_args = 1)]
97fn builtin_is_environment(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
98 let r = matches!(args.first(), Some(RValue::Environment(_)));
99 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
100}
101
102#[builtin(name = "is.language", min_args = 1)]
107fn builtin_is_language(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
108 let r = matches!(args.first(), Some(RValue::Language(_)));
109 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
110}
111
112#[builtin(min_args = 1)]
119fn builtin_is_na(args: &[RValue], _named: &[(String, RValue)]) -> Result<RValue, RError> {
120 match args.first() {
121 Some(RValue::Vector(v)) => {
122 let result: Vec<Option<bool>> = match &v.inner {
123 Vector::Raw(vals) => vals.iter().map(|_| Some(false)).collect(),
124 Vector::Logical(vals) => vals.iter().map(|x| Some(x.is_none())).collect(),
125 Vector::Integer(vals) => vals.iter().map(|x| Some(x.is_none())).collect(),
126 Vector::Double(vals) => vals
127 .iter()
128 .map(|x| Some(x.is_none() || x.map(|f| f.is_nan()).unwrap_or(false)))
129 .collect(),
130 Vector::Complex(vals) => vals.iter().map(|x| Some(x.is_none())).collect(),
131 Vector::Character(vals) => vals.iter().map(|x| Some(x.is_none())).collect(),
132 };
133 Ok(RValue::vec(Vector::Logical(result.into())))
134 }
135 _ => Ok(RValue::vec(Vector::Logical(vec![Some(false)].into()))),
136 }
137}
138
139#[builtin(min_args = 1)]
147fn builtin_is_numeric(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
148 let r = match args.first() {
149 Some(val @ RValue::Vector(rv))
150 if matches!(rv.inner, Vector::Double(_) | Vector::Integer(_)) =>
151 {
152 !has_class(val, "factor")
154 }
155 _ => false,
156 };
157 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
158}
159
160#[builtin(min_args = 1)]
165fn builtin_is_character(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
166 let r = matches!(args.first(), Some(RValue::Vector(rv)) if matches!(rv.inner, Vector::Character(_)));
167 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
168}
169
170#[builtin(min_args = 1)]
175fn builtin_is_logical(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
176 let r =
177 matches!(args.first(), Some(RValue::Vector(rv)) if matches!(rv.inner, Vector::Logical(_)));
178 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
179}
180
181#[builtin(min_args = 1)]
186fn builtin_is_integer(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
187 let r =
188 matches!(args.first(), Some(RValue::Vector(rv)) if matches!(rv.inner, Vector::Integer(_)));
189 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
190}
191
192#[builtin(min_args = 1)]
197fn builtin_is_double(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
198 let r =
199 matches!(args.first(), Some(RValue::Vector(rv)) if matches!(rv.inner, Vector::Double(_)));
200 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
201}
202
203#[builtin(min_args = 1)]
208fn builtin_is_function(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
209 let r = matches!(args.first(), Some(RValue::Function(_)));
210 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
211}
212
213#[builtin(min_args = 1)]
220fn builtin_is_primitive(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
221 let r = matches!(
222 args.first(),
223 Some(RValue::Function(RFunction::Builtin { .. }))
224 );
225 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
226}
227
228#[builtin(min_args = 1)]
236fn builtin_is_vector(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
237 let r = match args.first() {
239 Some(RValue::Vector(rv)) => match &rv.attrs {
240 None => true,
241 Some(attrs) => attrs.keys().all(|k| k == "names"),
242 },
243 Some(RValue::List(l)) => match &l.attrs {
244 None => true,
245 Some(attrs) => attrs.keys().all(|k| k == "names"),
246 },
247 _ => false,
248 };
249 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
250}
251
252#[builtin(min_args = 1)]
257fn builtin_is_list(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
258 let r = matches!(args.first(), Some(RValue::List(_)));
259 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
260}
261
262#[builtin(min_args = 1)]
270fn builtin_is_recursive(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
271 let r = match args.first() {
272 Some(RValue::List(_)) | Some(RValue::Environment(_)) => true,
273 Some(RValue::Language(lang)) => !matches!(*lang.inner, Expr::Symbol(_)),
275 _ => false,
276 };
277 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
278}
279
280#[builtin(min_args = 1)]
285fn builtin_is_atomic(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
286 let r = matches!(args.first(), Some(RValue::Vector(_)) | Some(RValue::Null));
288 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
289}
290
291#[builtin(min_args = 1)]
296fn builtin_is_finite(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
297 match args.first() {
298 Some(RValue::Vector(v)) => {
299 let result: Vec<Option<bool>> = match &v.inner {
300 Vector::Double(vals) => vals
301 .iter()
302 .map(|x| Some(x.map(|f| f.is_finite()).unwrap_or(false)))
303 .collect(),
304 Vector::Integer(vals) => vals.iter().map(|x| Some(x.is_some())).collect(),
306 Vector::Logical(vals) => vals.iter().map(|x| Some(x.is_some())).collect(),
307 _ => {
308 return Err(RError::new(
309 RErrorKind::Argument,
310 "default method not implemented for type".to_string(),
311 ))
312 }
313 };
314 Ok(RValue::vec(Vector::Logical(result.into())))
315 }
316 _ => Ok(RValue::vec(Vector::Logical(vec![Some(false)].into()))),
317 }
318}
319
320#[builtin(min_args = 1)]
325fn builtin_is_infinite(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
326 match args.first() {
327 Some(RValue::Vector(v)) => {
328 let result: Vec<Option<bool>> = match &v.inner {
329 Vector::Double(vals) => vals
330 .iter()
331 .map(|x| Some(x.map(|f| f.is_infinite()).unwrap_or(false)))
332 .collect(),
333 Vector::Integer(_) | Vector::Logical(_) => {
335 vec![Some(false); v.inner.len()]
336 }
337 _ => {
338 return Err(RError::new(
339 RErrorKind::Argument,
340 "default method not implemented for type".to_string(),
341 ))
342 }
343 };
344 Ok(RValue::vec(Vector::Logical(result.into())))
345 }
346 _ => Ok(RValue::vec(Vector::Logical(vec![Some(false)].into()))),
347 }
348}
349
350#[builtin(min_args = 1)]
357fn builtin_is_nan(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
358 match args.first() {
359 Some(RValue::Vector(v)) => {
360 let result: Vec<Option<bool>> = match &v.inner {
361 Vector::Double(vals) => vals
362 .iter()
363 .map(|x| Some(x.map(|f| f.is_nan()).unwrap_or(false)))
364 .collect(),
365 Vector::Integer(_) | Vector::Logical(_) => {
367 vec![Some(false); v.inner.len()]
368 }
369 _ => {
370 return Err(RError::new(
371 RErrorKind::Argument,
372 "default method not implemented for type".to_string(),
373 ))
374 }
375 };
376 Ok(RValue::vec(Vector::Logical(result.into())))
377 }
378 _ => Ok(RValue::vec(Vector::Logical(vec![Some(false)].into()))),
379 }
380}
381
382#[builtin(min_args = 1)]
387fn builtin_is_factor(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
388 let r = args.first().is_some_and(|v| has_class(v, "factor"));
389 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
390}
391
392#[builtin(min_args = 1)]
397fn builtin_is_data_frame(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
398 let r = args.first().is_some_and(|v| has_class(v, "data.frame"));
399 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
400}
401
402#[builtin(min_args = 1)]
407fn builtin_is_matrix(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
408 let r = args.first().is_some_and(|v| {
409 if has_class(v, "matrix") {
411 return true;
412 }
413 let dim_attr = match v {
415 RValue::Vector(rv) => rv.get_attr("dim"),
416 RValue::List(l) => l.get_attr("dim"),
417 _ => None,
418 };
419 get_dim_ints(dim_attr).is_some_and(|d| d.len() == 2)
420 });
421 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
422}
423
424#[builtin(min_args = 1)]
432fn builtin_is_array(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
433 let r = args.first().is_some_and(|v| {
434 if has_class(v, "array") || has_class(v, "matrix") {
436 return true;
437 }
438 let dim_attr = match v {
440 RValue::Vector(rv) => rv.get_attr("dim"),
441 RValue::List(l) => l.get_attr("dim"),
442 _ => None,
443 };
444 get_dim_ints(dim_attr).is_some_and(|d| !d.is_empty())
445 });
446 Ok(RValue::vec(Vector::Logical(vec![Some(r)].into())))
447}
448
449#[builtin(min_args = 2)]
458fn builtin_is_element(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
459 if args.len() < 2 {
460 return Err(RError::new(
461 RErrorKind::Argument,
462 "need 2 arguments".to_string(),
463 ));
464 }
465 let (lv, rv) = match (&args[0], &args[1]) {
466 (RValue::Vector(l), RValue::Vector(r)) => (l, r),
467 _ => return Ok(RValue::vec(Vector::Logical(vec![Some(false)].into()))),
468 };
469
470 if matches!(lv.inner, Vector::Character(_)) || matches!(rv.inner, Vector::Character(_)) {
472 let table = rv.to_characters();
473 let vals = lv.to_characters();
474 let result: Vec<Option<bool>> = vals
475 .iter()
476 .map(|xi| {
477 Some(
478 xi.as_ref()
479 .is_some_and(|xi| table.iter().any(|t| t.as_ref() == Some(xi))),
480 )
481 })
482 .collect();
483 return Ok(RValue::vec(Vector::Logical(result.into())));
484 }
485
486 let table = rv.to_doubles();
488 let vals = lv.to_doubles();
489 let result: Vec<Option<bool>> = vals
490 .iter()
491 .map(|x| match x {
492 Some(v) => Some(table.iter().any(|t| match t {
493 Some(t) => (*t == *v) || (t.is_nan() && v.is_nan()),
494 None => false,
495 })),
496 None => Some(table.iter().any(|t| t.is_none())),
497 })
498 .collect();
499 Ok(RValue::vec(Vector::Logical(result.into())))
500}
501
502#[builtin(name = "isTRUE", min_args = 1)]
509fn builtin_is_true(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
510 let result = match args.first() {
511 Some(RValue::Vector(rv)) if matches!(rv.inner, Vector::Logical(_)) => {
512 let Vector::Logical(v) = &rv.inner else {
513 unreachable!()
514 };
515 v.len() == 1 && v[0] == Some(true)
516 }
517 _ => false,
518 };
519 Ok(RValue::vec(Vector::Logical(vec![Some(result)].into())))
520}
521
522#[builtin(name = "isFALSE", min_args = 1)]
529fn builtin_is_false(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
530 let result = match args.first() {
531 Some(RValue::Vector(rv)) if matches!(rv.inner, Vector::Logical(_)) => {
532 let Vector::Logical(v) = &rv.inner else {
533 unreachable!()
534 };
535 v.len() == 1 && v[0] == Some(false)
536 }
537 _ => false,
538 };
539 Ok(RValue::vec(Vector::Logical(vec![Some(result)].into())))
540}