Skip to main content

miden_assembly_syntax/ast/constants/
value.rs

1use core::fmt;
2
3use miden_core::serde::{
4    ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
5};
6use miden_debug_types::{SourceSpan, Span, Spanned};
7
8use crate::{
9    ast::{HashKind, Ident},
10    parser::{IntValue, WordValue},
11};
12
13// CONSTANT VALUE
14// ================================================================================================
15
16/// Represents a constant value in Miden Assembly syntax.
17#[derive(Clone)]
18#[repr(u8)]
19#[cfg_attr(
20    all(feature = "arbitrary", test),
21    miden_test_serialization_macros::serialization_test
22)]
23pub enum ConstantValue {
24    /// A literal [`miden_core::Felt`] value.
25    Int(Span<IntValue>) = 1,
26    /// A plain spanned string.
27    String(Ident),
28    /// A literal ['WordValue'].
29    Word(Span<WordValue>),
30    /// A spanned string with a [`HashKind`] showing to which type of value the given string should
31    /// be hashed.
32    Hash(HashKind, Ident),
33}
34
35impl Eq for ConstantValue {}
36
37impl PartialEq for ConstantValue {
38    fn eq(&self, other: &Self) -> bool {
39        match (self, other) {
40            (Self::Int(l), Self::Int(y)) => l == y,
41            (Self::Int(_), _) => false,
42            (Self::Word(l), Self::Word(y)) => l == y,
43            (Self::Word(_), _) => false,
44            (Self::String(l), Self::String(y)) => l == y,
45            (Self::String(_), _) => false,
46            (Self::Hash(x_hk, x_i), Self::Hash(y_hk, y_i)) => x_i == y_i && x_hk == y_hk,
47            (Self::Hash(..), _) => false,
48        }
49    }
50}
51
52impl core::hash::Hash for ConstantValue {
53    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
54        core::mem::discriminant(self).hash(state);
55        match self {
56            Self::Int(value) => value.hash(state),
57            Self::Word(value) => value.hash(state),
58            Self::String(value) => value.hash(state),
59            Self::Hash(kind, value) => {
60                kind.hash(state);
61                value.hash(state);
62            },
63        }
64    }
65}
66
67impl fmt::Debug for ConstantValue {
68    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69        match self {
70            Self::Int(lit) => fmt::Debug::fmt(&**lit, f),
71            Self::Word(lit) => fmt::Debug::fmt(&**lit, f),
72            Self::String(name) => fmt::Debug::fmt(&**name, f),
73            Self::Hash(hash_kind, str) => fmt::Debug::fmt(&(str, hash_kind), f),
74        }
75    }
76}
77
78impl crate::prettier::PrettyPrint for ConstantValue {
79    fn render(&self) -> crate::prettier::Document {
80        use crate::prettier::*;
81
82        match self {
83            Self::Int(literal) => literal.render(),
84            Self::Word(literal) => literal.render(),
85            Self::String(ident) => text(format!("\"{}\"", ident.as_str().escape_debug())),
86            Self::Hash(hash_kind, str) => flatten(
87                display(hash_kind)
88                    + const_text("(")
89                    + text(format!("\"{}\"", str.as_str().escape_debug()))
90                    + const_text(")"),
91            ),
92        }
93    }
94}
95
96impl Spanned for ConstantValue {
97    fn span(&self) -> SourceSpan {
98        match self {
99            Self::Int(spanned) => spanned.span(),
100            Self::Word(spanned) => spanned.span(),
101            Self::String(spanned) => spanned.span(),
102            Self::Hash(_, spanned) => spanned.span(),
103        }
104    }
105}
106
107impl ConstantValue {
108    const fn tag(&self) -> u8 {
109        // SAFETY: This is safe because we have given this enum a
110        // primitive representation with #[repr(u8)], with the first
111        // field of the underlying union-of-structs the discriminant
112        //
113        // See the section on "accessing the numeric value of the discriminant"
114        // here: https://doc.rust-lang.org/std/mem/fn.discriminant.html
115        unsafe { *(self as *const Self).cast::<u8>() }
116    }
117}
118
119impl Serializable for ConstantValue {
120    fn write_into<W: ByteWriter>(&self, target: &mut W) {
121        target.write_u8(self.tag());
122        match self {
123            Self::Int(value) => value.inner().write_into(target),
124            Self::String(id) => id.write_into(target),
125            Self::Word(value) => value.inner().write_into(target),
126            Self::Hash(kind, id) => {
127                kind.write_into(target);
128                id.write_into(target);
129            },
130        }
131    }
132}
133
134impl Deserializable for ConstantValue {
135    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
136        match source.read_u8()? {
137            1 => IntValue::read_from(source).map(Span::unknown).map(Self::Int),
138            2 => Ident::read_from(source).map(Self::String),
139            3 => WordValue::read_from(source).map(Span::unknown).map(Self::Word),
140            4 => {
141                let kind = HashKind::read_from(source)?;
142                let id = Ident::read_from(source)?;
143                Ok(Self::Hash(kind, id))
144            },
145            invalid => Err(DeserializationError::InvalidValue(format!(
146                "unexpected ConstantValue tag: '{invalid}'"
147            ))),
148        }
149    }
150}
151
152#[cfg(feature = "arbitrary")]
153impl proptest::arbitrary::Arbitrary for ConstantValue {
154    type Parameters = ();
155
156    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
157        use proptest::{arbitrary::any, prop_oneof, strategy::Strategy};
158
159        prop_oneof![
160            any::<IntValue>().prop_map(|n| Self::Int(Span::unknown(n))),
161            any::<Ident>().prop_map(Self::String),
162            any::<WordValue>().prop_map(|word| Self::Word(Span::unknown(word))),
163            any::<(HashKind, Ident)>().prop_map(|(kind, s)| Self::Hash(kind, s)),
164        ]
165        .boxed()
166    }
167
168    type Strategy = proptest::prelude::BoxedStrategy<Self>;
169}