Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
Anand Krishnamoorthi
2023-02-18 17:22:16 -08:00
committed by Anand Krishnamoorthi
parent d84096024d
commit 3549931342
6 changed files with 202 additions and 108 deletions

View File

@@ -2,13 +2,25 @@
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_numeric};
use crate::lexer::Span;
use crate::value::{Float, Value};
use std::collections::HashMap;
use anyhow::{bail, Result};
pub fn count(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("count", count);
m.insert("max", max);
m.insert("min", min);
m.insert("product", product);
m.insert("sort", sort);
m.insert("sum", sum);
}
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] {
@@ -25,7 +37,7 @@ pub fn count(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
}))
}
pub fn max(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn max(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "max", params, args, 1)?;
Ok(match &args[0] {
@@ -40,7 +52,7 @@ pub fn max(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
})
}
pub fn min(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn min(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "min", params, args, 1)?;
Ok(match &args[0] {
@@ -55,7 +67,7 @@ pub fn min(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
})
}
pub fn product(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn product(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "min", params, args, 1)?;
let mut v = 1 as Float;
@@ -80,7 +92,7 @@ pub fn product(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
})
}
pub fn sort(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
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) => {
@@ -96,7 +108,7 @@ pub fn sort(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
})
}
pub fn sum(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn sum(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "sum", params, args, 1)?;
let mut v = 0 as Float;

View File

@@ -2,14 +2,22 @@
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_array};
use crate::lexer::Span;
use crate::value::Value;
use std::collections::HashMap;
use anyhow::Result;
use std::rc::Rc;
pub fn concat(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("array.concat", concat);
m.insert("array.reverse", reverse);
}
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, &params[0], args[0].clone())?;
@@ -19,7 +27,7 @@ pub fn concat(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::Array(v1))
}
pub fn reverse(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn reverse(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
let name = "array.reverse";
ensure_args_count(span, name, params, args, 2)?;
@@ -29,5 +37,5 @@ pub fn reverse(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
}
/*
pub fn slice(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn slice(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
*/

View File

@@ -6,6 +6,7 @@ pub mod arrays;
pub mod comparison;
pub mod numbers;
pub mod sets;
pub mod types;
pub mod utils;
use crate::ast::Expr;
@@ -24,29 +25,9 @@ lazy_static! {
pub static ref BUILTINS: HashMap<&'static str, BuiltinFcn> = {
let mut m : HashMap<&'static str, BuiltinFcn> = HashMap::new();
// numbers
m.insert("abs", numbers::abs);
m.insert("ceil", numbers::ceil);
m.insert("floor", numbers::floor);
m.insert("numbers.range", numbers::range);
m.insert("rand.intn", numbers::intn);
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);
numbers::register(&mut m);
aggregates::register(&mut m);
arrays::register(&mut m);
m
};

View File

@@ -2,82 +2,23 @@
// Licensed under the MIT License.
use crate::ast::{ArithOp, Expr};
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_numeric, ensure_string};
use crate::lexer::Span;
use crate::value::{Float, Value};
use std::collections::HashMap;
use anyhow::Result;
use rand::{thread_rng, Rng};
pub fn abs(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "abs", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("abs", &params[0], &args[0])?.abs(),
))
}
pub fn ceil(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "ceil", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("ceil", &params[0], &args[0])?.ceil(),
))
}
pub fn floor(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "floor", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("floor", &params[0], &args[0])?.floor(),
))
}
pub fn range(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "numbers.range", params, args, 2)?;
let v1 = ensure_numeric("numbers.range", &params[0], &args[0].clone())?;
let v2 = ensure_numeric("numbers.range", &params[1], &args[1].clone())?;
if v1 != v1.floor() || v2 != v2.floor() {
// TODO: OPA returns undefined here.
// Can we emit a warning?
return Ok(Value::Undefined);
}
let incr = if v2 >= v1 { 1 } else { -1 } as Float;
let mut values = vec![];
values.reserve((v2 - v1).abs() as usize + 1);
let mut v = v1;
while v != v2 {
values.push(Value::from_float(v));
v += incr;
}
values.push(Value::from_float(v));
Ok(Value::from_array(values))
}
pub fn round(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "round", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("round", &params[0], &args[0])?.round(),
))
}
pub fn intn(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
let fcn = "rand.intn";
ensure_args_count(span, fcn, params, args, 2)?;
let _ = ensure_string(fcn, &params[0], &args[0])?;
let n = ensure_numeric(fcn, &params[0], &args[1])?;
if n != n.floor() || n < 0 as Float {
return Ok(Value::Undefined);
}
if n == 0.0 {
return Ok(Value::from_float(0 as Float));
}
// TODO: bounds checking; arbitrary precision
let mut rng = thread_rng();
let v = rng.gen_range(0..n as u64);
Ok(Value::from_float(v as f64))
pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("abs", abs);
m.insert("ceil", ceil);
m.insert("floor", floor);
m.insert("numbers.range", range);
m.insert("rand.intn", intn);
m.insert("round", round);
}
pub fn arithmetic_operation(
@@ -103,3 +44,74 @@ pub fn arithmetic_operation(
ArithOp::Mod => v1 % v2,
}))
}
fn abs(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "abs", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("abs", &params[0], &args[0])?.abs(),
))
}
fn ceil(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "ceil", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("ceil", &params[0], &args[0])?.ceil(),
))
}
fn floor(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "floor", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("floor", &params[0], &args[0])?.floor(),
))
}
fn range(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "numbers.range", params, args, 2)?;
let v1 = ensure_numeric("numbers.range", &params[0], &args[0].clone())?;
let v2 = ensure_numeric("numbers.range", &params[1], &args[1].clone())?;
if v1 != v1.floor() || v2 != v2.floor() {
// TODO: OPA returns undefined here.
// Can we emit a warning?
return Ok(Value::Undefined);
}
let incr = if v2 >= v1 { 1 } else { -1 } as Float;
let mut values = vec![];
values.reserve((v2 - v1).abs() as usize + 1);
let mut v = v1;
while v != v2 {
values.push(Value::from_float(v));
v += incr;
}
values.push(Value::from_float(v));
Ok(Value::from_array(values))
}
fn round(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "round", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("round", &params[0], &args[0])?.round(),
))
}
fn intn(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
let fcn = "rand.intn";
ensure_args_count(span, fcn, params, args, 2)?;
let _ = ensure_string(fcn, &params[0], &args[0])?;
let n = ensure_numeric(fcn, &params[0], &args[1])?;
if n != n.floor() || n < 0 as Float {
return Ok(Value::Undefined);
}
if n == 0.0 {
return Ok(Value::from_float(0 as Float));
}
// TODO: bounds checking; arbitrary precision
let mut rng = thread_rng();
let v = rng.gen_range(0..n as u64);
Ok(Value::from_float(v as f64))
}

View File

@@ -2,18 +2,18 @@
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_set};
use crate::lexer::Span;
use crate::value::Value;
use std::collections::BTreeSet;
use std::collections::{BTreeSet, HashMap};
use anyhow::{bail, Result};
pub fn difference(expr1: &Expr, expr2: &Expr, v1: Value, v2: Value) -> Result<Value> {
let s1 = ensure_set("difference", expr1, v1)?;
let s2 = ensure_set("difference", expr2, v2)?;
Ok(Value::from_set(s1.difference(&s2).cloned().collect()))
pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("intersection", intersection_of_set_of_sets);
m.insert("union", union_of_set_of_sets);
}
pub fn intersection(expr1: &Expr, expr2: &Expr, v1: Value, v2: Value) -> Result<Value> {
@@ -28,7 +28,13 @@ pub fn union(expr1: &Expr, expr2: &Expr, v1: Value, v2: Value) -> Result<Value>
Ok(Value::from_set(s1.union(&s2).cloned().collect()))
}
pub fn intersection_of_set_of_sets(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
pub fn difference(expr1: &Expr, expr2: &Expr, v1: Value, v2: Value) -> Result<Value> {
let s1 = ensure_set("difference", expr1, v1)?;
let s2 = ensure_set("difference", expr2, v2)?;
Ok(Value::from_set(s1.difference(&s2).cloned().collect()))
}
fn intersection_of_set_of_sets(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
let name = "intersection";
ensure_args_count(span, name, params, args, 1)?;
let set = ensure_set(name, &params[0], args[0].clone())?;
@@ -55,7 +61,7 @@ pub fn intersection_of_set_of_sets(span: &Span, params: &[Expr], args: &[Value])
Ok(Value::from_set(res))
}
pub fn union_of_set_of_sets(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn union_of_set_of_sets(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
let name = "union";
ensure_args_count(span, name, params, args, 1)?;
let set = ensure_set(name, &params[0], args[0].clone())?;

75
src/builtins/types.rs Normal file
View File

@@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::builtins;
use crate::builtins::utils::ensure_args_count;
use crate::lexer::Span;
use crate::value::Value;
use std::collections::HashMap;
use anyhow::Result;
pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("is_array", is_array);
m.insert("is_boolean", is_boolean);
m.insert("is_null", is_null);
m.insert("is_number", is_number);
m.insert("is_object", is_object);
m.insert("is_set", is_set);
m.insert("is_string", is_string);
m.insert("type_name", type_name);
}
fn is_array(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_array", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Array(_))))
}
fn is_boolean(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_boolean", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Bool(_))))
}
fn is_null(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_null", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Null)))
}
fn is_number(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_number", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Number(_))))
}
fn is_object(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_object", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Object(_))))
}
fn is_set(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_set", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Set(_))))
}
fn is_string(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_string", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::String(_))))
}
fn type_name(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "type_name", params, args, 1)?;
Ok(Value::String(
match &args[0] {
Value::Null => "null",
Value::Bool(_) => "boolean",
Value::Number(_) => "number",
Value::String(_) => "string",
Value::Array(_) => "array",
Value::Object(_) => "object",
Value::Set(_) => "set",
Value::Undefined => "undefined",
}
.to_string(),
))
}