{% macro render_transformer(language) -%}
{%- set transformer = model.ir_languages[language].transformer -%}
{%- set target = model.ir_languages[language].target -%}
// Transformer from previous language implementation
#![allow(clippy::too_many_lines)]
use std::rc::Rc;
use super::{input, nodes as output};
#[allow(unused)]
use crate::cst::TerminalNode;
pub trait Transformer {
//
// Sequences:
//
{% for parent_type, sequence in transformer.sequences %}
fn transform_{{ parent_type | snake_case }}(&mut self, source: &input::{{ parent_type }}) -> output::{{ parent_type }}
{% if not sequence.has_added_fields %}
{
{% for field in sequence.fields %}
{%- if not field.is_removed -%}
let {{ field.label }} =
{%- if field.is_optional -%}
{%- if field.type.kind == "Terminal" -%}
source.{{ field.label }}.as_ref().map(Rc::clone);
{%- elif field.type.kind == "UniqueTerminal" -%}
source.{{ field.label }};
{%- else -%}
source.{{ field.label }}.as_ref().map(
|value| self.transform_{{ field.type.name | snake_case }}(value)
);
{%- endif -%}
{%- else -%}
{%- if field.type.is_terminal -%}
Rc::clone(&source.{{ field.label }});
{%- else -%}
self.transform_{{ field.type.name | snake_case }}(&source.{{ field.label }});
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endfor %}
Rc::new(output::{{ parent_type }}Struct {
node_id: source.node_id,
{%- for field in sequence.fields -%}
{%- if not field.is_removed -%}
{{ field.label }},
{%- endif -%}
{%- endfor %}
})
}
{% else %}
;
{% endif %}
{% endfor %}
//
// Collapsed sequences:
//
{% for parent_type, collapsed in transformer.collapsed_sequences %}
fn transform_{{ parent_type | snake_case }}(&mut self, source: &input::{{ parent_type }}) ->
{%- if collapsed.target_type.is_terminal -%}
Rc<TerminalNode>
{%- else -%}
output::{{ collapsed.target_type.name }}
{%- endif -%}
{
{%- if collapsed.target_type.is_terminal -%}
Rc::clone(&source.{{ collapsed.label }})
{%- else -%}
self.transform_{{ collapsed.type.name | snake_case }}(&source.{{ collapsed.label }})
{%- endif -%}
}
{% endfor %}
//
// Choices:
//
{% for parent_type, choice in transformer.choices %}
{% if not choice.is_new -%}
fn default_transform_{{ parent_type | snake_case }}(&mut self, source: &input::{{ parent_type }}) -> output::{{ parent_type }} {
#[allow(clippy::match_wildcard_for_single_variants)]
#[allow(clippy::match_single_binding)]
match source {
{% for nonterminal in choice.variants | filter(attribute="kind", value="Nonterminal") -%}
input::{{ parent_type }}::{{ nonterminal.name }}(ref {{ nonterminal.name | snake_case }}) => {
output::{{ parent_type }}::{{ nonterminal.name }}(self.transform_{{ nonterminal.name | snake_case }}({{ nonterminal.name | snake_case }}))
}
{%- endfor -%}
{% for terminal in choice.variants | filter(attribute="kind", value="Terminal") -%}
input::{{ parent_type }}::{{ terminal.name }}(node) => output::{{ parent_type }}::{{ terminal.name }}(Rc::clone(node)),
{%- endfor -%}
{% for terminal in choice.variants | filter(attribute="kind", value="UniqueTerminal") -%}
input::{{ parent_type }}::{{ terminal.name }} => output::{{ parent_type }}::{{ terminal.name }},
{%- endfor -%}
{% if choice.has_removed_variants %}
_ => panic!("Unexpected variant {source:?}"),
{% endif %}
}
}
fn transform_{{ parent_type | snake_case }}(&mut self, source: &input::{{ parent_type }}) -> output::{{ parent_type }} {
self.default_transform_{{ parent_type | snake_case }}(source)
}
{%- endif %}
{% endfor %}
//
// Repeated & Separated
//
{% for parent_type, collection in transformer.collections %}
{% if not collection.is_new -%}
fn transform_{{ parent_type | snake_case }}(&mut self, source: &input::{{ parent_type }}) -> output::{{ parent_type }} {
source.iter().map(
{%- if collection.item_type.is_terminal -%}
Rc::clone
{%- else -%}
|item| self.transform_{{ collection.item_type.name | snake_case }}(item)
{%- endif -%}
).collect()
}
{%- endif %}
{% endfor %}
}
{% endmacro render_transformer %}