mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
committed by
Anand Krishnamoorthi
parent
d84096024d
commit
3549931342
@@ -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;
|
||||
|
||||
@@ -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, ¶ms[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> {
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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", ¶ms[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", ¶ms[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", ¶ms[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", ¶ms[0], &args[0].clone())?;
|
||||
let v2 = ensure_numeric("numbers.range", ¶ms[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", ¶ms[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, ¶ms[0], &args[0])?;
|
||||
let n = ensure_numeric(fcn, ¶ms[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", ¶ms[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", ¶ms[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", ¶ms[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", ¶ms[0], &args[0].clone())?;
|
||||
let v2 = ensure_numeric("numbers.range", ¶ms[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", ¶ms[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, ¶ms[0], &args[0])?;
|
||||
let n = ensure_numeric(fcn, ¶ms[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))
|
||||
}
|
||||
|
||||
@@ -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, ¶ms[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, ¶ms[0], args[0].clone())?;
|
||||
|
||||
75
src/builtins/types.rs
Normal file
75
src/builtins/types.rs
Normal 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(),
|
||||
))
|
||||
}
|
||||
Reference in New Issue
Block a user