use crate::error::{Error, Result};
use crate::interpreter::Value;
use noise::Perlin;
use rand_chacha::ChaCha8Rng;
mod color;
mod compare;
mod func;
mod list;
mod math;
mod path;
mod rand;
mod shape;
mod transform;
macro_rules! define_builtins {
(
$(
$name:literal => {$func:path, $param_count:literal}
),* $(,)?
) => {
pub static BUILTIN_FUNCTIONS: &[&str] = &[
"map",
$($name),*
];
pub fn handle_builtin(name: &str, rng: &mut ChaCha8Rng, perlin: &Perlin, args: &[Value]) -> Result<Value> {
match name {
$(
$name => $func(rng, perlin, args),
)*
_ => Err(Error::UnknownFunction(name.into())),
}
}
pub fn builtin_param_count(name: &str) -> usize {
match name {
"map" => 2,
$(
$name => $param_count,
)*
_ => unreachable!(),
}
}
};
}
define_builtins! {
"neg" => {math::neg, 1},
"!" => {compare::not, 1},
"not" => {compare::not, 1},
"~" => {math::bitnot, 1},
"bitnot" => {math::bitnot, 1},
"+" => {math::add, 2},
"add" => {math::add, 2},
"-" => {math::sub, 2},
"sub" => {math::sub, 2},
"*" => {math::mul, 2},
"mul" => {math::mul, 2},
"/" => {math::div, 2},
"div" => {math::div, 2},
"%" => {math::modulo, 2},
"mod" => {math::modulo, 2},
"**" => {math::pow, 2},
"pow" => {math::pow, 2},
"&" => {math::bitand, 2},
"bitand" => {math::bitand, 2},
"|" => {math::bitor, 2},
"bitor" => {math::bitor, 2},
"^" => {math::bitxor, 2},
"bitxor" => {math::bitxor, 2},
"<<" => {math::bitleft, 2},
"bitleft" => {math::bitleft, 2},
">>" => {math::bitright, 2},
"bitright" => {math::bitright, 2},
"==" => {compare::eq, 2},
"eq" => {compare::eq, 2},
"!=" => {compare::neq, 2},
"neq" => {compare::neq, 2},
"<" => {compare::lt, 2},
"lt" => {compare::lt, 2},
"<=" => {compare::lte, 2},
"lte" => {compare::lte, 2},
">" => {compare::gt, 2},
"gt" => {compare::gt, 2},
">=" => {compare::gte, 2},
"gte" => {compare::gte, 2},
"&&" => {compare::and, 2},
"and" => {compare::and, 2},
"||" => {compare::or, 2},
"or" => {compare::or, 2},
".." => {list::range, 2},
"range" => {list::range, 2},
"..=" => {list::rangei, 2},
"rangei" => {list::rangei, 2},
"++" => {list::concat, 2},
"concat" => {list::concat, 2},
"+>" => {list::prepend, 2},
"prepend" => {list::prepend, 2},
"<+" => {list::append, 2},
"append" => {list::append, 2},
"nth" => {list::nth, 2},
"set" => {list::set, 3},
"length" => {list::length, 1},
"is_empty" => {list::is_empty, 1},
"head" => {list::head, 1},
"tail" => {list::tail, 1},
"init" => {list::init, 1},
"last" => {list::last, 1},
"contains" => {list::contains, 2},
"take" => {list::take, 2},
"drop" => {list::drop, 2},
"index_of" => {list::index_of, 2},
"reverse" => {list::reverse, 1},
"slice" => {list::slice, 3},
"split" => {list::split, 2},
"unique" => {list::unique, 1},
"min_of" => {list::min_of, 1},
"max_of" => {list::max_of, 1},
"sum" => {list::sum, 1},
"product" => {list::product, 1},
"sort" => {list::sort, 1},
"flatten" => {list::flatten, 1},
"intersperse" => {list::intersperse, 2},
":" => {shape::compose, 2},
"collect" => {shape::collect, 1},
"|>" => {func::pipe, 2},
"pipe" => {func::pipe, 2},
"pi" => {math::pi, 0},
"Ï€" => {math::pi, 0},
"tau" => {math::tau, 0},
"Ï„" => {math::tau, 0},
"e" => {math::e, 0},
"ℯ" => {math::e, 0},
"phi" => {math::phi, 0},
"φ" => {math::phi, 0},
"int" => {math::int, 1},
"float" => {math::float, 1},
"complex" => {math::complex, 2},
"real" => {math::real, 1},
"imag" => {math::imag, 1},
"sin" => {math::sin, 1},
"cos" => {math::cos, 1},
"tan" => {math::tan, 1},
"asin" => {math::asin, 1},
"acos" => {math::acos, 1},
"atan" => {math::atan, 1},
"atan2" => {math::atan2, 2},
"sinh" => {math::sinh, 1},
"cosh" => {math::cosh, 1},
"tanh" => {math::tanh, 1},
"asinh" => {math::asinh, 1},
"acosh" => {math::acosh, 1},
"atanh" => {math::atanh, 1},
"ln" => {math::ln, 1},
"log10" => {math::log10, 1},
"log" => {math::log, 2},
"floor" => {math::floor, 1},
"ceil" => {math::ceil, 1},
"abs" => {math::abs, 1},
"sqrt" => {math::sqrt, 1},
"cbrt" => {math::cbrt, 1},
"fact" => {math::fact, 1},
"fact2" => {math::fact2, 1},
"min" => {math::min, 2},
"max" => {math::max, 2},
"rand" => {rand::rand, 0},
"randi" => {rand::randi, 0},
"rand_range" => {rand::rand_range, 2},
"randi_range" => {rand::randi_range, 2},
"rand_rangei" => {rand::rand_rangei, 2},
"randi_rangei" => {rand::randi_rangei, 2},
"shuffle" => {rand::shuffle, 1},
"choose" => {rand::choose, 1},
"noise1" => {rand::noise1, 1},
"noise2" => {rand::noise2, 2},
"noise3" => {rand::noise3, 3},
"noise4" => {rand::noise4, 4},
"compose" => {shape::compose, 2},
"t" => {transform::translate, 3},
"translate" => {transform::translate, 3},
"tx" => {transform::translatex, 2},
"translatex" => {transform::translatex, 2},
"ty" => {transform::translatey, 2},
"translatey" => {transform::translatey, 2},
"tt" => {transform::translateb, 2},
"translateb" => {transform::translateb, 2},
"r" => {transform::rotate, 2},
"rotate" => {transform::rotate, 2},
"ra" => {transform::rotate_at, 4},
"rotate_at" => {transform::rotate_at, 4},
"s" => {transform::scale, 3},
"scale" => {transform::scale, 3},
"sx" => {transform::scalex, 2},
"scalex" => {transform::scalex, 2},
"sy" => {transform::scaley, 2},
"scaley" => {transform::scaley, 2},
"ss" => {transform::scaleb, 2},
"scaleb" => {transform::scaleb, 2},
"k" => {transform::skew, 3},
"skew" => {transform::skew, 3},
"kx" => {transform::skewx, 2},
"skewx" => {transform::skewx, 2},
"ky" => {transform::skewy, 2},
"skewy" => {transform::skewy, 2},
"kk" => {transform::skewb, 2},
"skewb" => {transform::skewb, 2},
"f" => {transform::flip, 2},
"flip" => {transform::flip, 2},
"fh" => {transform::fliph, 1},
"fliph" => {transform::fliph, 1},
"fv" => {transform::flipv, 1},
"flipv" => {transform::flipv, 1},
"fd" => {transform::flipd, 1},
"flipd" => {transform::flipd, 1},
"z" => {transform::zindex, 2},
"zindex" => {transform::zindex, 2},
"zshift" => {transform::zshift, 2},
"hsl" => {color::hsl, 4},
"hsla" => {color::hsla, 5},
"h" => {color::hue, 2},
"hue" => {color::hue, 2},
"sat" => {color::saturation, 2},
"saturation" => {color::saturation, 2},
"l" => {color::lightness, 2},
"lightness" => {color::lightness, 2},
"a" => {color::alpha, 2},
"alpha" => {color::alpha, 2},
"hshift" => {color::hshift, 2},
"satshift" => {color::satshift, 2},
"lshift" => {color::lshift, 2},
"ashift" => {color::ashift, 2},
"hex" => {color::hex, 2},
"blend" => {color::blend, 2},
"anti_alias" => {color::anti_alias, 2},
"move_to" => {path::move_to, 2},
"line_to" => {path::line_to, 2},
"quad_to" => {path::quad_to, 4},
"cubic_to" => {path::cubic_to, 6},
"close" => {path::close, 0},
}
#[macro_export]
macro_rules! builtin_function {
($name:ident => {
$(
$pattern:pat => $body:expr
),* $(,)?
}) => {
pub fn $name(_rng: &mut ChaCha8Rng, _perlin: &Perlin, args: &[Value]) -> Result<Value> {
match args {
$(
$pattern => Ok($body),
)*
_ => Err(Error::InvalidArgument(stringify!($name).into())),
}
}
};
($name:ident rng => {
$(
$pattern:pat => $body:expr
),* $(,)?
}) => {
pub fn $name(rng: &mut ChaCha8Rng, _perlin: &Perlin, args: &[Value]) -> Result<Value> {
match args {
$(
$pattern => $body(rng),
)*
_ => Err(Error::InvalidArgument(
stringify!($name).into(),
)),
}
}
};
($name:ident perlin => {
$(
$pattern:pat => $body:expr
),* $(,)?
}) => {
pub fn $name(_rng: &mut ChaCha8Rng, perlin: &Perlin, args: &[Value]) -> Result<Value> {
match args {
$(
$pattern => $body(perlin),
)*
_ => Err(Error::InvalidArgument(
stringify!($name).into(),
)),
}
}
};
}