tblgen/
init.rs

1// Original work Copyright 2016 Alexander Stocko <as@coder.gg>.
2// Modified work Copyright 2023 Daan Vanoverloop
3// See the COPYRIGHT file at the top-level directory of this distribution.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! This module contains smart pointers that reference various `Init` types in
12//! TableGen.
13//!
14//! Init reference types can be converted to Rust types using [`Into`] and
15//! [`TryInto`]. Most conversions are cheap, except for conversion to
16//! [`String`].
17
18#[cfg(feature = "llvm22-0")]
19use crate::raw::tableGenBitsInitConvertKnownBitsToInt;
20use crate::{
21    raw::{
22        TableGenRecTyKind, TableGenTypedInitRef, tableGenBitInitGetValue, tableGenBitInitIsVarBit,
23        tableGenBitsInitGetBitInit, tableGenBitsInitGetNumBits, tableGenDagRecordArgName,
24        tableGenDagRecordGet, tableGenDagRecordGetArgNo, tableGenDagRecordNumArgs,
25        tableGenDagRecordOperator, tableGenDefInitGetValue, tableGenInitDump, tableGenInitPrint,
26        tableGenInitRecType, tableGenIntInitGetValue, tableGenListInitGetElementType,
27        tableGenListRecordGet, tableGenListRecordNumElements, tableGenStringInitGetValue,
28        tableGenVarBitInitGetBitNum, tableGenVarBitInitGetVarName,
29    },
30    string_ref::StringRef,
31    util::print_callback,
32};
33use paste::paste;
34
35use crate::{
36    error::{Error, TableGenError},
37    record::Record,
38};
39use std::{
40    ffi::c_void,
41    fmt::{self, Debug, Display, Formatter},
42    marker::PhantomData,
43    str::Utf8Error,
44    string::FromUtf8Error,
45};
46
47/// Enum that holds a reference to a `TypedInit`.
48#[derive(Clone, Copy, PartialEq, Eq)]
49pub enum TypedInit<'a> {
50    Bit(BitInit<'a>),
51    Bits(BitsInit<'a>),
52    Code(StringInit<'a>),
53    Int(IntInit<'a>),
54    String(StringInit<'a>),
55    List(ListInit<'a>),
56    Dag(DagInit<'a>),
57    Def(DefInit<'a>),
58    Invalid,
59}
60
61impl TypedInit<'_> {
62    fn variant_name(&self) -> &'static str {
63        match self {
64            TypedInit::Bit(_) => "Bit",
65            TypedInit::Bits(_) => "Bits",
66            TypedInit::Code(_) => "Code",
67            TypedInit::Int(_) => "Int",
68            TypedInit::String(_) => "String",
69            TypedInit::List(_) => "List",
70            TypedInit::Dag(_) => "Dag",
71            TypedInit::Def(_) => "Def",
72            TypedInit::Invalid => "Invalid",
73        }
74    }
75}
76
77impl Display for TypedInit<'_> {
78    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
79        match self {
80            Self::Bit(init) => write!(f, "{}", &init),
81            Self::Bits(init) => write!(f, "{}", &init),
82            Self::Code(init) => write!(f, "{}", &init),
83            Self::Int(init) => write!(f, "{}", &init),
84            Self::String(init) => write!(f, "{}", &init),
85            Self::List(init) => write!(f, "{}", &init),
86            Self::Dag(init) => write!(f, "{}", &init),
87            Self::Def(init) => write!(f, "{}", &init),
88            Self::Invalid => write!(f, "Invalid"),
89        }
90    }
91}
92
93impl Debug for TypedInit<'_> {
94    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
95        write!(f, "TypedInit(")?;
96        let name = self.variant_name();
97        write!(f, "{name}(")?;
98        match self {
99            Self::Bit(init) => write!(f, "{:#?}", &init),
100            Self::Bits(init) => write!(f, "{:#?}", &init),
101            Self::Code(init) => write!(f, "{:#?}", &init),
102            Self::Int(init) => write!(f, "{:#?}", &init),
103            Self::String(init) => write!(f, "{:#?}", &init),
104            Self::List(init) => write!(f, "{:#?}", &init),
105            Self::Dag(init) => write!(f, "{:#?}", &init),
106            Self::Def(init) => write!(f, "{:#?}", &init),
107            Self::Invalid => write!(f, ""),
108        }?;
109        write!(f, "))")
110    }
111}
112
113impl std::hash::Hash for TypedInit<'_> {
114    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
115        std::mem::discriminant(self).hash(state);
116        match self {
117            Self::Bit(v) => v.hash(state),
118            Self::Bits(v) => v.hash(state),
119            Self::Code(v) => v.hash(state),
120            Self::Int(v) => v.hash(state),
121            Self::String(v) => v.hash(state),
122            Self::List(v) => v.hash(state),
123            Self::Dag(v) => v.hash(state),
124            Self::Def(v) => v.hash(state),
125            Self::Invalid => {}
126        }
127    }
128}
129
130macro_rules! as_inner {
131    ($name:ident, $variant:ident, $type:ty) => {
132        paste! {
133            pub fn [<as_ $name>](self) -> Result<$type<'a>, Error> {
134                match self {
135                    Self::$variant(v) => Ok(v),
136                    _ => Err(TableGenError::InitConversion {
137                        from: self.variant_name(),
138                        to: std::any::type_name::<$type>()
139                    }.into())
140                }
141            }
142        }
143    };
144}
145
146macro_rules! try_into {
147    ($variant:ident, $init:ty, $type:ty) => {
148        impl<'a> TryFrom<TypedInit<'a>> for $type {
149            type Error = Error;
150
151            fn try_from(value: TypedInit<'a>) -> Result<Self, Self::Error> {
152                match value {
153                    TypedInit::$variant(v) => Ok(Self::try_from(v).map_err(TableGenError::from)?),
154                    _ => Err(TableGenError::InitConversion {
155                        from: value.variant_name(),
156                        to: std::any::type_name::<$type>(),
157                    }
158                    .into()),
159                }
160            }
161        }
162    };
163}
164
165try_into!(Bit, BitInit<'a>, bool);
166try_into!(Bits, BitsInit<'a>, Vec<BitInit<'a>>);
167try_into!(Bits, BitsInit<'a>, Vec<bool>);
168try_into!(Int, IntInit<'a>, i64);
169try_into!(Def, DefInit<'a>, Record<'a>);
170try_into!(List, ListInit<'a>, ListInit<'a>);
171try_into!(Dag, DagInit<'a>, DagInit<'a>);
172
173impl<'a> TryFrom<TypedInit<'a>> for String {
174    type Error = Error;
175
176    fn try_from(value: TypedInit<'a>) -> Result<Self, Self::Error> {
177        match value {
178            TypedInit::String(v) | TypedInit::Code(v) => {
179                Ok(Self::try_from(v).map_err(TableGenError::from)?)
180            }
181            _ => Err(TableGenError::InitConversion {
182                from: value.variant_name(),
183                to: std::any::type_name::<String>(),
184            }
185            .into()),
186        }
187    }
188}
189
190impl<'a> TryFrom<TypedInit<'a>> for &'a str {
191    type Error = Error;
192
193    fn try_from(value: TypedInit<'a>) -> Result<Self, Self::Error> {
194        match value {
195            TypedInit::String(v) | TypedInit::Code(v) => {
196                Ok(v.to_str().map_err(TableGenError::from)?)
197            }
198            _ => Err(TableGenError::InitConversion {
199                from: value.variant_name(),
200                to: std::any::type_name::<&'a str>(),
201            }
202            .into()),
203        }
204    }
205}
206
207impl<'a> TypedInit<'a> {
208    as_inner!(bit, Bit, BitInit);
209    as_inner!(bits, Bits, BitsInit);
210    as_inner!(code, Code, StringInit);
211    as_inner!(int, Int, IntInit);
212    as_inner!(string, String, StringInit);
213    as_inner!(list, List, ListInit);
214    as_inner!(dag, Dag, DagInit);
215    as_inner!(def, Def, DefInit);
216
217    /// Creates a new init from a raw object.
218    ///
219    /// # Safety
220    ///
221    /// The raw object must be valid.
222    #[allow(non_upper_case_globals)]
223    pub unsafe fn from_raw(init: TableGenTypedInitRef) -> Self {
224        use TableGenRecTyKind::*;
225
226        match unsafe { tableGenInitRecType(init) } {
227            TableGenBitRecTyKind => Self::Bit(unsafe { BitInit::from_raw(init) }),
228            TableGenBitsRecTyKind => Self::Bits(unsafe { BitsInit::from_raw(init) }),
229            TableGenCodeRecTyKind => Self::Code(unsafe { StringInit::from_raw(init) }),
230            TableGenIntRecTyKind => TypedInit::Int(unsafe { IntInit::from_raw(init) }),
231            TableGenStringRecTyKind => Self::String(unsafe { StringInit::from_raw(init) }),
232            TableGenListRecTyKind => TypedInit::List(unsafe { ListInit::from_raw(init) }),
233            TableGenDagRecTyKind => TypedInit::Dag(unsafe { DagInit::from_raw(init) }),
234            TableGenRecordRecTyKind => Self::Def(unsafe { DefInit::from_raw(init) }),
235            _ => Self::Invalid,
236        }
237    }
238}
239
240macro_rules! init {
241    ($name:ident) => {
242        #[derive(Clone, Copy, PartialEq, Eq)]
243        pub struct $name<'a> {
244            raw: TableGenTypedInitRef,
245            _reference: PhantomData<&'a TableGenTypedInitRef>,
246        }
247
248        impl<'a> $name<'a> {
249            /// Creates a new init from a raw object.
250            ///
251            /// # Safety
252            ///
253            /// The raw object must be valid.
254            pub unsafe fn from_raw(raw: TableGenTypedInitRef) -> Self {
255                Self {
256                    raw,
257                    _reference: PhantomData,
258                }
259            }
260
261            /// Dumps this init to stderr (for debugging).
262            pub fn dump(self) {
263                unsafe { tableGenInitDump(self.raw) }
264            }
265        }
266
267        impl std::hash::Hash for $name<'_> {
268            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
269                self.raw.hash(state);
270            }
271        }
272
273        impl<'a> Display for $name<'a> {
274            fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
275                let mut data = (formatter, Ok(()));
276
277                unsafe {
278                    tableGenInitPrint(
279                        self.raw,
280                        Some(print_callback),
281                        &mut data as *mut _ as *mut c_void,
282                    );
283                }
284
285                data.1
286            }
287        }
288
289        impl<'a> Debug for $name<'a> {
290            fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
291                write!(formatter, "{}(", stringify!($name))?;
292                Display::fmt(self, formatter)?;
293                write!(formatter, ")")
294            }
295        }
296    };
297}
298
299init!(BitInit);
300
301impl<'a> BitInit<'a> {
302    /// Returns true if this bit is a variable reference (e.g., `lda{17}`)
303    /// rather than a literal 0/1.
304    pub fn is_var_bit(self) -> bool {
305        unsafe { tableGenBitInitIsVarBit(self.raw) != 0 }
306    }
307
308    /// If this bit is a variable reference, returns `(field_name, bit_index)`.
309    /// For example, `lda{17}` returns `Some(("lda", 17))`.
310    pub fn as_var_bit(self) -> Option<(&'a str, usize)> {
311        if !self.is_var_bit() {
312            return None;
313        }
314        let name_ref = unsafe { tableGenVarBitInitGetVarName(self.raw) };
315        if name_ref.data.is_null() {
316            return None;
317        }
318        let name = unsafe {
319            std::str::from_utf8(std::slice::from_raw_parts(
320                name_ref.data as *const u8,
321                name_ref.len,
322            ))
323            .ok()?
324        };
325        let bit_num = unsafe { tableGenVarBitInitGetBitNum(self.raw) };
326        Some((name, bit_num))
327    }
328
329    /// If this bit is a literal 0/1, returns its boolean value.
330    /// Returns `None` for variable references.
331    pub fn as_literal(self) -> Option<bool> {
332        if self.is_var_bit() {
333            return None;
334        }
335        let mut bit = -1i8;
336        let ok = unsafe { tableGenBitInitGetValue(self.raw, &mut bit) };
337        if ok > 0 && (bit == 0 || bit == 1) {
338            Some(bit != 0)
339        } else {
340            None
341        }
342    }
343}
344
345impl<'a> TryFrom<BitInit<'a>> for bool {
346    type Error = TableGenError;
347
348    fn try_from(value: BitInit<'a>) -> Result<Self, Self::Error> {
349        value.as_literal().ok_or(TableGenError::InitConversion {
350            from: "VarBitInit",
351            to: "bool",
352        })
353    }
354}
355
356init!(BitsInit);
357
358impl<'a> From<BitsInit<'a>> for Vec<BitInit<'a>> {
359    fn from(value: BitsInit<'a>) -> Self {
360        (0..value.num_bits())
361            .map(|i| value.bit(i).expect("index within range"))
362            .collect()
363    }
364}
365
366impl<'a> TryFrom<BitsInit<'a>> for Vec<bool> {
367    type Error = TableGenError;
368
369    fn try_from(value: BitsInit<'a>) -> Result<Self, Self::Error> {
370        (0..value.num_bits())
371            .map(|i| {
372                value
373                    .bit(i)
374                    .ok_or(TableGenError::InitConversion {
375                        from: "BitsInit",
376                        to: "bool",
377                    })
378                    .and_then(bool::try_from)
379            })
380            .collect()
381    }
382}
383
384impl<'a> From<BitsInit<'a>> for Vec<Option<bool>> {
385    fn from(value: BitsInit<'a>) -> Self {
386        (0..value.num_bits())
387            .map(|i| value.bit(i).expect("index within range").as_literal())
388            .collect()
389    }
390}
391
392impl<'a> BitsInit<'a> {
393    /// Returns the bit at the given index.
394    pub fn bit(self, index: usize) -> Option<BitInit<'a>> {
395        let bit = unsafe { tableGenBitsInitGetBitInit(self.raw, index) };
396        if !bit.is_null() {
397            Some(unsafe { BitInit::from_raw(bit) })
398        } else {
399            None
400        }
401    }
402
403    /// Returns the number of bits in the init.
404    pub fn num_bits(self) -> usize {
405        let mut len = 0;
406        unsafe { tableGenBitsInitGetNumBits(self.raw, &mut len) };
407        len
408    }
409
410    /// Returns the known bits as a `u64`.
411    ///
412    /// Variable bits (unresolved references) are treated as zero.
413    #[cfg(feature = "llvm22-0")]
414    pub fn known_bits_to_int(self) -> u64 {
415        unsafe { tableGenBitsInitConvertKnownBitsToInt(self.raw) }
416    }
417}
418
419init!(IntInit);
420
421impl<'a> TryFrom<IntInit<'a>> for i64 {
422    type Error = TableGenError;
423
424    fn try_from(value: IntInit<'a>) -> Result<Self, Self::Error> {
425        let mut int: i64 = 0;
426        let res = unsafe { tableGenIntInitGetValue(value.raw, &mut int) };
427        if res > 0 {
428            Ok(int)
429        } else {
430            Err(TableGenError::InitConversion {
431                from: "Int",
432                to: "i64",
433            })
434        }
435    }
436}
437
438init!(StringInit);
439
440impl<'a> TryFrom<StringInit<'a>> for String {
441    type Error = FromUtf8Error;
442
443    fn try_from(value: StringInit<'a>) -> Result<Self, Self::Error> {
444        String::from_utf8(value.as_bytes().to_vec())
445    }
446}
447
448impl<'a> TryFrom<StringInit<'a>> for &'a str {
449    type Error = Utf8Error;
450
451    fn try_from(value: StringInit<'a>) -> Result<Self, Utf8Error> {
452        value.to_str()
453    }
454}
455
456impl<'a> StringInit<'a> {
457    /// Converts the string init to a [`&str`].
458    ///
459    /// # Errors
460    ///
461    /// Returns a [`Utf8Error`] if the string init does not contain valid UTF-8.
462    pub fn to_str(self) -> Result<&'a str, Utf8Error> {
463        unsafe { StringRef::from_raw(tableGenStringInitGetValue(self.raw)) }.try_into()
464    }
465
466    /// Gets the string init as a slice of bytes.
467    pub fn as_bytes(self) -> &'a [u8] {
468        unsafe { StringRef::from_raw(tableGenStringInitGetValue(self.raw)) }.into()
469    }
470}
471
472init!(DefInit);
473
474impl<'a> From<DefInit<'a>> for Record<'a> {
475    fn from(value: DefInit<'a>) -> Self {
476        unsafe { Record::from_raw(tableGenDefInitGetValue(value.raw)) }
477    }
478}
479
480init!(DagInit);
481
482impl<'a> DagInit<'a> {
483    /// Returns an iterator over the arguments of the dag.
484    ///
485    /// The iterator yields tuples `(Option<&str>, TypedInit)` where the first element is the
486    /// argument name, or `None` if the argument is unnamed (e.g. positional args like
487    /// `(add r0, r1, r2)`).
488    ///
489    /// Use [`DagInit::num_args`] and [`DagInit::get`] for indexed access if you only need values.
490    pub fn args(self) -> DagIter<'a> {
491        let back = self.num_args();
492        DagIter {
493            dag: self,
494            index: 0,
495            back,
496        }
497    }
498
499    /// Returns the operator of the dag as a [`Record`].
500    pub fn operator(self) -> Record<'a> {
501        unsafe { Record::from_raw(tableGenDagRecordOperator(self.raw)) }
502    }
503
504    /// Returns the number of arguments for this dag.
505    pub fn num_args(self) -> usize {
506        unsafe { tableGenDagRecordNumArgs(self.raw) }
507    }
508
509    /// Returns the name of the argument at the given index.
510    pub fn name(self, index: usize) -> Option<&'a str> {
511        unsafe { StringRef::from_option_raw(tableGenDagRecordArgName(self.raw, index)) }
512            .and_then(|s| s.try_into().ok())
513    }
514
515    /// Returns the argument index for the given name, or `None` if not found.
516    pub fn arg_no(self, name: &str) -> Option<usize> {
517        let result = unsafe { tableGenDagRecordGetArgNo(self.raw, StringRef::from(name).to_raw()) };
518        if result == usize::MAX {
519            None
520        } else {
521            Some(result)
522        }
523    }
524
525    /// Returns the argument at the given index.
526    pub fn get(self, index: usize) -> Option<TypedInit<'a>> {
527        let value = unsafe { tableGenDagRecordGet(self.raw, index) };
528        if !value.is_null() {
529            Some(unsafe { TypedInit::from_raw(value) })
530        } else {
531            None
532        }
533    }
534}
535
536/// Iterator over the arguments of a [`DagInit`].
537#[derive(Debug, Clone)]
538pub struct DagIter<'a> {
539    dag: DagInit<'a>,
540    index: usize,
541    back: usize,
542}
543
544impl<'a> Iterator for DagIter<'a> {
545    type Item = (Option<&'a str>, TypedInit<'a>);
546
547    fn next(&mut self) -> Option<Self::Item> {
548        if self.index >= self.back {
549            return None;
550        }
551        let next = self.dag.get(self.index)?;
552        let name = self.dag.name(self.index);
553        self.index += 1;
554        Some((name, next))
555    }
556
557    fn size_hint(&self) -> (usize, Option<usize>) {
558        let remaining = self.back.saturating_sub(self.index);
559        (remaining, Some(remaining))
560    }
561}
562
563impl<'a> DoubleEndedIterator for DagIter<'a> {
564    fn next_back(&mut self) -> Option<Self::Item> {
565        if self.index >= self.back {
566            return None;
567        }
568        self.back -= 1;
569        match self.dag.get(self.back) {
570            Some(next) => {
571                let name = self.dag.name(self.back);
572                Some((name, next))
573            }
574            None => {
575                self.back += 1;
576                None
577            }
578        }
579    }
580}
581
582impl ExactSizeIterator for DagIter<'_> {}
583
584impl std::iter::FusedIterator for DagIter<'_> {}
585
586init!(ListInit);
587
588impl<'a> ListInit<'a> {
589    /// Returns an iterator over the elements of the list.
590    ///
591    /// The iterator yields values of type [`TypedInit`].
592    pub fn iter(self) -> ListIter<'a> {
593        let back = self.len();
594        ListIter {
595            list: self,
596            index: 0,
597            back,
598        }
599    }
600
601    /// Returns true if the list is empty.
602    pub fn is_empty(self) -> bool {
603        self.len() == 0
604    }
605
606    /// Returns the length of the list.
607    pub fn len(self) -> usize {
608        unsafe { tableGenListRecordNumElements(self.raw) }
609    }
610
611    /// Returns the element at the given index in the list.
612    pub fn get(self, index: usize) -> Option<TypedInit<'a>> {
613        let value = unsafe { tableGenListRecordGet(self.raw, index) };
614        if !value.is_null() {
615            Some(unsafe { TypedInit::from_raw(value) })
616        } else {
617            None
618        }
619    }
620
621    /// Returns the element type of this list, or `None` if it cannot be determined.
622    pub fn element_type(self) -> Option<crate::raw::TableGenRecTyKind::Type> {
623        use crate::raw::TableGenRecTyKind::TableGenInvalidRecTyKind;
624        let kind = unsafe { tableGenListInitGetElementType(self.raw) };
625        if kind == TableGenInvalidRecTyKind {
626            None
627        } else {
628            Some(kind)
629        }
630    }
631}
632
633/// Iterator over the elements of a [`ListInit`].
634#[derive(Debug, Clone)]
635pub struct ListIter<'a> {
636    list: ListInit<'a>,
637    index: usize,
638    back: usize,
639}
640
641impl<'a> Iterator for ListIter<'a> {
642    type Item = TypedInit<'a>;
643
644    fn next(&mut self) -> Option<TypedInit<'a>> {
645        if self.index >= self.back {
646            return None;
647        }
648        let next = unsafe { tableGenListRecordGet(self.list.raw, self.index) };
649        self.index += 1;
650        if !next.is_null() {
651            Some(unsafe { TypedInit::from_raw(next) })
652        } else {
653            None
654        }
655    }
656
657    fn size_hint(&self) -> (usize, Option<usize>) {
658        let remaining = self.back.saturating_sub(self.index);
659        (remaining, Some(remaining))
660    }
661}
662
663impl<'a> DoubleEndedIterator for ListIter<'a> {
664    fn next_back(&mut self) -> Option<TypedInit<'a>> {
665        if self.index >= self.back {
666            return None;
667        }
668        self.back -= 1;
669        let next = unsafe { tableGenListRecordGet(self.list.raw, self.back) };
670        if !next.is_null() {
671            Some(unsafe { TypedInit::from_raw(next) })
672        } else {
673            // Restore back so the element is not silently skipped on the next call.
674            self.back += 1;
675            None
676        }
677    }
678}
679
680impl ExactSizeIterator for ListIter<'_> {}
681
682impl std::iter::FusedIterator for ListIter<'_> {}
683
684#[cfg(test)]
685mod tests {
686    use super::*;
687    use crate::TableGenParser;
688
689    macro_rules! test_init {
690        ($name:ident, $td_field:expr, $expected:expr) => {
691            #[test]
692            fn $name() {
693                let rk = TableGenParser::new()
694                    .add_source(&format!(
695                        "
696                    def A {{
697                        {}
698                    }}
699                    ",
700                        $td_field
701                    ))
702                    .unwrap()
703                    .parse()
704                    .expect("valid tablegen");
705                let a = rk
706                    .def("A")
707                    .expect("def A exists")
708                    .value("a")
709                    .expect("field a exists");
710                assert_eq!(a.init.try_into(), Ok($expected));
711            }
712        };
713    }
714
715    test_init!(bit, "bit a = 0;", false);
716    test_init!(
717        bits,
718        "bits<4> a = { 0, 0, 1, 0 };",
719        vec![false, true, false, false]
720    );
721    test_init!(int, "int a = 42;", 42);
722    test_init!(string, "string a = \"hi\";", "hi");
723    test_init!(code, "code a = \"hi\";", "hi");
724
725    #[test]
726    fn dag() {
727        let rk = TableGenParser::new()
728            .add_source(
729                "
730                def ins;
731                def X {
732                    int i = 4;
733                }
734                def Y {
735                    string s = \"test\";
736                }
737                def A {
738                    dag args = (ins X:$src1, Y:$src2);
739                }
740                ",
741            )
742            .unwrap()
743            .parse()
744            .expect("valid tablegen");
745        let a: DagInit = rk
746            .def("A")
747            .expect("def A exists")
748            .value("args")
749            .expect("field args exists")
750            .try_into()
751            .expect("is dag init");
752        assert_eq!(a.num_args(), 2);
753        assert_eq!(a.operator().name(), Ok("ins"));
754        let mut args = a.args();
755        assert_eq!(
756            args.clone().next().map(|(name, init)| (
757                name,
758                Record::try_from(init).expect("is record").int_value("i")
759            )),
760            Some((Some("src1"), Ok(4)))
761        );
762        assert_eq!(
763            args.nth(1).map(|(name, init)| (
764                name,
765                Record::try_from(init).expect("is record").string_value("s")
766            )),
767            Some((Some("src2"), Ok("test".into())))
768        );
769    }
770
771    #[test]
772    fn dag_unnamed_args() {
773        let rk = TableGenParser::new()
774            .add_source(
775                "
776                def add;
777                def X { int i = 1; }
778                def Y { int i = 2; }
779                def A {
780                    dag args = (add X, Y);
781                }
782                ",
783            )
784            .unwrap()
785            .parse()
786            .expect("valid tablegen");
787        let a: DagInit = rk
788            .def("A")
789            .expect("def A exists")
790            .value("args")
791            .expect("field args exists")
792            .try_into()
793            .expect("is dag init");
794        assert_eq!(a.num_args(), 2);
795        let collected: Vec<_> = a
796            .args()
797            .map(|(name, init)| {
798                (
799                    name,
800                    Record::try_from(init).expect("is record").int_value("i"),
801                )
802            })
803            .collect();
804        assert_eq!(collected, vec![(None, Ok(1)), (None, Ok(2))]);
805    }
806
807    #[test]
808    fn dag_mixed_named_unnamed_args() {
809        let rk = TableGenParser::new()
810            .add_source(
811                "
812                def op;
813                def X { int i = 10; }
814                def Y { int i = 20; }
815                def A {
816                    dag args = (op X:$named, Y);
817                }
818                ",
819            )
820            .unwrap()
821            .parse()
822            .expect("valid tablegen");
823        let a: DagInit = rk
824            .def("A")
825            .expect("def A exists")
826            .value("args")
827            .expect("field args exists")
828            .try_into()
829            .expect("is dag init");
830        assert_eq!(a.num_args(), 2);
831        let collected: Vec<_> = a
832            .args()
833            .map(|(name, init)| {
834                (
835                    name,
836                    Record::try_from(init).expect("is record").int_value("i"),
837                )
838            })
839            .collect();
840        assert_eq!(collected, vec![(Some("named"), Ok(10)), (None, Ok(20))]);
841    }
842
843    #[test]
844    fn list() {
845        let rk = TableGenParser::new()
846            .add_source(
847                "
848                def A {
849                    list<int> l = [0, 1, 2, 3];
850                }
851                ",
852            )
853            .unwrap()
854            .parse()
855            .expect("valid tablegen");
856        let l: ListInit = rk
857            .def("A")
858            .expect("def A exists")
859            .value("l")
860            .expect("field args exists")
861            .try_into()
862            .expect("is list init");
863        assert_eq!(l.len(), 4);
864        let iter = l.iter();
865        assert_eq!(iter.clone().count(), 4);
866        assert_eq!(iter.clone().next().unwrap().try_into(), Ok(0));
867        assert_eq!(iter.clone().nth(1).unwrap().try_into(), Ok(1));
868        assert_eq!(iter.clone().nth(2).unwrap().try_into(), Ok(2));
869        assert_eq!(iter.clone().nth(3).unwrap().try_into(), Ok(3));
870    }
871
872    #[test]
873    fn list_double_ended() {
874        let rk = TableGenParser::new()
875            .add_source("def A { list<int> l = [10, 20, 30, 40]; }")
876            .unwrap()
877            .parse()
878            .expect("valid tablegen");
879        let l: ListInit = rk.def("A").unwrap().value("l").unwrap().try_into().unwrap();
880        let mut iter = l.iter();
881        assert_eq!(iter.len(), 4);
882        assert_eq!(iter.next().unwrap().try_into(), Ok(10i64));
883        assert_eq!(iter.len(), 3);
884        assert_eq!(iter.next_back().unwrap().try_into(), Ok(40i64));
885        assert_eq!(iter.len(), 2);
886        assert_eq!(iter.next().unwrap().try_into(), Ok(20i64));
887        assert_eq!(iter.next_back().unwrap().try_into(), Ok(30i64));
888        assert_eq!(iter.len(), 0);
889        assert!(iter.next().is_none());
890        assert!(iter.next_back().is_none());
891    }
892
893    #[test]
894    fn dag_double_ended() {
895        let rk = TableGenParser::new()
896            .add_source(
897                "def op; def A { int i = 1; } def B { int i = 2; } def C { int i = 3; }
898                 def R { dag d = (op A, B, C); }",
899            )
900            .unwrap()
901            .parse()
902            .expect("valid tablegen");
903        let dag: DagInit = rk.def("R").unwrap().value("d").unwrap().try_into().unwrap();
904        let mut iter = dag.args();
905        assert_eq!(iter.len(), 3);
906        let (_, first) = iter.next().unwrap();
907        assert_eq!(Record::try_from(first).unwrap().int_value("i"), Ok(1));
908        assert_eq!(iter.len(), 2);
909        let (_, last) = iter.next_back().unwrap();
910        assert_eq!(Record::try_from(last).unwrap().int_value("i"), Ok(3));
911        assert_eq!(iter.len(), 1);
912        let (_, mid) = iter.next().unwrap();
913        assert_eq!(Record::try_from(mid).unwrap().int_value("i"), Ok(2));
914        assert_eq!(iter.len(), 0);
915        assert!(iter.next().is_none());
916        assert!(iter.next_back().is_none());
917    }
918
919    #[test]
920    fn varbit() {
921        // Access the class template before parameter substitution.
922        // bits<4> val = src produces VarBitInit elements: src{0}..src{3}.
923        let rk = TableGenParser::new()
924            .add_source("class Foo<bits<4> src> { bits<4> val = src; }")
925            .unwrap()
926            .parse()
927            .expect("valid tablegen");
928        let bits: BitsInit = rk
929            .class("Foo")
930            .expect("class Foo exists")
931            .value("val")
932            .expect("field val exists")
933            .init
934            .as_bits()
935            .expect("is BitsInit");
936        assert_eq!(bits.num_bits(), 4);
937        for i in 0..4 {
938            let bit = bits.bit(i).expect("bit in range");
939            assert!(bit.is_var_bit());
940            assert_eq!(bit.as_var_bit(), Some(("Foo:src", i)));
941            assert_eq!(bit.as_literal(), None);
942        }
943        let optional: Vec<Option<bool>> = bits.into();
944        assert_eq!(optional, vec![None, None, None, None]);
945    }
946
947    #[test]
948    fn vec_bool_from_varbit_bits_returns_err() {
949        // Variable-reference bits (VarBitInit) cannot be converted to bool.
950        // The TryFrom impl must return Err rather than panicking.
951        let rk = TableGenParser::new()
952            .add_source("class Foo<bits<4> src> { bits<4> val = src; }")
953            .unwrap()
954            .parse()
955            .expect("valid tablegen");
956        let bits: BitsInit = rk
957            .class("Foo")
958            .expect("class Foo exists")
959            .value("val")
960            .expect("field val exists")
961            .init
962            .as_bits()
963            .expect("is BitsInit");
964        let result = Vec::<bool>::try_from(bits);
965        assert!(result.is_err());
966    }
967
968    #[test]
969    fn empty_list() {
970        let rk = TableGenParser::new()
971            .add_source("def A { list<int> l = []; }")
972            .unwrap()
973            .parse()
974            .expect("valid tablegen");
975        let l: ListInit = rk
976            .def("A")
977            .expect("def A exists")
978            .value("l")
979            .expect("field l exists")
980            .try_into()
981            .expect("is list init");
982        assert_eq!(l.len(), 0);
983        assert!(l.is_empty());
984        assert!(l.iter().next().is_none());
985        // Repeated next() calls on exhausted iterator must not misbehave.
986        let mut iter = l.iter();
987        assert!(iter.next().is_none());
988        assert!(iter.next().is_none());
989    }
990
991    #[test]
992    fn literal_bit_methods() {
993        let rk = TableGenParser::new()
994            .add_source("def A { bits<4> a = { 0, 1, 0, 1 }; }")
995            .unwrap()
996            .parse()
997            .expect("valid tablegen");
998        let bits: BitsInit = rk
999            .def("A")
1000            .expect("def A exists")
1001            .value("a")
1002            .expect("field a exists")
1003            .init
1004            .as_bits()
1005            .expect("is BitsInit");
1006        for i in 0..4 {
1007            let bit = bits.bit(i).expect("bit in range");
1008            assert!(!bit.is_var_bit());
1009            assert!(bit.as_var_bit().is_none());
1010            assert!(bit.as_literal().is_some());
1011        }
1012    }
1013
1014    #[test]
1015    fn list_element_type() {
1016        use crate::raw::TableGenRecTyKind::{
1017            TableGenDagRecTyKind, TableGenIntRecTyKind, TableGenStringRecTyKind,
1018        };
1019        let rk = TableGenParser::new()
1020            .add_source(
1021                r#"
1022                def op;
1023                def A {
1024                    list<int> li = [1, 2, 3];
1025                    list<string> ls = ["a", "b"];
1026                    list<dag> ld = [(op)];
1027                }
1028                "#,
1029            )
1030            .unwrap()
1031            .parse()
1032            .expect("valid tablegen");
1033        let a = rk.def("A").expect("def A exists");
1034        let li: ListInit = a.value("li").unwrap().try_into().unwrap();
1035        assert_eq!(li.element_type(), Some(TableGenIntRecTyKind));
1036        let ls: ListInit = a.value("ls").unwrap().try_into().unwrap();
1037        assert_eq!(ls.element_type(), Some(TableGenStringRecTyKind));
1038        let ld: ListInit = a.value("ld").unwrap().try_into().unwrap();
1039        assert_eq!(ld.element_type(), Some(TableGenDagRecTyKind));
1040    }
1041}