mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
Arrays and Aggregates
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
committed by
Anand Krishnamoorthi
parent
351483d100
commit
d84096024d
122
src/builtins/aggregates.rs
Normal file
122
src/builtins/aggregates.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use crate::ast::Expr;
|
||||
use crate::builtins::utils::{ensure_args_count, ensure_numeric};
|
||||
use crate::lexer::Span;
|
||||
use crate::value::{Float, Value};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
pub fn count(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
|
||||
ensure_args_count(span, "count", params, args, 1)?;
|
||||
|
||||
Ok(Value::from_float(match &args[0] {
|
||||
Value::Array(a) => a.len() as Float,
|
||||
Value::Set(a) => a.len() as Float,
|
||||
Value::Object(a) => a.len() as Float,
|
||||
Value::String(a) => a.len() as Float,
|
||||
a => {
|
||||
let span = params[0].span();
|
||||
bail!(span.error(
|
||||
format!("`count` requires array/object/set/string argument. Got `{a}`.").as_str()
|
||||
))
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn max(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
|
||||
ensure_args_count(span, "max", params, args, 1)?;
|
||||
|
||||
Ok(match &args[0] {
|
||||
Value::Array(a) if a.is_empty() => Value::Undefined,
|
||||
Value::Array(a) => a.iter().max().unwrap().clone(),
|
||||
Value::Set(a) if a.is_empty() => Value::Undefined,
|
||||
Value::Set(a) => a.iter().max().unwrap().clone(),
|
||||
a => {
|
||||
let span = params[0].span();
|
||||
bail!(span.error(format!("`max` requires array/set argument. Got `{a}`.").as_str()))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn min(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
|
||||
ensure_args_count(span, "min", params, args, 1)?;
|
||||
|
||||
Ok(match &args[0] {
|
||||
Value::Array(a) if a.is_empty() => Value::Undefined,
|
||||
Value::Array(a) => a.iter().max().unwrap().clone(),
|
||||
Value::Set(a) if a.is_empty() => Value::Undefined,
|
||||
Value::Set(a) => a.iter().max().unwrap().clone(),
|
||||
a => {
|
||||
let span = params[0].span();
|
||||
bail!(span.error(format!("`min` requires array/set argument. Got `{a}`.").as_str()))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn product(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
|
||||
ensure_args_count(span, "min", params, args, 1)?;
|
||||
|
||||
let mut v = 1 as Float;
|
||||
Ok(match &args[0] {
|
||||
Value::Array(a) => {
|
||||
for e in a.iter() {
|
||||
v *= ensure_numeric("product", ¶ms[0], e)?;
|
||||
}
|
||||
Value::from_float(v)
|
||||
}
|
||||
|
||||
Value::Set(a) => {
|
||||
for e in a.iter() {
|
||||
v *= ensure_numeric("product", ¶ms[0], e)?;
|
||||
}
|
||||
Value::from_float(v)
|
||||
}
|
||||
a => {
|
||||
let span = params[0].span();
|
||||
bail!(span.error(format!("`product` requires array/set argument. Got `{a}`.").as_str()))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn sort(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
|
||||
ensure_args_count(span, "sort", params, args, 1)?;
|
||||
Ok(match &args[0] {
|
||||
Value::Array(a) => {
|
||||
let mut ac = (**a).clone();
|
||||
ac.sort();
|
||||
Value::from_array(ac)
|
||||
}
|
||||
Value::Set(a) => Value::from_set(a.iter().cloned().collect()),
|
||||
a => {
|
||||
let span = params[0].span();
|
||||
bail!(span.error(format!("`sort` requires array/set argument. Got `{a}`.").as_str()))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn sum(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
|
||||
ensure_args_count(span, "sum", params, args, 1)?;
|
||||
|
||||
let mut v = 0 as Float;
|
||||
Ok(match &args[0] {
|
||||
Value::Array(a) => {
|
||||
for e in a.iter() {
|
||||
v += ensure_numeric("sum", ¶ms[0], e)?;
|
||||
}
|
||||
Value::from_float(v)
|
||||
}
|
||||
|
||||
Value::Set(a) => {
|
||||
for e in a.iter() {
|
||||
v += ensure_numeric("sum", ¶ms[0], e)?;
|
||||
}
|
||||
Value::from_float(v)
|
||||
}
|
||||
a => {
|
||||
let span = params[0].span();
|
||||
bail!(span.error(format!("`sum` requires array/set argument. Got `{a}`.").as_str()))
|
||||
}
|
||||
})
|
||||
}
|
||||
33
src/builtins/arrays.rs
Normal file
33
src/builtins/arrays.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use crate::ast::Expr;
|
||||
use crate::builtins::utils::{ensure_args_count, ensure_array};
|
||||
use crate::lexer::Span;
|
||||
use crate::value::Value;
|
||||
|
||||
use anyhow::Result;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn concat(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
|
||||
let name = "array.concat";
|
||||
ensure_args_count(span, name, params, args, 2)?;
|
||||
let mut v1 = ensure_array(name, ¶ms[0], args[0].clone())?;
|
||||
let mut v2 = ensure_array(name, ¶ms[1], args[1].clone())?;
|
||||
|
||||
Rc::make_mut(&mut v1).append(Rc::make_mut(&mut v2));
|
||||
Ok(Value::Array(v1))
|
||||
}
|
||||
|
||||
pub fn reverse(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
|
||||
let name = "array.reverse";
|
||||
ensure_args_count(span, name, params, args, 2)?;
|
||||
|
||||
let mut v1 = ensure_array(name, ¶ms[0], args[0].clone())?;
|
||||
Rc::make_mut(&mut v1).reverse();
|
||||
Ok(Value::Array(v1))
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn slice(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
|
||||
*/
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
pub mod aggregates;
|
||||
pub mod arrays;
|
||||
pub mod comparison;
|
||||
pub mod numbers;
|
||||
pub mod sets;
|
||||
@@ -28,12 +30,24 @@ lazy_static! {
|
||||
m.insert("floor", numbers::floor);
|
||||
m.insert("numbers.range", numbers::range);
|
||||
m.insert("rand.intn", numbers::intn);
|
||||
m.insert("round", numbers::round);
|
||||
m.insert("round", numbers::round);
|
||||
|
||||
// aggregates
|
||||
m.insert("count", aggregates::count);
|
||||
m.insert("max", aggregates::max);
|
||||
m.insert("min", aggregates::min);
|
||||
m.insert("product", aggregates::product);
|
||||
m.insert("sort", aggregates::sort);
|
||||
m.insert("sum", aggregates::sum);
|
||||
|
||||
// arrays
|
||||
m.insert("array.concat", arrays::concat);
|
||||
m.insert("array.reverse", arrays::reverse);
|
||||
|
||||
// sets
|
||||
m.insert("intersection", sets::intersection_of_set_of_sets);
|
||||
m.insert("union", sets::union_of_set_of_sets);
|
||||
|
||||
|
||||
m
|
||||
};
|
||||
}
|
||||
|
||||
@@ -53,6 +53,16 @@ pub fn ensure_string(fcn: &str, arg: &Expr, v: &Value) -> Result<String> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ensure_array(fcn: &str, arg: &Expr, v: Value) -> Result<Rc<Vec<Value>>> {
|
||||
Ok(match v {
|
||||
Value::Array(a) => a,
|
||||
_ => {
|
||||
let span = arg.span();
|
||||
bail!(span.error(format!("`{fcn}` expects array argument. Got `{v}` instead").as_str()))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ensure_set(fcn: &str, arg: &Expr, v: Value) -> Result<Rc<BTreeSet<Value>>> {
|
||||
Ok(match v {
|
||||
Value::Set(s) => s,
|
||||
|
||||
Reference in New Issue
Block a user