1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use super::{OperationElement, OperationField, VariadicKind};
use crate::dialect::{
    error::Error,
    r#type::Type as ElementType,
    utility::{generate_iterator_type, generate_result_type, sanitize_snake_case_identifier},
};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
use syn::{parse_quote, Type};

#[derive(Debug)]
pub struct Operand<'a> {
    name: &'a str,
    singular_identifier: Ident,
    r#type: ElementType,
    variadic_kind: VariadicKind,
}

impl<'a> Operand<'a> {
    pub fn new(
        name: &'a str,
        r#type: ElementType,
        variadic_kind: VariadicKind,
    ) -> Result<Self, Error> {
        Ok(Self {
            name,
            singular_identifier: sanitize_snake_case_identifier(name)?,
            r#type,
            variadic_kind,
        })
    }
}

impl OperationField for Operand<'_> {
    fn name(&self) -> &str {
        self.name
    }

    fn singular_identifier(&self) -> &Ident {
        &self.singular_identifier
    }

    fn plural_kind_identifier(&self) -> Ident {
        format_ident!("operands")
    }

    fn parameter_type(&self) -> Type {
        let r#type: Type = parse_quote!(::melior::ir::Value<'c, '_>);

        if self.r#type.is_variadic() {
            parse_quote! { &[#r#type] }
        } else {
            r#type
        }
    }

    fn return_type(&self) -> Type {
        let r#type: Type = parse_quote!(::melior::ir::Value<'c, '_>);

        if !self.r#type.is_variadic() {
            generate_result_type(r#type)
        } else if self.variadic_kind == VariadicKind::AttributeSized {
            generate_result_type(generate_iterator_type(r#type))
        } else {
            generate_iterator_type(r#type)
        }
    }

    fn is_optional(&self) -> bool {
        self.r#type.is_optional()
    }

    fn add_arguments(&self, name: &Ident) -> TokenStream {
        if self.r#type.is_variadic() {
            quote! { #name }
        } else {
            quote! { &[#name] }
        }
    }
}

impl OperationElement for Operand<'_> {
    fn is_variadic(&self) -> bool {
        self.r#type.is_variadic()
    }

    fn variadic_kind(&self) -> &VariadicKind {
        &self.variadic_kind
    }
}