shadergraph/lisp/
mod.rs

1use std::rc::Rc;
2
3use glium::backend::Context;
4use lexpr::Value;
5
6use crate::{
7    graph::{
8        NodeId,
9        ShaderGraph,
10    },
11    reload::ShaderDir,
12};
13
14mod env;
15mod load;
16mod val;
17
18pub use env::{
19    Env,
20    External,
21};
22pub use load::load_shaders;
23pub use val::Val;
24
25/// Takes a source string of lisp that represents the shader
26/// graph to be constructed, And constructs that shader
27/// graph within a certain context, Provided a map of all
28/// shaders avaliable for the construction of the graph. You
29/// can use [`load_shaders`] to load a directory into a map.
30pub fn graph_from_sexp(
31    context: &Rc<Context>,
32    shader_dir: ShaderDir,
33    external: External,
34) -> Result<ShaderGraph, String> {
35    let mut graph = ShaderGraph::new(context);
36    let mut env = Env::new(shader_dir.shaders, external);
37
38    // little hack to get a list of expressions
39    let sexp = lexpr::from_str(&format!("({})", shader_dir.lisp))
40        .map_err(|e| format!("{}", e))?;
41
42    begin(&mut graph, &mut env, &sexp)?;
43
44    Ok(graph)
45}
46
47fn into_iter(sexp: &Value) -> Result<lexpr::cons::ListIter<'_>, String> {
48    sexp.list_iter()
49        .ok_or_else(|| "Expected a form".to_string())
50}
51
52fn next_item<'a>(
53    iter: &mut lexpr::cons::ListIter<'a>,
54) -> Result<&'a Value, String> {
55    iter.next()
56        .ok_or_else(|| "Expected a non-empty form".to_string())
57}
58
59fn next_symbol<'a>(
60    iter: &mut lexpr::cons::ListIter<'a>,
61) -> Result<&'a str, String> {
62    return next_item(iter)?
63        .as_symbol()
64        .ok_or_else(|| "Expected a symbol".to_string());
65}
66
67fn iter_finish(iter: lexpr::cons::ListIter<'_>) -> Result<(), String> {
68    if !iter.is_empty() {
69        Err("Unexpected extra args while parsing form".to_string())
70    } else {
71        Ok(())
72    }
73}
74
75fn begin(
76    mut graph: &mut ShaderGraph,
77    env: &mut Env,
78    sexp: &Value,
79) -> Result<(), String> {
80    for declaration in into_iter(sexp)? {
81        declare(&mut graph, env, declaration)?;
82    }
83
84    Ok(())
85}
86
87fn declare(
88    graph: &mut ShaderGraph,
89    env: &mut Env,
90    sexp: &Value,
91) -> Result<(), String> {
92    let mut iter = into_iter(sexp)?;
93    let keyword = next_symbol(&mut iter)?;
94
95    match keyword {
96        "input" => {
97            let var = next_symbol(&mut iter)?;
98            let input = graph.add_input();
99            env.set(var.to_string(), Val::Node(input));
100        },
101        "output" => {
102            let id = next_symbol(&mut iter)?;
103            graph.mark_output(env.get(id)?.to_node()?);
104        },
105        "define" => {
106            // get the form defining the signature
107            let list = next_item(&mut iter)?;
108            let mut signature = into_iter(list)?;
109            let name = next_symbol(&mut signature)?;
110
111            // extract all the arguments
112            let mut args = vec![];
113            for arg in signature {
114                args.push(
115                    arg.as_symbol()
116                        .ok_or_else(|| {
117                            "Expected symbol in signature".to_string()
118                        })?
119                        .to_string(),
120                );
121            }
122
123            let forms: Vec<Value> = iter.map(|f| f.to_owned()).collect();
124            if forms.is_empty() {
125                return Err(format!(
126                    "Definition `{}` must have at least one expression in body",
127                    name
128                ));
129            }
130            env.set_fn(name.to_string(), (args, forms));
131            return Ok(());
132        },
133        "let" => {
134            let var = next_symbol(&mut iter)?;
135            let val = expr(graph, env, next_item(&mut iter)?)?;
136            env.set(var.to_string(), val);
137        },
138        "repeat" => {
139            let times = expr(graph, env, next_item(&mut iter)?)?.to_nat()?;
140            let forms: Vec<Value> = iter.map(|f| f.to_owned()).collect();
141            for _ in 0..times {
142                for form in forms.iter() {
143                    declare(graph, env, form)?;
144                }
145            }
146            return Ok(());
147        },
148        other => {
149            return Err(format!(
150                "Expected a statement keyword, found `{}`",
151                other
152            ))
153        },
154    }
155
156    iter_finish(iter)
157}
158
159fn expr(
160    graph: &mut ShaderGraph,
161    env: &mut Env,
162    value: &Value,
163) -> Result<Val, String> {
164    let val = match value {
165        Value::Number(n) => {
166            if let Some(float) = n.as_f64() {
167                Val::Number(float)
168            } else {
169                return Err("unexpected number type".to_string());
170            }
171        },
172
173        Value::Bool(b) => Val::Bool(*b),
174        Value::String(_) => Val::String(value.as_str().unwrap().to_string()),
175        Value::Symbol(_) => env.get(value.as_symbol().unwrap())?.clone(),
176
177        x if x.is_list() => node(graph, env, x)?,
178
179        other => return Err(format!("unexpected value `{}`", other)),
180    };
181
182    Ok(val)
183}
184
185fn shader(
186    graph: &mut ShaderGraph,
187    env: &mut Env,
188    mut iter: lexpr::cons::ListIter<'_>,
189) -> Result<(String, u32, u32, Vec<NodeId>), String> {
190    let name = expr(graph, env, next_item(&mut iter)?)?.to_string()?;
191    let width = expr(graph, env, next_item(&mut iter)?)?.to_nat()?;
192    let height = expr(graph, env, next_item(&mut iter)?)?.to_nat()?;
193    let mut inputs = vec![];
194    for remaining in iter {
195        let node_id = expr(graph, env, remaining)?.to_node()?;
196        inputs.push(node_id);
197    }
198    Ok((name, width as u32, height as u32, inputs))
199}
200
201fn external(
202    graph: &mut ShaderGraph,
203    env: &mut Env,
204    mut iter: lexpr::cons::ListIter<'_>,
205) -> Result<(String, Vec<NodeId>), String> {
206    let name = expr(graph, env, next_item(&mut iter)?)?.to_string()?;
207    let mut inputs = vec![];
208    for remaining in iter {
209        let node_id = expr(graph, env, remaining)?.to_node()?;
210        inputs.push(node_id);
211    }
212    Ok((name, inputs))
213}
214
215fn node(
216    graph: &mut ShaderGraph,
217    env: &mut Env,
218    sexp: &Value,
219) -> Result<Val, String> {
220    let mut iter = into_iter(sexp)?;
221    let function = next_symbol(&mut iter)?;
222
223    match function {
224        "shader" => {
225            let (name, width, height, inputs) = shader(graph, env, iter)?;
226            let node_id = graph.add_shader(
227                env.shader(&name)?,
228                inputs,
229                width as u32,
230                height as u32,
231            )?;
232            Ok(Val::Node(node_id))
233        },
234        "shader-param" => {
235            // get the shader we'll be running the transformations
236            // against
237            let decl = into_iter(next_item(&mut iter)?)?;
238            let (name, width, height, inputs) = shader(graph, env, decl)?;
239            let mut source = env.shader(&name)?.to_string();
240
241            // parse the substitutions to be applied
242            // let mut subst = vec![];
243            for form in iter {
244                source = subst(graph, env, form, source)?;
245            }
246
247            let node_id = graph.add_shader(
248                &source,
249                inputs,
250                width as u32,
251                height as u32,
252            )?;
253            Ok(Val::Node(node_id))
254        },
255        "shader-rec" => {
256            let (name, width, height, inputs) = shader(graph, env, iter)?;
257            let node_id = graph.add_rec_shader(
258                env.shader(&name)?,
259                inputs,
260                width as u32,
261                height as u32,
262            )?;
263            Ok(Val::Node(node_id))
264        },
265        "extern" => {
266            let (name, inputs) = external(graph, env, iter)?;
267            let adder = env.external(&name)?;
268            let node_id = adder(graph, &inputs).map_err(|e| {
269                format!("While adding external function `{}`: {}", name, e)
270            })?;
271            Ok(Val::Node(node_id))
272        },
273        user_defined => {
274            // evaluate the arguments (pass by value)
275            let mut args = vec![];
276            for arg in iter {
277                args.push(expr(graph, env, arg)?);
278            }
279
280            if let Some(val) = builtin(user_defined, &args) {
281                return val;
282            }
283
284            // get the function
285            let (params, body) = env.get_fn(user_defined)?.clone();
286
287            // check things match up before calling
288            if params.len() != args.len() {
289                return Err(format!(
290                    "function `{}` expected {} args, but found {}",
291                    user_defined,
292                    params.len(),
293                    args.len(),
294                ));
295            }
296
297            // evaluate in new scope, declare arguments
298            // recursive definitions will bap the stack, so please don't
299            // write them
300            env.enter_scope();
301            for (name, val) in params.iter().zip(args.iter()) {
302                env.set(name.to_string(), val.to_owned())
303            }
304
305            // unwrap is ok because length is checked when adding
306            // definiton
307            let last = body.last().unwrap();
308            let declarations = &body[..body.len() - 1];
309            for declaration in declarations {
310                declare(graph, env, declaration)?;
311            }
312
313            // TODO: multiple returns how?
314            // last value must be an expression, return it
315            let ret = expr(graph, env, last)?.to_node()?;
316            env.exit_scope();
317            Ok(Val::Node(ret))
318        },
319    }
320}
321
322fn builtin(name: &str, args: &[Val]) -> Option<Result<Val, String>> {
323    let result: fn(Vec<f64>) -> Val = match name {
324        "+" => |n| Val::Number(n.into_iter().sum()),
325        "-" => |n| {
326            let iter = n.into_iter();
327            Val::Number(iter.reduce(|a, b| a - b).unwrap_or(0.0))
328        },
329        "*" => |n| Val::Number(n.into_iter().product()),
330        "/" => |n| {
331            let iter = n.into_iter();
332            Val::Number(iter.reduce(|a, b| a / b).unwrap_or(1.0))
333        },
334        _ => {
335            return None;
336        },
337    };
338
339    let numbers = args
340        .iter()
341        .map(|v| v.to_float())
342        .collect::<Result<Vec<f64>, _>>();
343
344    let numbers = match numbers {
345        Err(e) => {
346            return Some(Err(e));
347        },
348        Ok(ok) => ok,
349    };
350
351    Some(Ok(result(numbers)))
352}
353
354fn subst(
355    graph: &mut ShaderGraph,
356    env: &mut Env,
357    form: &Value,
358    source: String,
359) -> Result<String, String> {
360    let mut subst_iter = into_iter(form)?;
361    let op = next_symbol(&mut subst_iter)?;
362
363    let (name, subst) = match op {
364        "define" => {
365            let name =
366                expr(graph, env, next_item(&mut subst_iter)?)?.to_string()?;
367            let val =
368                expr(graph, env, next_item(&mut subst_iter)?)?.to_string()?;
369            let subst = format!("#define {} {}", name, val);
370            (name, subst)
371        },
372        "ifdef" => {
373            let name =
374                expr(graph, env, next_item(&mut subst_iter)?)?.to_string()?;
375            let should_define =
376                expr(graph, env, next_item(&mut subst_iter)?)?.to_bool()?;
377            if should_define {
378                (name.clone(), format!("#define {} 1", name))
379            } else {
380                (name, String::new())
381            }
382        },
383        other => {
384            return Err(format!("Invalid param substitution type `{}`", other));
385        },
386    };
387
388    iter_finish(subst_iter)?;
389    return Ok(source.replace(&format!("<{}>", name), &subst));
390}