 #![allow(unused, unused_imports, non_snake_case, unused_parens)]

// generate imports, pointing to userland cartridge `pub mod pax_reexports`
{% for import in imports %}
use {{ import }};
{% endfor %}

//pull in entire const token stream here e.g. `const JABBERWOCKY : &str = r#"’Twas brillig, and the slithy toves `...
{% for const in consts %}
    {{ const }}
{% endfor %}

pub fn instantiate_expression_table<R: 'static + RenderContext>() -> HashMap<usize, Box<dyn Fn(ExpressionContext<R>) -> TypesCoproduct>> {
    let mut vtable: HashMap<usize, Box<dyn Fn(ExpressionContext<R>) -> TypesCoproduct>> = HashMap::new();

    {% for expression_spec in expression_specs %}
    //{{ expression_spec.input_statement}}
    vtable.insert({{ expression_spec.id }}, Box::new(|ec: ExpressionContext<R>| -> TypesCoproduct {
        {% for invocation in expression_spec.invocations %}
            let {{ invocation.escaped_identifier }} =
            {
                let properties = if let Some(sf) = (*ec.stack_frame).borrow().peek_nth({{ invocation.stack_offset }}) {
                    Rc::clone(&sf)
                } else {
                    Rc::clone(&ec.stack_frame)
                }.borrow().deref().get_properties();
                let properties = &*(*properties).borrow();
                {% if invocation.property_flags.is_binding_repeat_elem %}
                    //binding repeat elem
                    if let PropertiesCoproduct::RepeatItem(elem, i) = properties {
                        {% if invocation.is_numeric %}
                            //iterable numeric
                            {# For known numeric primitives, we can safely deref-copy and wrap in Numeric #}
                            let unwrapped = if let PropertiesCoproduct::{{invocation.iterable_type_id_escaped}}(i) = **elem {i} else {unreachable!()};
                            Numeric::from(unwrapped)
                        {% elif invocation.is_primitive_nonnumeric %}
                            //iterable primitive non-numeric
                            elem.clone()
                        {% else %}
                            //iterable complex type
                            if let PropertiesCoproduct::{{invocation.iterable_type_id_escaped}}(ict) = elem.deref() {
                                ict.clone()
                            } else {unreachable!()}
                        {% endif %}
                    } else {unreachable!()}
                {% elif invocation.property_flags.is_binding_repeat_i %}
                    //binding repeat i
                    if let PropertiesCoproduct::RepeatItem(_, i) = properties {
                        Numeric::from(*i)
                    } else {unreachable!()}
                {% else %}
                    if let PropertiesCoproduct::{{ invocation.properties_coproduct_type }}(p) = properties {
                        {% if invocation.is_numeric %}
                            //binding simple numeric property
                            Numeric::from(p.{{invocation.root_identifier}}.get())
                        {% else %}
                            //binding cloneable property
                            p.{{invocation.root_identifier}}.get().clone()
                        {% endif %}
                    } else {unreachable!()}
                {% endif %}
            }{{ invocation.nested_symbol_tail_literal }};
            {% if invocation.is_nested_numeric %}
                let {{ invocation.escaped_identifier }} = Numeric::from( {{ invocation.escaped_identifier }} );
            {% endif %}

        {% endfor %}

        {% if expression_spec.is_repeat_source_iterable_expression %}
            {# We have a Vec<T> and we need to rewrap it into a Vec<Rc<PropertiesCoproduct>> for Repeat #}
            {% for invocation in expression_spec.invocations %}
                let {{ invocation.escaped_identifier }} = {{ invocation.escaped_identifier }}.iter().map(|t|{
                    Rc::new(PropertiesCoproduct::{{expression_spec.repeat_source_iterable_type_id_escaped}}(t.clone()))
                }).collect::<Vec<Rc<PropertiesCoproduct>>>();
            {% endfor %}
        {% endif %}

        TypesCoproduct::{{ expression_spec.pascalized_return_type }}(
            {{ expression_spec.output_statement }}
        )
    }));
    {% endfor %}

    vtable
}

//Begin component factory literals
{% for factory_literal in component_factories_literal %}
    {{ factory_literal }}
{% endfor %}