miden_assembly_syntax/ast/attribute/meta/
expr.rs

1use alloc::{string::String, sync::Arc};
2
3use miden_core::utils::{
4    ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
5};
6use miden_debug_types::{SourceSpan, Span, Spanned};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::{
11    Felt,
12    ast::Ident,
13    parser::{IntValue, WordValue},
14    prettier,
15};
16
17/// Represents a metadata expression of an [crate::ast::Attribute]
18#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
19#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
20#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
21#[cfg_attr(
22    all(feature = "arbitrary", test),
23    miden_test_serde_macros::serde_test(winter_serde(true))
24)]
25pub enum MetaExpr {
26    /// An identifier/keyword, e.g. `inline`
27    Ident(Ident),
28    /// A decimal or hexadecimal integer value
29    Int(Span<IntValue>),
30    /// A word-sized value
31    Word(Span<WordValue>),
32    /// A quoted string or identifier
33    String(Ident),
34}
35
36impl prettier::PrettyPrint for MetaExpr {
37    fn render(&self) -> prettier::Document {
38        use prettier::*;
39
40        match self {
41            Self::Ident(id) => text(id),
42            Self::Int(value) => value.inner().render(),
43            Self::Word(value) => display(value),
44            Self::String(id) => text(format!("\"{}\"", id.as_str().escape_default())),
45        }
46    }
47}
48
49impl From<Ident> for MetaExpr {
50    fn from(value: Ident) -> Self {
51        Self::Ident(value)
52    }
53}
54
55impl From<&str> for MetaExpr {
56    fn from(value: &str) -> Self {
57        Self::String(Ident::from_raw_parts(Span::new(SourceSpan::UNKNOWN, Arc::from(value))))
58    }
59}
60
61impl From<String> for MetaExpr {
62    fn from(value: String) -> Self {
63        Self::String(Ident::from_raw_parts(Span::new(
64            SourceSpan::UNKNOWN,
65            Arc::from(value.into_boxed_str()),
66        )))
67    }
68}
69
70impl From<u8> for MetaExpr {
71    fn from(value: u8) -> Self {
72        Self::Int(Span::new(SourceSpan::UNKNOWN, IntValue::U8(value)))
73    }
74}
75
76impl From<u16> for MetaExpr {
77    fn from(value: u16) -> Self {
78        Self::Int(Span::new(SourceSpan::UNKNOWN, IntValue::U16(value)))
79    }
80}
81
82impl From<u32> for MetaExpr {
83    fn from(value: u32) -> Self {
84        Self::Int(Span::new(SourceSpan::UNKNOWN, IntValue::U32(value)))
85    }
86}
87
88impl From<Felt> for MetaExpr {
89    fn from(value: Felt) -> Self {
90        Self::Int(Span::new(SourceSpan::UNKNOWN, IntValue::Felt(value)))
91    }
92}
93
94impl From<WordValue> for MetaExpr {
95    fn from(value: WordValue) -> Self {
96        Self::Word(Span::new(SourceSpan::UNKNOWN, value))
97    }
98}
99
100impl Spanned for MetaExpr {
101    fn span(&self) -> SourceSpan {
102        match self {
103            Self::Ident(spanned) | Self::String(spanned) => spanned.span(),
104            Self::Int(spanned) => spanned.span(),
105            Self::Word(spanned) => spanned.span(),
106        }
107    }
108}
109
110#[cfg(feature = "arbitrary")]
111impl proptest::arbitrary::Arbitrary for MetaExpr {
112    type Parameters = ();
113
114    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
115        use proptest::{arbitrary::any, prop_oneof, strategy::Strategy};
116
117        prop_oneof![
118            any::<Ident>().prop_map(Self::Ident),
119            any::<IntValue>().prop_map(|n| Self::Int(Span::unknown(n))),
120            any::<WordValue>().prop_map(|word| Self::Word(Span::unknown(word))),
121            any::<Ident>().prop_map(Self::String),
122        ]
123        .boxed()
124    }
125
126    type Strategy = proptest::prelude::BoxedStrategy<Self>;
127}
128
129impl Serializable for MetaExpr {
130    fn write_into<W: ByteWriter>(&self, target: &mut W) {
131        match self {
132            Self::Ident(value) => {
133                target.write_u8(0);
134                value.write_into(target);
135            },
136            Self::Int(value) => {
137                target.write_u8(1);
138                value.inner().write_into(target);
139            },
140            Self::Word(value) => {
141                target.write_u8(2);
142                value.inner().write_into(target);
143            },
144            Self::String(value) => {
145                target.write_u8(3);
146                value.write_into(target);
147            },
148        }
149    }
150}
151
152impl Deserializable for MetaExpr {
153    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
154        use alloc::string::ToString;
155
156        match source.read_u8()? {
157            0 => Ident::read_from(source).map(Self::Ident),
158            1 => {
159                let value = IntValue::read_from(source)?;
160                Ok(Self::Int(Span::unknown(value)))
161            },
162            2 => {
163                let value = WordValue::read_from(source)?;
164                Ok(Self::Word(Span::unknown(value)))
165            },
166            3 => {
167                let len = source.read_usize()?;
168                let bytes = source.read_slice(len)?;
169                let id = core::str::from_utf8(bytes)
170                    .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?;
171                Ok(Self::String(Ident::from_raw_parts(Span::unknown(Arc::from(
172                    id.to_string().into_boxed_str(),
173                )))))
174            },
175            n => Err(DeserializationError::InvalidValue(format!(
176                "unknown MetaExpr variant tag '{n}'"
177            ))),
178        }
179    }
180}