use crate::eval::evaluate_expr;
use crate::eval::functions::{check_arity_len, EvalCtx};
use crate::parser::ast::Expr;
use crate::types::{ErrorKind, Value};
use super::cell_ref::{parse_cell_ref, parse_range_ref};
pub fn row_fn(args: &[Expr], ctx: &mut EvalCtx<'_>) -> Value {
if let Some(err) = check_arity_len(args.len(), 0, 1) {
return err;
}
if args.is_empty() {
return Value::Number(1.0);
}
match &args[0] {
Expr::Variable(name, _) => {
if let Some((_sc, sr, _ec, _er)) = parse_range_ref(name) {
return Value::Number(sr as f64);
}
if let Some((_col, row)) = parse_cell_ref(name) {
return Value::Number(row as f64);
}
let v = evaluate_expr(&args[0], ctx);
match v {
Value::Error(e) => Value::Error(e),
_ => Value::Error(ErrorKind::NA),
}
}
_ => {
let v = evaluate_expr(&args[0], ctx);
match v {
Value::Error(e) => Value::Error(e),
_ => Value::Error(ErrorKind::NA),
}
}
}
}
pub fn column_fn(args: &[Expr], ctx: &mut EvalCtx<'_>) -> Value {
if let Some(err) = check_arity_len(args.len(), 0, 1) {
return err;
}
if args.is_empty() {
return Value::Number(1.0);
}
match &args[0] {
Expr::Variable(name, _) => {
if let Some((sc, _sr, _ec, _er)) = parse_range_ref(name) {
return Value::Number(sc as f64);
}
if let Some((col, _row)) = parse_cell_ref(name) {
return Value::Number(col as f64);
}
let v = evaluate_expr(&args[0], ctx);
match v {
Value::Error(e) => Value::Error(e),
_ => Value::Error(ErrorKind::NA),
}
}
_ => {
let v = evaluate_expr(&args[0], ctx);
match v {
Value::Error(e) => Value::Error(e),
_ => Value::Error(ErrorKind::NA),
}
}
}
}
pub fn rows_fn(args: &[Expr], ctx: &mut EvalCtx<'_>) -> Value {
if let Some(err) = check_arity_len(args.len(), 1, 1) {
return err;
}
match &args[0] {
Expr::Variable(name, _) => {
if let Some((_sc, sr, _ec, er)) = parse_range_ref(name) {
let rows = if er >= sr { er - sr + 1 } else { sr - er + 1 };
return Value::Number(rows as f64);
}
if parse_cell_ref(name).is_some() {
return Value::Number(1.0);
}
let v = evaluate_expr(&args[0], ctx);
count_rows_from_value(&v)
}
_ => {
let v = evaluate_expr(&args[0], ctx);
count_rows_from_value(&v)
}
}
}
pub fn columns_fn(args: &[Expr], ctx: &mut EvalCtx<'_>) -> Value {
if let Some(err) = check_arity_len(args.len(), 1, 1) {
return err;
}
match &args[0] {
Expr::Variable(name, _) => {
if let Some((sc, _sr, ec, _er)) = parse_range_ref(name) {
let cols = if ec >= sc { ec - sc + 1 } else { sc - ec + 1 };
return Value::Number(cols as f64);
}
if parse_cell_ref(name).is_some() {
return Value::Number(1.0);
}
let v = evaluate_expr(&args[0], ctx);
count_cols_from_value(&v)
}
_ => {
let v = evaluate_expr(&args[0], ctx);
count_cols_from_value(&v)
}
}
}
fn count_rows_from_value(v: &Value) -> Value {
match v {
Value::Array(outer) => {
let is_2d = outer.iter().any(|e| matches!(e, Value::Array(_)));
if is_2d {
Value::Number(outer.len() as f64)
} else {
Value::Number(1.0)
}
}
Value::Error(e) => Value::Error(e.clone()),
_ => Value::Number(1.0),
}
}
fn count_cols_from_value(v: &Value) -> Value {
match v {
Value::Array(outer) => {
let is_2d = outer.iter().any(|e| matches!(e, Value::Array(_)));
if is_2d {
match outer.first() {
Some(Value::Array(row)) => Value::Number(row.len() as f64),
_ => Value::Number(1.0),
}
} else {
Value::Number(outer.len() as f64)
}
}
Value::Error(e) => Value::Error(e.clone()),
_ => Value::Number(1.0),
}
}