{% macro render_rewriter(language) -%}
{%- set target = model.ir_languages[language].target -%}
#![allow(clippy::too_many_lines)]
use std::rc::Rc;
#[allow(clippy::wildcard_imports)]
use super::nodes::*;
pub trait Rewriter {
//
// Sequences:
//
{% for parent_type, sequence in target.sequences %}
fn rewrite_{{ parent_type | snake_case }}(&mut self, source: &{{ parent_type }}) -> {{ parent_type }} {
{% for field in sequence.fields %}
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.rewrite_{{ field.type.name | snake_case }}(value)
);
{%- endif -%}
{%- else -%}
{%- if field.type.is_terminal -%}
Rc::clone(&source.{{ field.label }});
{%- else -%}
self.rewrite_{{ field.type.name | snake_case }}(&source.{{ field.label }});
{%- endif -%}
{%- endif -%}
{%- endfor %}
Rc::new({{ parent_type }}Struct {
node_id: source.node_id,
{%- for field in sequence.fields -%}
{{ field.label }},
{%- endfor %}
})
}
{% endfor %}
//
// Choices:
//
{% for parent_type, choice in target.choices %}
fn default_rewrite_{{ parent_type | snake_case }}(&mut self, source: &{{ parent_type }}) -> {{ parent_type }} {
match source {
{% for nonterminal in choice.variants | filter(attribute="kind", value="Nonterminal") -%}
{{ parent_type }}::{{ nonterminal.name }}(ref {{ nonterminal.name | snake_case }}) => {
{{ parent_type }}::{{ nonterminal.name }}(self.rewrite_{{ nonterminal.name | snake_case }}({{ nonterminal.name | snake_case }}))
}
{%- endfor %}
{% for terminal in choice.variants | filter(attribute="kind", value="Terminal") -%}
{{ parent_type }}::{{ terminal.name }}(node) => {{ parent_type }}::{{ terminal.name }}(Rc::clone(node)),
{%- endfor -%}
{% for terminal in choice.variants | filter(attribute="kind", value="UniqueTerminal") -%}
{{ parent_type }}::{{ terminal.name }} => {{ parent_type }}::{{ terminal.name }},
{%- endfor -%}
}
}
fn rewrite_{{ parent_type | snake_case }}(&mut self, source: &{{ parent_type }}) -> {{ parent_type }} {
self.default_rewrite_{{ parent_type | snake_case }}(source)
}
{% endfor %}
//
// Repeated & Separated
//
{% for parent_type, collection in target.collections %}
fn rewrite_{{ parent_type | snake_case }}(&mut self, source: &{{ parent_type }}) -> {{ parent_type }} {
source.iter().map(
{%- if collection.item_type.is_terminal -%}
Rc::clone
{%- else -%}
|item| self.rewrite_{{ collection.item_type.name | snake_case }}(item)
{%- endif -%}
).collect()
}
{% endfor %}
}
{% endmacro render_rewriter %}