Skip to content

Commit

Permalink
Implement more math filters
Browse files Browse the repository at this point in the history
  • Loading branch information
itchyny committed Mar 2, 2024
1 parent 23187ab commit 32f4bf4
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 2 deletions.
75 changes: 74 additions & 1 deletion src/intrinsic/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,48 @@ macro_rules! as_math_fn {
};
}

macro_rules! as_math_fn2 {
($name: ident) => {
crate::vm::bytecode::NamedFn2 {
name: stringify!($name),
func: |_: Value, v: Value, w: Value| match (v, w) {
(crate::Value::Number(v), crate::Value::Number(w)) => {
crate::intrinsic::math::$name(v, w).map(Into::into)
}
(v, crate::Value::Number(_)) => crate::vm::Result::Err(
crate::vm::QueryExecutionError::InvalidArgType(stringify!($name), v),
),
(_, w) => crate::vm::Result::Err(crate::vm::QueryExecutionError::InvalidArgType(
stringify!($name),
w,
)),
},
}
};
}

macro_rules! as_math_fn3 {
($name: ident) => {
crate::vm::bytecode::NamedFn3 {
name: stringify!($name),
func: |_: Value, v: Value, w: Value, x: Value| match (v, w, x) {
(crate::Value::Number(v), crate::Value::Number(w), crate::Value::Number(x)) => {
crate::intrinsic::math::$name(v, w, x).map(Into::into)
}
(v, crate::Value::Number(_), crate::Value::Number(_)) => crate::vm::Result::Err(
crate::vm::QueryExecutionError::InvalidArgType(stringify!($name), v),
),
(_, w, crate::Value::Number(_)) => crate::vm::Result::Err(
crate::vm::QueryExecutionError::InvalidArgType(stringify!($name), w),
),
(_, _, x) => crate::vm::Result::Err(
crate::vm::QueryExecutionError::InvalidArgType(stringify!($name), x),
),
},
}
};
}

pub(crate) fn nan(_: Value) -> Result<Value> {
Ok(Number::nan().into())
}
Expand All @@ -37,6 +79,10 @@ pub(crate) fn is_infinite(v: Number) -> Result<bool> {
Ok(v.is_infinite())
}

pub(crate) fn exp10(v: Number) -> Result<Number> {
Ok(Number::from(10).powf(v))
}

macro_rules! pub_math_fn {
($($name: ident),*) => {
$(
Expand All @@ -47,4 +93,31 @@ macro_rules! pub_math_fn {
};
}

pub_math_fn!(floor, sqrt, sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh);
pub_math_fn!(
floor, round, ceil, trunc, abs, sqrt, cbrt, sin, cos, tan, asin, acos, atan, sinh, cosh, tanh,
asinh, acosh, atanh, exp, exp2, exp_m1, ln, log2, log10
);

pub(crate) fn fmax(v: Number, w: Number) -> Result<Number> {
Ok(Float::max(v, w))
}

pub(crate) fn fmin(v: Number, w: Number) -> Result<Number> {
Ok(Float::min(v, w))
}

macro_rules! pub_math_fn2 {
($($name: ident),*) => {
$(
pub(crate) fn $name(v: Number, w: Number) -> Result<Number> {
Ok(v.$name(w))
}
)*
};
}

pub_math_fn2!(copysign, atan2, hypot, powf);

pub(crate) fn fma(v: Number, w: Number, x: Number) -> Result<Number> {
Ok(v.mul_add(w, x))
}
31 changes: 30 additions & 1 deletion src/intrinsic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
compile::compiler::{ArgType, FunctionIdentifier},
util::make_owned,
vm::{
bytecode::{NamedFn0, NamedFn1, NamedFn2},
bytecode::{NamedFn0, NamedFn1, NamedFn2, NamedFn3},
error::Result,
ByteCode, QueryExecutionError,
},
Expand Down Expand Up @@ -62,7 +62,12 @@ static INTRINSICS0: phf::Map<&'static str, NamedFn0> = phf_map! {
"isnormal" => as_math_fn!(is_normal),
"isinfinite" => as_math_fn!(is_infinite),
"floor" => as_math_fn!(floor),
"round" => as_math_fn!(round),
"ceil" => as_math_fn!(ceil),
"trunc" => as_math_fn!(trunc),
"fabs" => as_math_fn!(abs),
"sqrt" => as_math_fn!(sqrt),
"cbrt" => as_math_fn!(cbrt),
"sin" => as_math_fn!(sin),
"cos" => as_math_fn!(cos),
"tan" => as_math_fn!(tan),
Expand All @@ -75,6 +80,13 @@ static INTRINSICS0: phf::Map<&'static str, NamedFn0> = phf_map! {
"asinh" => as_math_fn!(asinh),
"acosh" => as_math_fn!(acosh),
"atanh" => as_math_fn!(atanh),
"exp" => as_math_fn!(exp),
"exp2" => as_math_fn!(exp2),
"exp10" => as_math_fn!(exp10),
"expm1" => as_math_fn!(exp_m1),
"log" => as_math_fn!(ln),
"log2" => as_math_fn!(log2),
"log10" => as_math_fn!(log10),
};
static INTRINSICS1: phf::Map<&'static str, NamedFn1> = phf_map! {
"error" => NamedFn1 { name: "error", func: error1 },
Expand All @@ -101,6 +113,16 @@ static INTRINSICS1: phf::Map<&'static str, NamedFn1> = phf_map! {
static INTRINSICS2: phf::Map<&'static str, NamedFn2> = phf_map! {
"setpath" => NamedFn2 { name: "setpath", func: path::set_path },
"__split_match_impl" => NamedFn2 { name: "__split_match_impl", func: regex::split_match_impl },

"fmax" => as_math_fn2!(fmax),
"fmin" => as_math_fn2!(fmin),
"copysign" => as_math_fn2!(copysign),
"atan2" => as_math_fn2!(atan2),
"hypot" => as_math_fn2!(hypot),
"pow" => as_math_fn2!(powf),
};
static INTRINSICS3: phf::Map<&'static str, NamedFn3> = phf_map! {
"fma" => as_math_fn3!(fma),
};

pub(crate) fn lookup_intrinsic_fn(
Expand All @@ -123,6 +145,13 @@ pub(crate) fn lookup_intrinsic_fn(
vec![ArgType::Value, ArgType::Value],
)
})
} else if *n_args == 3 {
INTRINSICS3.get(&ident.0).cloned().map(|f| {
(
ByteCode::Intrinsic3(f),
vec![ArgType::Value, ArgType::Value, ArgType::Value],
)
})
} else {
None
}
Expand Down
7 changes: 7 additions & 0 deletions src/vm/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub(crate) struct ClosureAddress(pub(crate) Address);
pub type NamedFn0 = NamedFunction<fn(Value) -> Result<Value>>;
pub type NamedFn1 = NamedFunction<fn(Value, Value) -> Result<Value>>;
pub type NamedFn2 = NamedFunction<fn(Value, Value, Value) -> Result<Value>>;
pub type NamedFn3 = NamedFunction<fn(Value, Value, Value, Value) -> Result<Value>>;

impl<F: Clone> Debug for NamedFunction<F> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Expand Down Expand Up @@ -189,6 +190,12 @@ pub(crate) enum ByteCode {
/// # Panics
/// Panics if the stack had less than 3 elements, or the invoked function panicked.
Intrinsic2(NamedFn2),
/// Pops a value `arg3` from the stack, pops another value `arg2` from the stack, pops another value `arg1` from the stack,
/// and another value `context` from the stack, and invokes the function with the arg `context, arg1, arg2, arg3`,
/// and pushes the resulting value to the stack.
/// # Panics
/// Panics if the stack had less than 4 elements, or the invoked function panicked.
Intrinsic3(NamedFn3),
}

#[derive(Debug, Clone)]
Expand Down
18 changes: 18 additions & 0 deletions src/vm/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,24 @@ fn run_code(
Err(e) => err = Some(e),
}
}
Intrinsic3(NamedFunction { name, func }) => {
let arg3 = state.pop();
let arg2 = state.pop();
let arg1 = state.pop();
let context = state.pop();
log::trace!(
"Calling function {} with context {:?} and arg1 {:?} and arg2 {:?} and arg3 {:?}",
name,
context,
arg1,
arg2,
arg3
);
match func(context, arg1, arg2, arg3) {
Ok(value) => state.push(value),
Err(e) => err = Some(e),
}
}
}
state.pc.next();
}
Expand Down
110 changes: 110 additions & 0 deletions tests/hand_written/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,37 @@ test!(
"#
);

test!(
floor_round_ceil_trunc_fabs_functions,
r#"
map(floor), map(round), map(ceil), map(trunc), map(fabs)
"#,
r#"
[-3.5,-2.1,-1,-0.3,0,0.3,0.7,1,1.2,2.8,3.5]
"#,
r#"
[-4,-3,-1,-1,0,0,0,1,1,2,3]
[-4,-2,-1,-0,0,0,1,1,1,3,4]
[-3,-2,-1,-0,0,1,1,1,2,3,4]
[-3,-2,-1,-0,0,0,0,1,1,2,3]
[3.5,2.1,1,0.3,0,0.3,0.7,1,1.2,2.8,3.5]
"#
);

test!(
sqrt_cbrt_functions,
r#"
map(sqrt | select(isnan | not)), map(cbrt) | map(. * 1000000000 | floor / 1000000000)
"#,
r#"
[-8,-3.375,0,0.125,1,4,8,40.96,64]
"#,
r#"
[0,0.35355339,1,2,2.828427124,6.4,8]
[-2,-1.5,0,0.5,1,1.587401051,2,3.447095504,4]
"#
);

test!(
trigonometric_functions,
r#"
Expand Down Expand Up @@ -75,3 +106,82 @@ test!(
[0,0.346573590,0.804718956]
"#
);

test!(
exponential_functions,
r#"
map(exp), map(exp2), map(exp10), map(expm1) | map(. * 1000000000 | floor / 1000000000)
"#,
r#"
[-1,-0.5,0,0.5,1,1.5,2]
"#,
r#"
[0.367879441,0.606530659,1,1.64872127,2.718281828,4.48168907,7.389056098]
[0.5,0.707106781,1,1.414213562,2,2.828427124,4]
[0.1,0.316227766,1,3.16227766,10,31.622776601,100]
[-0.632120559,-0.393469341,0,0.64872127,1.718281828,3.48168907,6.389056098]
"#
);

test!(
logarithmic_functions,
r#"
map(log), map(log2), map(log10) | map(. * 1000000000 | floor / 1000000000)
"#,
r#"
[0.1,0.5,1,2,3,10]
"#,
r#"
[-2.302585093,-0.693147181,0,0.69314718,1.098612288,2.302585092]
[-3.321928095,-1,0,1,1.5849625,3.321928094]
[-1,-0.301029996,0,0.301029995,0.477121254,1]
"#
);

test!(
fmax_fmin_copysign_functions,
r#"
[fmax(0.1,0.3; 0.2,0.4)],
[fmin(0.1,0.3; 0.2,0.4)],
[copysign(0.1,-0.3; 0.2,-0.4)]
"#,
r#"
null
"#,
r#"
[0.2,0.4,0.3,0.4]
[0.1,0.1,0.2,0.3]
[0.1,-0.1,0.3,-0.3]
"#
);

test!(
atan2_hypot_powf_functions,
r#"
[atan2(0.1,0.3; 0.2,0.4)],
[hypot(0.1,0.3; 0.2,0.4)],
[pow(0.1,0.3; 0.2,0.4)] |
map(. * 1000000000 | floor / 1000000000)
"#,
r#"
null
"#,
r#"
[0.463647609,0.244978663,0.982793723,0.643501108]
[0.223606797,0.412310562,0.360555127,0.5]
[0.630957344,0.39810717,0.786003085,0.61780085]
"#
);

test!(
fma_function,
r#"
[fma(1.5,2.5; 3.5,4.5; 5.25,6.75)]
"#,
r#"
null
"#,
r#"
[10.5,12,12,13.5,14,15.5,16.5,18]
"#
);

0 comments on commit 32f4bf4

Please # to comment.