use crate::types::semantic::ExtendedExpression;
use nom_locate::LocatedSpan;
#[cfg(feature = "codec")]
use serde::{
de::{self, Deserializer, MapAccess, Visitor},
ser::{SerializeStruct, Serializer},
Deserialize, Serialize,
};
pub const MAX_PRIORITY_LEVEL_FOR_EXPRESSIONS: u8 = 9;
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
pub struct Ident<'a>(LocatedSpan<&'a str>);
impl<'a> Ident<'a> {
#[must_use]
pub fn new(ident: &'a str) -> Ident<'a> {
Self(LocatedSpan::new(ident))
}
#[must_use]
pub fn fragment(&self) -> &'a str {
self.0.fragment()
}
#[must_use]
pub fn location_line(&self) -> u32 {
self.0.location_line()
}
#[must_use]
pub fn location_offset(&self) -> usize {
self.0.location_offset()
}
}
impl<'a> std::fmt::Display for Ident<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.fragment())
}
}
impl<'a> From<&'a str> for Ident<'a> {
fn from(value: &'a str) -> Ident<'a> {
Ident::new(value)
}
}
#[cfg(feature = "codec")]
impl<'a> Serialize for Ident<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let fragment = self.0.into_fragment_and_extra();
let mut state = serializer.serialize_struct("Ident", 4)?;
state.serialize_field("offset", &self.0.location_offset())?;
state.serialize_field("line", &self.0.location_line())?;
state.serialize_field("fragment", &fragment.0)?;
state.serialize_field("extra", &fragment.1)?;
state.end()
}
}
#[cfg(feature = "codec")]
impl<'de: 'a, 'a> Deserialize<'de> for Ident<'a> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct IdentVisitor<'a> {
marker: std::marker::PhantomData<fn() -> Ident<'a>>,
}
impl<'de: 'a, 'a> Visitor<'de> for IdentVisitor<'a> {
type Value = Ident<'de>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("struct Ident")
}
fn visit_map<V>(self, mut map: V) -> Result<Ident<'de>, V::Error>
where
V: MapAccess<'de>,
{
let mut offset = None;
let mut line = None;
let mut fragment = None;
let mut extra = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"offset" => {
if offset.is_some() {
return Err(de::Error::duplicate_field("offset"));
}
offset = Some(map.next_value()?);
}
"line" => {
if line.is_some() {
return Err(de::Error::duplicate_field("line"));
}
line = Some(map.next_value()?);
}
"fragment" => {
if fragment.is_some() {
return Err(de::Error::duplicate_field("fragment"));
}
fragment = Some(map.next_value()?);
}
"extra" => {
if extra.is_some() {
return Err(de::Error::duplicate_field("extra"));
}
extra = Some(map.next_value()?);
}
_ => return Err(de::Error::unknown_field(&key, FIELDS)),
}
}
let offset = offset.ok_or_else(|| de::Error::missing_field("offset"))?;
let line = line.ok_or_else(|| de::Error::missing_field("line"))?;
let fragment = fragment.ok_or_else(|| de::Error::missing_field("fragment"))?;
#[allow(clippy::let_unit_value)]
let extra = extra.ok_or_else(|| de::Error::missing_field("extra"))?;
let located =
unsafe { LocatedSpan::new_from_raw_offset(offset, line, fragment, extra) };
Ok(Ident(located))
}
}
const FIELDS: &[&str] = &["offset", "line", "fragment", "extra"];
deserializer.deserialize_struct(
"Ident",
FIELDS,
IdentVisitor {
marker: std::marker::PhantomData,
},
)
}
}
pub trait GetName {
fn name(&self) -> String;
}
pub trait GetLocation {
fn location(&self) -> CodeLocation;
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct ImportName<'a>(#[cfg_attr(feature = "codec", serde(borrow))] Ident<'a>);
impl GetName for ImportName<'_> {
fn name(&self) -> String {
(*self.0.fragment()).to_string()
}
}
impl<'a> ImportName<'a> {
#[must_use]
pub const fn new(ident: Ident<'a>) -> Self {
Self(ident)
}
}
pub type ImportPath<'a> = Vec<ImportName<'a>>;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct ConstantName<'a>(#[cfg_attr(feature = "codec", serde(borrow))] Ident<'a>);
impl<'a> ConstantName<'a> {
#[must_use]
pub const fn new(name: Ident<'a>) -> Self {
Self(name)
}
}
impl GetLocation for ConstantName<'_> {
fn location(&self) -> CodeLocation {
CodeLocation::new(self.0.location_line(), self.0.location_offset())
}
}
impl GetName for ConstantName<'_> {
fn name(&self) -> String {
(*self.0.fragment()).to_string()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct FunctionName<'a>(#[cfg_attr(feature = "codec", serde(borrow))] Ident<'a>);
impl<'a> FunctionName<'a> {
#[must_use]
pub const fn new(name: Ident<'a>) -> Self {
Self(name)
}
}
impl GetLocation for FunctionName<'_> {
fn location(&self) -> CodeLocation {
CodeLocation::new(self.0.location_line(), self.0.location_offset())
}
}
impl<'a> std::fmt::Display for FunctionName<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.fragment())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct ParameterName<'a>(#[cfg_attr(feature = "codec", serde(borrow))] Ident<'a>);
impl<'a> ParameterName<'a> {
#[must_use]
pub const fn new(name: Ident<'a>) -> Self {
Self(name)
}
}
impl std::fmt::Display for ParameterName<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.fragment())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct ValueName<'a>(#[cfg_attr(feature = "codec", serde(borrow))] Ident<'a>);
impl<'a> ValueName<'a> {
#[must_use]
pub const fn new(name: Ident<'a>) -> Self {
Self(name)
}
}
impl GetLocation for ValueName<'_> {
fn location(&self) -> CodeLocation {
CodeLocation::new(self.0.location_line(), self.0.location_offset())
}
}
impl GetName for ValueName<'_> {
fn name(&self) -> String {
(*self.0.fragment()).to_string()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct CodeLocation(u32, usize);
impl CodeLocation {
#[must_use]
pub const fn new(location: u32, offset: usize) -> Self {
Self(location, offset)
}
#[must_use]
pub const fn line(&self) -> u32 {
self.0
}
#[must_use]
pub const fn offset(&self) -> usize {
self.1
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum PrimitiveTypes {
U8,
U16,
U32,
U64,
I8,
I16,
I32,
I64,
F32,
F64,
Bool,
Char,
String,
Ptr,
None,
}
impl GetName for PrimitiveTypes {
fn name(&self) -> String {
match self {
Self::U8 => "u8".to_string(),
Self::U16 => "u16".to_string(),
Self::U32 => "u32".to_string(),
Self::U64 => "u64".to_string(),
Self::I8 => "i8".to_string(),
Self::I16 => "i16".to_string(),
Self::I32 => "i32".to_string(),
Self::I64 => "i64".to_string(),
Self::F32 => "f32".to_string(),
Self::F64 => "f64".to_string(),
Self::Bool => "bool".to_string(),
Self::Char => "char".to_string(),
Self::String => "str".to_string(),
Self::Ptr => "ptr".to_string(),
Self::None => "()".to_string(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct ExpressionStructValue<'a> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub name: ValueName<'a>,
pub attribute: ValueName<'a>,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct StructType<'a> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub attr_name: Ident<'a>,
pub attr_type: Type<'a>,
}
impl GetName for StructType<'_> {
fn name(&self) -> String {
(*self.attr_name.fragment()).to_string()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct StructTypes<'a> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub name: Ident<'a>,
pub attributes: Vec<StructType<'a>>,
}
impl GetLocation for StructTypes<'_> {
fn location(&self) -> CodeLocation {
CodeLocation::new(self.name.location_line(), self.name.location_offset())
}
}
impl<'a> GetName for StructTypes<'a> {
fn name(&self) -> String {
(*self.name.fragment()).to_string()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum Type<'a> {
Primitive(PrimitiveTypes),
#[cfg_attr(feature = "codec", serde(borrow))]
Struct(StructTypes<'a>),
Array(Box<Self>, u32),
}
impl<'a> GetName for Type<'a> {
fn name(&self) -> String {
match self {
Self::Primitive(primitive) => primitive.name(),
Self::Struct(struct_type) => (*struct_type.name.fragment()).to_string(),
Self::Array(array_type, size) => {
format!("[{:?};{:?}]", array_type.name(), size)
}
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum ConstantValue<'a> {
#[cfg_attr(feature = "codec", serde(borrow))]
Constant(ConstantName<'a>),
Value(PrimitiveValue),
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct ConstantExpression<'a> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub value: ConstantValue<'a>,
pub operation: Option<(ExpressionOperations, Box<ConstantExpression<'a>>)>,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct Constant<'a> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub name: ConstantName<'a>,
pub constant_type: Type<'a>,
pub constant_value: ConstantExpression<'a>,
}
impl GetLocation for Constant<'_> {
fn location(&self) -> CodeLocation {
self.name.location()
}
}
impl GetName for Constant<'_> {
fn name(&self) -> String {
(*self.name.0.fragment()).to_string()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct FunctionParameter<'a> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub name: ParameterName<'a>,
pub parameter_type: Type<'a>,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct FunctionStatement<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub name: FunctionName<'a>,
pub parameters: Vec<FunctionParameter<'a>>,
pub result_type: Type<'a>,
pub body: Vec<BodyStatement<'a, E>>,
}
impl<E: ExtendedExpression> GetLocation for FunctionStatement<'_, E> {
fn location(&self) -> CodeLocation {
self.name.location()
}
}
impl<E: ExtendedExpression> GetName for FunctionStatement<'_, E> {
fn name(&self) -> String {
(*self.name.0.fragment()).to_string()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum PrimitiveValue {
U8(u8),
U16(u16),
U32(u32),
U64(u64),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
F32(f32),
F64(f64),
Bool(bool),
String(String),
Char(char),
Ptr,
None,
}
impl PrimitiveValue {
#[must_use]
pub const fn get_type(&self) -> Type<'_> {
match self {
Self::U8(_) => Type::Primitive(PrimitiveTypes::U8),
Self::U16(_) => Type::Primitive(PrimitiveTypes::U16),
Self::U32(_) => Type::Primitive(PrimitiveTypes::U32),
Self::U64(_) => Type::Primitive(PrimitiveTypes::U64),
Self::I8(_) => Type::Primitive(PrimitiveTypes::I8),
Self::I16(_) => Type::Primitive(PrimitiveTypes::I16),
Self::I32(_) => Type::Primitive(PrimitiveTypes::I32),
Self::I64(_) => Type::Primitive(PrimitiveTypes::I64),
Self::F32(_) => Type::Primitive(PrimitiveTypes::F32),
Self::F64(_) => Type::Primitive(PrimitiveTypes::F64),
Self::Char(_) => Type::Primitive(PrimitiveTypes::Char),
Self::Bool(_) => Type::Primitive(PrimitiveTypes::Bool),
Self::String(_) => Type::Primitive(PrimitiveTypes::String),
Self::Ptr => Type::Primitive(PrimitiveTypes::Ptr),
Self::None => Type::Primitive(PrimitiveTypes::None),
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum ExpressionValue<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
ValueName(ValueName<'a>),
PrimitiveValue(PrimitiveValue),
FunctionCall(FunctionCall<'a, E>),
StructValue(ExpressionStructValue<'a>),
Expression(Box<Expression<'a, E>>),
ExtendedExpression(Box<E>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum ExpressionOperations {
Plus,
Minus,
Multiply,
Divide,
ShiftLeft,
ShiftRight,
And,
Or,
Xor,
Eq,
NotEq,
Great,
Less,
GreatEq,
LessEq,
}
impl ExpressionOperations {
#[must_use]
pub const fn priority(&self) -> u8 {
match self {
Self::Plus => 5,
Self::Minus => 4,
Self::Divide => 8,
Self::Multiply | Self::ShiftLeft | Self::ShiftRight => {
MAX_PRIORITY_LEVEL_FOR_EXPRESSIONS
}
Self::Or | Self::Xor => 6,
Self::And
| Self::Eq
| Self::NotEq
| Self::Great
| Self::Less
| Self::GreatEq
| Self::LessEq => 7,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct Expression<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub expression_value: ExpressionValue<'a, E>,
pub operation: Option<(ExpressionOperations, Box<Expression<'a, E>>)>,
}
impl<E: ExtendedExpression> GetLocation for Expression<'_, E> {
fn location(&self) -> CodeLocation {
CodeLocation::new(1, 0)
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize), serde(tag = "type"))]
pub struct LetBinding<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub name: ValueName<'a>,
pub mutable: bool,
pub value_type: Option<Type<'a>>,
pub value: Box<Expression<'a, E>>,
}
impl<E: ExtendedExpression> GetLocation for LetBinding<'_, E> {
fn location(&self) -> CodeLocation {
self.name.location()
}
}
impl<E: ExtendedExpression> GetName for LetBinding<'_, E> {
fn name(&self) -> String {
self.name.0.to_string()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct Binding<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub name: ValueName<'a>,
pub value: Box<Expression<'a, E>>,
}
impl<E: ExtendedExpression> GetLocation for Binding<'_, E> {
fn location(&self) -> CodeLocation {
self.name.location()
}
}
impl<E: ExtendedExpression> GetName for Binding<'_, E> {
fn name(&self) -> String {
self.name.0.to_string()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct FunctionCall<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub name: FunctionName<'a>,
pub parameters: Vec<Expression<'a, E>>,
}
impl<E: ExtendedExpression> GetLocation for FunctionCall<'_, E> {
fn location(&self) -> CodeLocation {
self.name.location()
}
}
impl<E: ExtendedExpression> GetName for FunctionCall<'_, E> {
fn name(&self) -> String {
(*self.name.0.fragment()).to_string()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum Condition {
Great,
Less,
Eq,
GreatEq,
LessEq,
NotEq,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum LogicCondition {
And,
Or,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct ExpressionCondition<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub left: Expression<'a, E>,
pub condition: Condition,
pub right: Expression<'a, E>,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct ExpressionLogicCondition<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub left: ExpressionCondition<'a, E>,
pub right: Option<(LogicCondition, Box<ExpressionLogicCondition<'a, E>>)>,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum IfCondition<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
Single(Expression<'a, E>),
Logic(ExpressionLogicCondition<'a, E>),
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
pub struct IfStatement<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
pub condition: IfCondition<'a, E>,
pub body: IfBodyStatements<'a, E>,
pub else_statement: Option<IfBodyStatements<'a, E>>,
pub else_if_statement: Option<Box<IfStatement<'a, E>>>,
}
impl<E: ExtendedExpression> GetLocation for IfStatement<'_, E> {
fn location(&self) -> CodeLocation {
CodeLocation::new(1, 0)
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum BodyStatement<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
LetBinding(LetBinding<'a, E>),
Binding(Binding<'a, E>),
FunctionCall(FunctionCall<'a, E>),
If(IfStatement<'a, E>),
Loop(Vec<LoopBodyStatement<'a, E>>),
Expression(Expression<'a, E>),
Return(Expression<'a, E>),
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum IfBodyStatement<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
LetBinding(LetBinding<'a, E>),
Binding(Binding<'a, E>),
FunctionCall(FunctionCall<'a, E>),
If(IfStatement<'a, E>),
Loop(Vec<LoopBodyStatement<'a, E>>),
Return(Expression<'a, E>),
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "codec", serde(tag = "type", content = "content"))]
pub enum IfLoopBodyStatement<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
LetBinding(LetBinding<'a, E>),
Binding(Binding<'a, E>),
FunctionCall(FunctionCall<'a, E>),
If(IfStatement<'a, E>),
Loop(Vec<LoopBodyStatement<'a, E>>),
Return(Expression<'a, E>),
Break,
Continue,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum IfBodyStatements<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
If(Vec<IfBodyStatement<'a, E>>),
Loop(Vec<IfLoopBodyStatement<'a, E>>),
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum LoopBodyStatement<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
LetBinding(LetBinding<'a, E>),
Binding(Binding<'a, E>),
FunctionCall(FunctionCall<'a, E>),
If(IfStatement<'a, E>),
Loop(Vec<LoopBodyStatement<'a, E>>),
Return(Expression<'a, E>),
Break,
Continue,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "codec",
derive(Serialize, Deserialize),
serde(tag = "type", content = "content")
)]
pub enum MainStatement<'a, E: ExtendedExpression> {
#[cfg_attr(feature = "codec", serde(borrow))]
Import(ImportPath<'a>),
Constant(Constant<'a>),
Types(StructTypes<'a>),
Function(FunctionStatement<'a, E>),
}
pub type Main<'a, E> = Vec<MainStatement<'a, E>>;