xylo-lang 0.1.2

A functional programming language for generative art.
Documentation
use crate::builtin_function;
use crate::interpreter::{Data, Value};
use crate::shape::{Color, Gradient, WHITE};

use crate::error::{Error, Result};
use rand_chacha::ChaCha8Rng;

builtin_function!(hsl => {
    [h, s, l, Value::Shape(shape)] => {
         let h = match h {
             Value::Integer(h) => *h as f32,
             Value::Float(h)   => *h,
             _ => return Err(Error::InvalidArgument("hsl".into())),
         };
         let s = match s {
             Value::Integer(s) => *s as f32,
             Value::Float(s)   => *s,
             _ => return Err(Error::InvalidArgument("hsl".into())),
         };
         let l = match l {
             Value::Integer(l) => *l as f32,
             Value::Float(l)   => *l,
             _ => return Err(Error::InvalidArgument("hsl".into())),
         };
         shape.borrow_mut().set_hsl(h, s, l);
         Value::Shape(shape.clone())
    }
});

builtin_function!(hsla => {
    [h, s, l, a, Value::Shape(shape)] => {
         let h = match h {
             Value::Integer(h) => *h as f32,
             Value::Float(h)   => *h,
             _ => return Err(Error::InvalidArgument("hsla".into())),
         };
         let s = match s {
             Value::Integer(s) => *s as f32,
             Value::Float(s)   => *s,
             _ => return Err(Error::InvalidArgument("hsla".into())),
         };
         let l = match l {
             Value::Integer(l) => *l as f32,
             Value::Float(l)   => *l,
             _ => return Err(Error::InvalidArgument("hsla".into())),
         };
         let a = match a {
             Value::Integer(a) => *a as f32,
             Value::Float(a)   => *a,
             _ => return Err(Error::InvalidArgument("hsla".into())),
         };
         shape.borrow_mut().set_hsla(h, s, l, a);
         Value::Shape(shape.clone())
    }
});

builtin_function!(hue => {
    [Value::Integer(h), Value::Shape(shape)] => {
         shape.borrow_mut().set_hue(*h as f32);
         Value::Shape(shape.clone())
    },
    [Value::Float(h), Value::Shape(shape)] => {
         shape.borrow_mut().set_hue(*h);
         Value::Shape(shape.clone())
    }
});

builtin_function!(saturation => {
    [Value::Integer(s), Value::Shape(shape)] => {
         shape.borrow_mut().set_saturation(*s as f32);
         Value::Shape(shape.clone())
    },
    [Value::Float(s), Value::Shape(shape)] => {
         shape.borrow_mut().set_saturation(*s);
         Value::Shape(shape.clone())
    }
});

builtin_function!(lightness => {
    [Value::Integer(l), Value::Shape(shape)] => {
         shape.borrow_mut().set_lightness(*l as f32);
         Value::Shape(shape.clone())
    },
    [Value::Float(l), Value::Shape(shape)] => {
         shape.borrow_mut().set_lightness(*l);
         Value::Shape(shape.clone())
    }
});

builtin_function!(alpha => {
    [Value::Integer(a), Value::Shape(shape)] => {
         shape.borrow_mut().set_alpha(*a as f32);
         Value::Shape(shape.clone())
    },
    [Value::Float(a), Value::Shape(shape)] => {
         shape.borrow_mut().set_alpha(*a);
         Value::Shape(shape.clone())
    }
});

builtin_function!(hshift => {
    [Value::Integer(h), Value::Shape(shape)] => {
         shape.borrow_mut().shift_hue(*h as f32);
         Value::Shape(shape.clone())
    },
    [Value::Float(h), Value::Shape(shape)] => {
         shape.borrow_mut().shift_hue(*h);
         Value::Shape(shape.clone())
    }
});

builtin_function!(satshift => {
    [Value::Integer(s), Value::Shape(shape)] => {
         shape.borrow_mut().shift_saturation(*s as f32);
         Value::Shape(shape.clone())
    },
    [Value::Float(s), Value::Shape(shape)] => {
         shape.borrow_mut().shift_saturation(*s);
         Value::Shape(shape.clone())
    }
});

builtin_function!(lshift => {
    [Value::Integer(l), Value::Shape(shape)] => {
         shape.borrow_mut().shift_lightness(*l as f32);
         Value::Shape(shape.clone())
    },
    [Value::Float(l), Value::Shape(shape)] => {
         shape.borrow_mut().shift_lightness(*l);
         Value::Shape(shape.clone())
    }
});

builtin_function!(ashift => {
    [Value::Integer(a), Value::Shape(shape)] => {
         shape.borrow_mut().shift_alpha(*a as f32);
         Value::Shape(shape.clone())
    },
    [Value::Float(a), Value::Shape(shape)] => {
         shape.borrow_mut().shift_alpha(*a);
         Value::Shape(shape.clone())
    }
});

builtin_function!(hex => {
    [Value::Hex(hex), Value::Shape(shape)] => {
         shape.borrow_mut().set_hex(*hex);
         Value::Shape(shape.clone())
    }
});

builtin_function!(solid => {
    [Value::Shape(shape)] => {
        shape.borrow_mut().set_color(Color::Solid(WHITE));
        Value::Shape(shape.clone())
    }
});

builtin_function!(gradient => {
    [Value::Gradient(g), Value::Shape(shape)] => {
         shape.borrow_mut().set_color(Color::Gradient(g.clone()));
         Value::Shape(shape.clone())
    }
});

builtin_function!(linear_grad => {
    [start_x, start_y, end_x, end_y] => {
        let start_x = match start_x {
            Value::Integer(start_x) => *start_x as f32,
            Value::Float(start_x)   => *start_x,
        _ => return Err(Error::InvalidArgument("linear_grad".into())),
        };
        let start_y = match start_y {
            Value::Integer(start_y) => *start_y as f32,
            Value::Float(start_y)   => *start_y,
        _ => return Err(Error::InvalidArgument("linear_grad".into())),
        };
        let end_x = match end_x {
            Value::Integer(end_x) => *end_x as f32,
            Value::Float(end_x)   => *end_x,
        _ => return Err(Error::InvalidArgument("linear_grad".into())),
        };
        let end_y = match end_y {
            Value::Integer(end_y) => *end_y as f32,
            Value::Float(end_y)   => *end_y,
        _ => return Err(Error::InvalidArgument("linear_grad".into())),
        };
        Value::Gradient(Gradient::linear(start_x, start_y, end_x, end_y))
    }
});

builtin_function!(radial_grad => {
    [start_x, start_y, end_x, end_y, radius] => {
        let start_x = match start_x {
            Value::Integer(start_x) => *start_x as f32,
            Value::Float(start_x)   => *start_x,
        _ => return Err(Error::InvalidArgument("radial_grad".into())),
        };
        let start_y = match start_y {
            Value::Integer(start_y) => *start_y as f32,
            Value::Float(start_y)   => *start_y,
        _ => return Err(Error::InvalidArgument("radial_grad".into())),
        };
        let end_x = match end_x {
            Value::Integer(end_x) => *end_x as f32,
            Value::Float(end_x)   => *end_x,
        _ => return Err(Error::InvalidArgument("radial_grad".into())),
        };
        let end_y = match end_y {
            Value::Integer(end_y) => *end_y as f32,
            Value::Float(end_y)   => *end_y,
        _ => return Err(Error::InvalidArgument("radial_grad".into())),
        };
        let radius = match radius {
            Value::Integer(radius) => *radius as f32,
            Value::Float(radius)   => *radius,
            _ => return Err(Error::InvalidArgument("radial_grad".into())),
        };
        Value::Gradient(Gradient::radial(start_x, start_y, end_x, end_y, radius))
    }
});

builtin_function!(grad_start => {
    [start_x, start_y, Value::Gradient(g)] => {
        let start_x = match start_x {
            Value::Integer(start_x) => *start_x as f32,
            Value::Float(start_x)   => *start_x,
            _ => return Err(Error::InvalidArgument("grad_start".into())),
        };
        let start_y = match start_y {
            Value::Integer(start_y) => *start_y as f32,
            Value::Float(start_y)   => *start_y,
            _ => return Err(Error::InvalidArgument("grad_start".into())),
        };

        let mut g = g.clone();
        g.set_start(start_x, start_y);
        Value::Gradient(g)
    }
});

builtin_function!(grad_end => {
    [end_x, end_y, Value::Gradient(g)] => {
        let end_x = match end_x {
            Value::Integer(end_x) => *end_x as f32,
            Value::Float(end_x)   => *end_x,
            _ => return Err(Error::InvalidArgument("grad_end".into())),
        };
        let end_y = match end_y {
            Value::Integer(end_y) => *end_y as f32,
            Value::Float(end_y)   => *end_y,
            _ => return Err(Error::InvalidArgument("grad_end".into())),
        };

        let mut g = g.clone();
        g.set_end(end_x, end_y);
        Value::Gradient(g)
    }
});

builtin_function!(to_linear_grad => {
    [Value::Gradient(g)] => {
        let mut g = g.clone();
        g.set_radius(None);
        Value::Gradient(g)
    }
});

builtin_function!(grad_radius => {
    [radius, Value::Gradient(g)] => {
        let radius = match radius {
            Value::Integer(radius) => *radius as f32,
            Value::Float(radius)   => *radius,
            _ => return Err(Error::InvalidArgument("grad_radius".into())),
        };

        let mut g = g.clone();
        g.set_radius(Some(radius));
        Value::Gradient(g)
    }
});

builtin_function!(grad_stop_hsl => {
    [pos, h, s, l, Value::Gradient(g)] => {
         let pos = match pos {
             Value::Integer(pos) => *pos as f32,
             Value::Float(pos)   => *pos,
             _ => return Err(Error::InvalidArgument("grad_stop_hsl".into())),
         };
         let h = match h {
             Value::Integer(h) => *h as f32,
             Value::Float(h)   => *h,
             _ => return Err(Error::InvalidArgument("grad_stop_hsl".into())),
         };
         let s = match s {
             Value::Integer(s) => *s as f32,
             Value::Float(s)   => *s,
             _ => return Err(Error::InvalidArgument("grad_stop_hsl".into())),
         };
         let l = match l {
             Value::Integer(l) => *l as f32,
             Value::Float(l)   => *l,
             _ => return Err(Error::InvalidArgument("grad_stop_hsl".into())),
         };

        let mut g = g.clone();
        g.set_stop_hsl(pos, h, s, l);
        Value::Gradient(g)
    }
});

builtin_function!(grad_stop_hsla => {
    [pos, h, s, l, a, Value::Gradient(g)] => {
         let pos = match pos {
             Value::Integer(pos) => *pos as f32,
             Value::Float(pos)   => *pos,
             _ => return Err(Error::InvalidArgument("grad_stop_hsla".into())),
         };
         let h = match h {
             Value::Integer(h) => *h as f32,
             Value::Float(h)   => *h,
             _ => return Err(Error::InvalidArgument("grad_stop_hsla".into())),
         };
         let s = match s {
             Value::Integer(s) => *s as f32,
             Value::Float(s)   => *s,
             _ => return Err(Error::InvalidArgument("grad_stop_hsla".into())),
         };
         let l = match l {
             Value::Integer(l) => *l as f32,
             Value::Float(l)   => *l,
             _ => return Err(Error::InvalidArgument("grad_stop_hsla".into())),
         };
         let a = match a {
             Value::Integer(a) => *a as f32,
             Value::Float(a)   => *a,
             _ => return Err(Error::InvalidArgument("grad_stop_hsla".into())),
         };

        let mut g = g.clone();
        g.set_stop_hsla(pos, h, s, l, a);
        Value::Gradient(g)
    }
});

builtin_function!(grad_stop_hex => {
    [pos, Value::Hex(hex), Value::Gradient(g)] => {
         let pos = match pos {
             Value::Integer(pos) => *pos as f32,
             Value::Float(pos)   => *pos,
             _ => return Err(Error::InvalidArgument("grad_stop_hex".into())),
         };

        let mut g = g.clone();
        g.set_stop_hex(pos, *hex);
        Value::Gradient(g)
    }
});

builtin_function!(grad_spread_mode => {
    [Value::SpreadMode(spread_mode), Value::Gradient(g)] => {
        let mut g = g.clone();
        g.set_spread_mode(*spread_mode);
        Value::Gradient(g)
    }
});