{%- set target = model.ir_languages['ir2_flat_contracts'].target -%}
{%- set custom_types = ["Identifier", "YulIdentifier"] -%}
#![allow(unused)]
use std::rc::Rc;
use paste::paste;
use super::input as input_ir;
use crate::backend::{binder, SemanticAnalysis};
use crate::cst::{NodeId, TerminalKind, TerminalNode, TextIndex};
use super::node_extensions::{Identifier, IdentifierStruct, YulIdentifier, YulIdentifierStruct};
use super::node_extensions::{create_identifier, create_yul_identifier};
use super::Type;
//
// Sequences:
//
{% for parent_type, sequence in target.sequences %}
pub type {{ parent_type }} = Rc<{{ parent_type }}Struct>;
pub struct {{ parent_type }}Struct {
pub(crate) ir_node: input_ir::{{ parent_type }},
pub(crate) semantic: Rc<SemanticAnalysis>,
}
pub(crate) fn create_{{ parent_type | snake_case }}(
ir_node: &input_ir::{{ parent_type }},
semantic: &Rc<SemanticAnalysis>,
) -> {{ parent_type }} {
Rc::new({{ parent_type }}Struct {
ir_node: Rc::clone(ir_node),
semantic: Rc::clone(semantic),
})
}
impl {{ parent_type }}Struct {
pub fn node_id(&self) -> NodeId {
self.ir_node.node_id
}
{% for field in sequence.fields -%}
{% if field.is_optional %}
{% if custom_types is containing(field.type.name) or
target.sequences is containing(field.type.name) or
target.choices is containing(field.type.name) %}
pub fn {{ field.label }}(&self) -> Option<{{ field.type.name }}> {
self.ir_node.{{ field.label }}.as_ref().map(|ir_node| {
create_{{ field.type.name | snake_case }}(ir_node, &self.semantic)
})
}
{% elif field.type.kind == "UniqueTerminal" %}
pub fn {{ field.label }}(&self) -> bool {
self.ir_node.{{ field.label }}
}
{% elif field.type.is_terminal %}
pub fn {{ field.label }}(&self) -> Option<Rc<TerminalNode>> {
self.ir_node.{{ field.label }}.as_ref().map(Rc::clone)
}
{% elif target.collections is containing(field.type.name) %}
{% set item_type = target.collections[field.type.name].item_type %}
{% if custom_types is containing(item_type.name) or not item_type.is_terminal %}
pub fn {{ field.label }}(&self) -> Option<{{ field.type.name }}> {
self.ir_node.{{ field.label }}.as_ref().map(|ir_node| {
create_{{ field.type.name | snake_case }}(ir_node, &self.semantic)
})
}
{% elif item_type.is_terminal %}
pub fn {{ field.label }}(&self) -> Option<Vec<Rc<TerminalNode>>> {
self.ir_node.{{ field.label }}.as_ref().map(|items| items.clone())
}
{% endif -%}
{% endif %}
{% else %}
{% if custom_types is containing(field.type.name) or
target.sequences is containing(field.type.name) or
target.choices is containing(field.type.name) %}
pub fn {{ field.label }}(&self) -> {{ field.type.name }} {
create_{{ field.type.name | snake_case }}(&self.ir_node.{{ field.label }}, &self.semantic)
}
{% elif field.type.is_terminal %}
pub fn {{ field.label }}(&self) -> Rc<TerminalNode> {
Rc::clone(&self.ir_node.{{ field.label }})
}
{% elif target.collections is containing(field.type.name) %}
{% set item_type = target.collections[field.type.name].item_type %}
{% if custom_types is containing(item_type.name) or not item_type.is_terminal %}
pub fn {{ field.label }}(&self) -> {{ field.type.name }} {
create_{{ field.type.name | snake_case }}(&self.ir_node.{{ field.label }}, &self.semantic)
}
{% elif item_type.is_terminal %}
pub fn {{ field.label }}(&self) -> Vec<Rc<TerminalNode>> {
self.ir_node.{{ field.label }}.clone()
}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
pub fn text_offset(&self) -> TextIndex {
self.semantic.get_text_offset_by_node_id(self.ir_node.node_id).unwrap()
}
pub fn get_type(&self) -> Option<Type> {
self.semantic.get_type_from_node_id(self.ir_node.node_id)
}
}
{% endfor %}
//
// Choices:
//
{% for parent_type, choice in target.choices %}
pub enum {{ parent_type }} {
{% for variant in choice.variants -%}
{{ variant.name }}
{%- if custom_types is containing(variant.name) or
target.sequences is containing(variant.name) or
target.choices is containing(variant.name) -%}
({{ variant.name }})
{%- elif target.collections is containing(variant.name) -%}
{% set item_type = target.collections[variant.name].item_type %}
{% if custom_types is containing(item_type.name) or
target.sequences is containing(item_type.name) or
target.choices is containing(item_type.name) %}
({{ variant.name }})
{% elif variant.kind != "UniqueTerminal" %}
(Vec<Rc<TerminalNode>>)
{% endif %}
{% elif variant.kind != "UniqueTerminal" %}
(Rc<TerminalNode>)
{%- endif -%}
,
{%- endfor -%}
}
#[allow(clippy::too_many_lines)]
pub(crate) fn create_{{ parent_type | snake_case }}(
ir_node: &input_ir::{{ parent_type }},
semantic: &Rc<SemanticAnalysis>,
) -> {{ parent_type }}{
match ir_node {
{% for variant in choice.variants -%}
input_ir::{{ parent_type }}::{{ variant.name }}
{%- if custom_types is containing(variant.name) or
target.sequences is containing(variant.name) or
target.choices is containing(variant.name) -%}
(variant) => {{ parent_type }}::{{ variant.name }}(
create_{{ variant.name | snake_case }}(variant, semantic)
),
{%- elif target.collections is containing(variant.name) -%}
{% set item_type = target.collections[variant.name].item_type %}
{% if custom_types is containing(item_type.name) or
target.sequences is containing(item_type.name) or
target.choices is containing(item_type.name) %}
(nodes) => {{ parent_type }}::{{ variant.name }}(
create_{{ variant.name | snake_case }}(nodes, semantic)
),
{% else %}
(nodes) => {{ parent_type }}::{{ variant.name }}(nodes.clone()),
{% endif %}
{% elif variant.kind != "UniqueTerminal" %}
(node) => {{ parent_type }}::{{ variant.name }}(Rc::clone(node)),
{%- else -%}
=> {{ parent_type }}::{{ variant.name }},
{%- endif -%}
{%- endfor %}
}
}
{% endfor %}
//
// Repeated & Separated
//
{%- for parent_type, collection in target.collections %}
{# Declare types only for collections of non-terminals *or* custom-type terminals #}
{%- if collection.item_type.is_terminal and custom_types is containing(collection.item_type.name) %}
{% set ir_type = "Rc<TerminalNode>" %}
{% elif not collection.item_type.is_terminal %}
{% set ir_type = "input_ir::" ~ collection.item_type.name %}
{% endif -%}
{%- if ir_type is defined %}
pub type {{ parent_type }} = Rc<{{ parent_type }}Struct>;
pub(crate) fn create_{{ parent_type | snake_case }}(
nodes: &[{{ ir_type }}],
semantic: &Rc<SemanticAnalysis>,
) -> {{ parent_type }} {
Rc::new({{ parent_type }}Struct {
ir_nodes: nodes.to_vec(),
semantic: Rc::clone(semantic),
})
}
pub struct {{ parent_type }}Struct {
pub(crate) ir_nodes: Vec<{{ ir_type }}>,
pub(crate) semantic: Rc<SemanticAnalysis>,
}
impl {{ parent_type }}Struct {
pub fn iter(&self) -> impl Iterator<Item = {{ collection.item_type.name }}> + use<'_> {
self.ir_nodes
.iter()
.map(|ir_node| create_{{ collection.item_type.name | snake_case }}(ir_node, &self.semantic))
}
pub fn len(&self) -> usize {
self.ir_nodes.len()
}
pub fn is_empty(&self) -> bool {
self.ir_nodes.is_empty()
}
}
{% endif -%}
{% endfor -%}