Skip to content

Instantly share code, notes, and snippets.

@Yatekii
Created May 22, 2018 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Yatekii/90341b4539ac6b0482c9b33708210e84 to your computer and use it in GitHub Desktop.
Save Yatekii/90341b4539ac6b0482c9b33708210e84 to your computer and use it in GitHub Desktop.
pub fn render(library: &Library, state: &mut State, mut stack: Vec<String>, expression: &mut Expression) -> Expression {
match expression {
// We have a symbolic expression that we have to evaluate
Expression::Symbolic(ref mut args) | Expression::NotDone(ref mut args) => {
// If we have a valid expression (unnamed ones are not allowed)
if args.len() > 0 {
// Get the first nested expression
return match args.remove(0) {
// If the first expression is a plain literal
Expression::Literal(Literal::S(name)) => {
// Try render all nested expressions
let possibly_rendered_args: Vec<Expression> = args.into_iter().map(|arg| {
stack.push(name.clone());
let rendered = render(library, state, stack.clone(), arg);
rendered
}).collect();
let rendered_args: Vec<&Expression> = possibly_rendered_args.iter().filter(|expr| if let Expression::Done(_) = expr { true } else { false }).collect();
// If all child nodes are already rendered
if rendered_args.len() == args.len() {
// Render the parent if the environment is known
if let Some(renderer) = library.search_environment(name.clone()) {
// Unpack the rendered children
let rendered_args = rendered_args.iter().map(|arg| {
if let Expression::Done(rendered) = arg {
rendered.clone()
} else {
"".to_owned()
}
}).collect();
*expression = renderer(state, stack, rendered_args);
} else {
// Even tho we failed, mark the expression as done processing
println!("Environment {} is not known to the renderer.", name.clone());
*expression = Expression::Done(format!("{{environment {} is not known to the renderer}}", name.clone()).into());
}
return expression.clone()
} else {
// Not all child nodes are already rendered
// Store the rendered ones
let n = possibly_rendered_args.len();
for i in 0..n {
args[i] = possibly_rendered_args[i].clone();
}
args.insert(0, Expression::Literal(Literal::S(name)));
// Signalize we have to reprocess this again
Expression::NotDone(args.clone())
}
},
// Name of the symbolic expression is not a literal
_ => panic!("Symbolic expressions can't name a symbolic expression")
}
}
panic!("Unnamed expressions are not allowed.");
},
// We can immediately mark the expression as resolved,
// as we already have a literal that doesn't have to be processed
Expression::Literal(l) => match l {
Literal::S(s) => Expression::Done(s.to_owned())
}
// If expression is already done, just return it
Expression::Done(_s) => expression.clone()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment