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