miden_assembly_syntax/ast/
immediate.rs

1use alloc::sync::Arc;
2use core::fmt;
3
4use miden_debug_types::{SourceSpan, Span, Spanned};
5
6use crate::{Felt, ast::Ident};
7
8/// An 8-bit unsigned immediate
9pub type ImmU8 = Immediate<u8>;
10
11/// A 16-bit unsigned immediate
12pub type ImmU16 = Immediate<u16>;
13
14/// A 32-bit unsigned immediate
15pub type ImmU32 = Immediate<u32>;
16
17/// A field element immediate
18pub type ImmFelt = Immediate<Felt>;
19
20/// The type of error messages used in MASM assertions.
21pub type ErrorMsg = Immediate<Arc<str>>;
22
23/// Represents an instruction immediate, e.g. `add.1` or `add.CONST`
24pub enum Immediate<T> {
25    /// A literal integer value, either decimal or hex-encoded
26    Value(Span<T>),
27    /// A constant identifier
28    ///
29    /// This must refer to a constant definition in the current module.
30    ///
31    /// All immediates of this type are folded to `Value` during
32    /// semantic analysis, once all constant definitions are evaluated.
33    Constant(Ident),
34}
35
36/// All immediates
37impl<T> Immediate<T> {
38    pub fn is_literal(&self) -> bool {
39        matches!(self, Self::Value(_))
40    }
41
42    /// Override the source span of this immediate with `span`
43    pub fn with_span(self, span: SourceSpan) -> Self {
44        match self {
45            Self::Constant(id) => Self::Constant(id.with_span(span)),
46            Self::Value(value) => Self::Value(Span::new(span, value.into_inner())),
47        }
48    }
49
50    /// Transform the type of this immediate from T to U, using `map`
51    pub fn map<U, F>(self, map: F) -> Immediate<U>
52    where
53        F: FnMut(T) -> U,
54    {
55        match self {
56            Self::Constant(id) => Immediate::Constant(id),
57            Self::Value(value) => Immediate::Value(value.map(map)),
58        }
59    }
60}
61
62/// Copy-able immediates (in practice, all of them)
63impl<T: Copy> Immediate<T> {
64    pub fn expect_value(&self) -> T {
65        match self {
66            Self::Value(value) => value.into_inner(),
67            Self::Constant(name) => panic!("tried to unwrap unresolved constant: '{name}'"),
68        }
69    }
70
71    pub fn expect_spanned_value(&self) -> Span<T> {
72        match self {
73            Self::Value(value) => *value,
74            Self::Constant(name) => panic!("tried to unwrap unresolved constant: '{name}'"),
75        }
76    }
77}
78
79impl Immediate<Arc<str>> {
80    pub fn expect_string(&self) -> Arc<str> {
81        match self {
82            Self::Value(value) => value.clone().into_inner(),
83            Self::Constant(name) => panic!("tried to unwrap unresolved constant: '{name}'"),
84        }
85    }
86}
87
88impl<T> Spanned for Immediate<T> {
89    fn span(&self) -> SourceSpan {
90        match self {
91            Self::Value(spanned) => spanned.span(),
92            Self::Constant(spanned) => spanned.span(),
93        }
94    }
95}
96
97impl<T> From<T> for Immediate<T> {
98    fn from(value: T) -> Self {
99        Self::Value(Span::unknown(value))
100    }
101}
102
103impl<T> From<Span<T>> for Immediate<T> {
104    fn from(value: Span<T>) -> Self {
105        Self::Value(value)
106    }
107}
108
109impl<T: Clone> Clone for Immediate<T> {
110    fn clone(&self) -> Self {
111        match self {
112            Self::Value(value) => Self::Value(value.clone()),
113            Self::Constant(name) => Self::Constant(name.clone()),
114        }
115    }
116}
117
118impl<T: Eq> Eq for Immediate<T> {}
119
120impl<T: PartialEq> PartialEq for Immediate<T> {
121    fn eq(&self, other: &Self) -> bool {
122        match (self, other) {
123            (Self::Value(l), Self::Value(r)) => l == r,
124            (Self::Constant(l), Self::Constant(r)) => l == r,
125            _ => false,
126        }
127    }
128}
129
130impl<T: PartialEq> PartialEq<T> for Immediate<T> {
131    fn eq(&self, other: &T) -> bool {
132        match self {
133            Self::Value(l) => l == other,
134            _ => false,
135        }
136    }
137}
138
139impl<T: core::hash::Hash> core::hash::Hash for Immediate<T> {
140    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
141        core::mem::discriminant(self).hash(state);
142        match self {
143            Self::Value(v) => v.hash(state),
144            Self::Constant(name) => name.hash(state),
145        }
146    }
147}
148
149impl<T: fmt::Debug> fmt::Debug for Immediate<T> {
150    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151        match self {
152            Self::Value(value) if f.alternate() => write!(f, "Value({value:#?})"),
153            Self::Value(value) => write!(f, "Value({value:?})"),
154            Self::Constant(name) => write!(f, "Constant({name})"),
155        }
156    }
157}
158
159impl<T: fmt::Display> fmt::Display for Immediate<T> {
160    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161        match self {
162            Self::Value(value) => write!(f, "{value}"),
163            Self::Constant(name) => write!(f, "{name}"),
164        }
165    }
166}
167
168impl<T: crate::prettier::PrettyPrint> crate::prettier::PrettyPrint for Immediate<T> {
169    fn render(&self) -> crate::prettier::Document {
170        use crate::prettier::*;
171
172        match self {
173            Self::Value(value) => value.render(),
174            Self::Constant(name) => text(name),
175        }
176    }
177}