xylo-lang 0.1.2

A functional programming language for generative art.
Documentation
use crate::builtin_function;
use crate::error::{Error, Result};
use crate::interpreter::{Data, Value};

use noise::NoiseFn;
use rand::prelude::*;
use rand_chacha::ChaCha8Rng;

builtin_function!(rand rng => {
    [] => |rng: &mut ChaCha8Rng| Ok(Value::Float(rng.random())),
});

builtin_function!(randi rng => {
    [] => |rng: &mut ChaCha8Rng| {
        if rng.random() {
            Ok(Value::Integer(1))
        } else {
            Ok(Value::Integer(0))
        }
    },
});

builtin_function!(rand_range rng => {
    [Value::Integer(from), Value::Integer(to)] => |rng: &mut ChaCha8Rng| {
        let a = *from as f32;
        let b = *to as f32;
        Ok(Value::Float(rng.random_range(a..b)))
    },
    [Value::Float(from), Value::Float(to)] => |rng: &mut ChaCha8Rng| {
        Ok(Value::Float(rng.random_range(*from..*to)))
    },
    [Value::Integer(from), Value::Float(to)] => |rng: &mut ChaCha8Rng| {
        let a = *from as f32;
        Ok(Value::Float(rng.random_range(a..*to)))
    },
    [Value::Float(from), Value::Integer(to)] => |rng: &mut ChaCha8Rng| {
        let b = *to as f32;
        Ok(Value::Float(rng.random_range(*from..b)))
    }
});

builtin_function!(rand_rangei rng => {
    [Value::Integer(from), Value::Integer(to)] => |rng: &mut ChaCha8Rng| {
        let a = *from as f32;
        let b = *to as f32;
        Ok(Value::Float(rng.random_range(a..=b)))
    },
    [Value::Float(from), Value::Float(to)] => |rng: &mut ChaCha8Rng| {
        Ok(Value::Float(rng.random_range(*from..=*to)))
    },
    [Value::Integer(from), Value::Float(to)] => |rng: &mut ChaCha8Rng| {
        let a = *from as f32;
        Ok(Value::Float(rng.random_range(a..=*to)))
    },
    [Value::Float(from), Value::Integer(to)] => |rng: &mut ChaCha8Rng| {
        let b = *to as f32;
        Ok(Value::Float(rng.random_range(*from..=b)))
    }
});

builtin_function!(randi_range rng => {
    [Value::Integer(a), Value::Integer(b)] => |rng: &mut ChaCha8Rng| {
        Ok(Value::Integer(rng.random_range(*a..*b)))
    },
    [Value::Float(a), Value::Float(b)] => |rng: &mut ChaCha8Rng| {
        Ok(Value::Integer(rng.random_range((*a as i32)..(*b as i32))))
    },
    [Value::Integer(a), Value::Float(b)] => |rng: &mut ChaCha8Rng| {
        Ok(Value::Integer(rng.random_range(*a..(*b as i32))))
    },
    [Value::Float(a), Value::Integer(b)] => |rng: &mut ChaCha8Rng| {
        Ok(Value::Integer(rng.random_range((*a as i32)..*b)))
    }
});

builtin_function!(randi_rangei rng => {
    [Value::Integer(a), Value::Integer(b)] => |rng: &mut ChaCha8Rng| {
        Ok(Value::Integer(rng.random_range(*a..=*b)))
    },
    [Value::Float(a), Value::Float(b)] => |rng: &mut ChaCha8Rng| {
        Ok(Value::Integer(rng.random_range((*a as i32)..=(*b as i32))))
    },
    [Value::Integer(a), Value::Float(b)] => |rng: &mut ChaCha8Rng| {
        Ok(Value::Integer(rng.random_range(*a..=(*b as i32))))
    },
    [Value::Float(a), Value::Integer(b)] => |rng: &mut ChaCha8Rng| {
        Ok(Value::Integer(rng.random_range((*a as i32)..=*b)))
    }
});

builtin_function!(shuffle rng => {
    [Value::List(list)] => |rng: &mut ChaCha8Rng| {
        let mut list = list.clone();
        list.shuffle(rng);
        Ok(Value::List(list))
    }
});

builtin_function!(choose rng => {
    [Value::List(list)] => |rng: &mut ChaCha8Rng| {
        Ok(list.choose(rng).unwrap().clone())
    }
});

builtin_function!(noise1 data => {
    [a] => |data: &Data| {
        let a = match a {
            Value::Integer(a) => *a as f64,
            Value::Float(a) => *a as f64,
            _ => return Err(Error::InvalidArgument("noise1".into())),
        };

        Ok(Value::Float(data.perlin.get([a]) as f32))
    }
});

builtin_function!(noise2 data => {
    [a, b] => |data: &Data| {
        let a = match a {
            Value::Integer(a) => *a as f64,
            Value::Float(a) => *a as f64,
            _ => return Err(Error::InvalidArgument("noise2".into())),
        };

        let b = match b {
            Value::Integer(b) => *b as f64,
            Value::Float(b) => *b as f64,
            _ => return Err(Error::InvalidArgument("noise2".into())),
        };

        Ok(Value::Float(data.perlin.get([a, b]) as f32))
    }
});

builtin_function!(noise3 data => {
    [a, b, c] => |data: &Data| {
        let a = match a {
            Value::Integer(a) => *a as f64,
            Value::Float(a) => *a as f64,
            _ => return Err(Error::InvalidArgument("noise3".into())),
        };

        let b = match b {
            Value::Integer(b) => *b as f64,
            Value::Float(b) => *b as f64,
            _ => return Err(Error::InvalidArgument("noise3".into())),
        };

        let c = match c {
            Value::Integer(c) => *c as f64,
            Value::Float(c) => *c as f64,
            _ => return Err(Error::InvalidArgument("noise3".into())),
        };

        Ok(Value::Float(data.perlin.get([a, b, c]) as f32))
    }
});

builtin_function!(noise4 data => {
    [a, b, c, d] => |data: &Data| {
        let a = match a {
            Value::Integer(a) => *a as f64,
            Value::Float(a) => *a as f64,
            _ => return Err(Error::InvalidArgument("noise4".into())),
        };

        let b = match b {
            Value::Integer(b) => *b as f64,
            Value::Float(b) => *b as f64,
            _ => return Err(Error::InvalidArgument("noise4".into())),
        };

        let c = match c {
            Value::Integer(c) => *c as f64,
            Value::Float(c) => *c as f64,
            _ => return Err(Error::InvalidArgument("noise4".into())),
        };

        let d = match d {
            Value::Integer(d) => *d as f64,
            Value::Float(d) => *d as f64,
            _ => return Err(Error::InvalidArgument("noise4".into())),
        };

        Ok(Value::Float(data.perlin.get([a, b, c, d]) as f32))
    }
});