furiosa_mapping/parser/
mod.rs

1//! Macros for virtual ISA.
2
3use crate::PaddingKind;
4use lalrpop_util::lalrpop_mod;
5use quote::quote;
6
7mod lexer;
8lalrpop_mod!(
9    #[expect(missing_docs, missing_debug_implementations)]
10    parser,
11    "/parser/parser.rs"
12);
13
14pub use lexer::{Lexer, LexerMode};
15pub use parser::{IndexParser, MappingParser};
16
17/// Representation of an index assignment (e.g., `A / 32 = 8` or `A = i`).
18#[derive(Debug, Clone)]
19pub struct IndexAssignment {
20    /// The mapping expression.
21    pub mapping: Mapping,
22    /// The value expression.
23    pub value: proc_macro2::TokenStream,
24}
25
26impl IndexAssignment {
27    /// Expand the index assignment into code that adds it to an `Index`.
28    pub fn expand(&self) -> proc_macro2::TokenStream {
29        let value = &self.value;
30        self.mapping.expand_as_index(value)
31    }
32}
33
34/// Representation of a TCP mapping expression.
35#[derive(Debug, Clone)]
36#[expect(missing_docs)]
37pub enum Mapping {
38    Identity,
39    Symbol {
40        symbol: String,
41    },
42    Stride {
43        inner: Box<Self>,
44        stride: usize,
45    },
46    Modulo {
47        inner: Box<Self>,
48        modulo: usize,
49    },
50    Resize {
51        inner: Box<Self>,
52        resize: usize,
53    },
54    Padding {
55        inner: Box<Self>,
56        padding: usize,
57        kind: PaddingKind,
58    },
59    Pair {
60        left: Box<Self>,
61        right: Box<Self>,
62    },
63    Escaped {
64        tokens: proc_macro2::TokenStream,
65    },
66}
67
68impl Mapping {
69    /// Expand the mapping into virtual ISA type representation.
70    pub fn expand(&self) -> proc_macro2::TokenStream {
71        match self {
72            Self::Identity => {
73                quote! { Identity }
74            }
75            Self::Symbol { symbol } => {
76                let sym_ident = proc_macro2::Ident::new(symbol, proc_macro2::Span::call_site());
77                quote! { Symbol<#sym_ident> }
78            }
79            Self::Stride {
80                inner: left,
81                stride: value,
82            } => {
83                let l = left.expand();
84                quote! { Stride<#l, #value> }
85            }
86            Self::Modulo {
87                inner: left,
88                modulo: value,
89            } => {
90                let l = left.expand();
91                quote! { Modulo<#l, #value> }
92            }
93            Self::Resize {
94                inner: left,
95                resize: value,
96            } => {
97                let l = left.expand();
98                quote! { Resize<#l, #value> }
99            }
100            Self::Padding {
101                inner: left,
102                padding: value,
103                kind: _,
104            } => {
105                let l = left.expand();
106                quote! { Padding<#l, #value> }
107            }
108            Self::Pair { left, right } => {
109                let l = left.expand();
110                let r = right.expand();
111                quote! { Pair<#l, #r> }
112            }
113            Self::Escaped { tokens } => {
114                quote! { #tokens }
115            }
116        }
117    }
118
119    /// Expand the mapping into an index addition operation.
120    pub fn expand_as_index(&self, value: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
121        match self {
122            Self::Symbol { symbol } => {
123                let sym_ident = proc_macro2::Ident::new(symbol, proc_macro2::Span::call_site());
124                let size_expr = quote! { <#sym_ident as m::AxisName>::SIZE };
125                quote! {
126                    {
127                        use ::furiosa_mapping as m;
128                        const SIZE: usize = #size_expr;
129                        index.add_term(
130                            m::Term {
131                                inner: m::Atom::Symbol {
132                                    symbol: m::Ident::new(#symbol),
133                                    size: SIZE,
134                                },
135                                stride: 1,
136                                modulo: SIZE,
137                            },
138                            #value
139                        );
140                    }
141                }
142            }
143            Self::Identity => {
144                quote! {
145                    {
146                        use ::furiosa_mapping as m;
147                        if let Some(mapped_index) = <m::Identity as m::M>::map(#value) {
148                            index.add(mapped_index);
149                        } else {
150                            index.mark_invalid();
151                        }
152                    }
153                }
154            }
155            Self::Stride { inner, stride } => {
156                let inner_expanded = inner.expand();
157                quote! {
158                    {
159                        use ::furiosa_mapping as m;
160                        if let Some(mapped_index) = <m::Stride<#inner_expanded, #stride> as m::M>::map(#value) {
161                            index.add(mapped_index);
162                        } else {
163                            index.mark_invalid();
164                        }
165                    }
166                }
167            }
168            Self::Modulo { inner, modulo } => {
169                let inner_expanded = inner.expand();
170                quote! {
171                    {
172                        use ::furiosa_mapping as m;
173                        if let Some(mapped_index) = <m::Modulo<#inner_expanded, #modulo> as m::M>::map(#value) {
174                            index.add(mapped_index);
175                        } else {
176                            index.mark_invalid();
177                        }
178                    }
179                }
180            }
181            Self::Resize { inner, resize } => {
182                let inner_expanded = inner.expand();
183                quote! {
184                    {
185                        use ::furiosa_mapping as m;
186                        if let Some(mapped_index) = <m::Resize<#inner_expanded, #resize> as m::M>::map(#value) {
187                            index.add(mapped_index);
188                        } else {
189                            index.mark_invalid();
190                        }
191                    }
192                }
193            }
194            Self::Padding {
195                inner,
196                padding,
197                kind: _,
198            } => {
199                let inner_expanded = inner.expand();
200                quote! {
201                    {
202                        use ::furiosa_mapping as m;
203                        if let Some(mapped_index) = <m::Padding<#inner_expanded, #padding> as m::M>::map(#value) {
204                            index.add(mapped_index);
205                        } else {
206                            index.mark_invalid();
207                        }
208                    }
209                }
210            }
211            Self::Pair { left, right } => {
212                let left_expanded = left.expand();
213                let right_expanded = right.expand();
214                quote! {
215                    {
216                        use ::furiosa_mapping as m;
217                        if let Some(mapped_index) = <m::Pair<#left_expanded, #right_expanded> as m::M>::map(#value) {
218                            index.add(mapped_index);
219                        } else {
220                            index.mark_invalid();
221                        }
222                    }
223                }
224            }
225            Self::Escaped { tokens } => {
226                quote! {
227                    {
228                        use ::furiosa_mapping as m;
229                        if let Some(mapped_index) = <#tokens as m::M>::map(#value) {
230                            index.add(mapped_index);
231                        } else {
232                            index.mark_invalid();
233                        }
234                    }
235                }
236            }
237        }
238    }
239}