prjunnamed_pattern/
lib.rs

1pub trait Pattern<Target> {
2    type Capture;
3
4    fn execute(&self, design: &dyn DesignDyn, target: &Target) -> Option<Self::Capture>;
5}
6
7#[macro_export]
8macro_rules! netlist_match {
9    { [ $($rule:tt)* ] $($rest:tt)* } => {
10        |design: &dyn $crate::DesignDyn, target: &prjunnamed_netlist::Value| {
11            $crate::netlist_match! { @TOP@ design target [ $($rule)* ] $($rest)* }
12        }
13    };
14    { @TOP@ $design:ident $target:ident $($rest:tt)* } => {
15        {
16            if $target.len() > 0 {
17                use $crate::{Pattern, DesignDyn};
18                let design = $crate::CellCollector::new($design);
19                $crate::netlist_match! { @RULE@ design $target $($rest)* }
20            } else {
21                None
22            }
23        }
24    };
25    { @RULE@ $design:ident $target:ident } => { None };
26    { @RULE@ $design:ident $target:ident [ $($pat:tt)+ ] $( if $gexpr:expr )? => $result:expr; $($rest:tt)* } => {
27        {
28            'block: {
29                $design.clear();
30                let pattern = $crate::netlist_match!( @NEW@ [ $($pat)+ ] );
31                match pattern.execute(&$design, $target) {
32                    Some($crate::netlist_match!( @PAT@ [ $($pat)+ ] )) => {
33                        let _guard = $design.inner().use_metadata_from(&$design.cells());
34                        $( if $gexpr )? {
35                            if cfg!(feature = "trace") {
36                                eprintln!(">match {} => {}",
37                                    stringify!([ $($pat)* ] $( if $gexpr )?).replace("\n", " "),
38                                    $design.inner().display_value(&*$target)
39                                );
40                            }
41                            break 'block Some($result.into())
42                        }
43                    }
44                    _ => ()
45                }
46                $crate::netlist_match! { @RULE@ $design $target $($rest)* }
47            }
48        }
49    };
50    { @RULE@ $design:ident $target:ident [ $($pat:tt)+ ] if let $gpat:pat = $gexpr:expr => $result:expr; $($rest:tt)* } => {
51        {
52            'block: {
53                $design.clear();
54                let pattern = $crate::netlist_match!( @NEW@ [ $($pat)+ ] );
55                match pattern.execute(&$design, $target) {
56                    Some($crate::netlist_match!( @PAT@ [ $($pat)+ ] )) => {
57                        let _guard = $design.inner().use_metadata_from(&$design.cells());
58                        if let $gpat = $gexpr {
59                            if cfg!(feature = "trace") {
60                                eprintln!(">match {} => {}",
61                                    stringify!([ $($pat)* ] if let $gpat = $gexpr).replace("\n", " "),
62                                    $design.inner().display_value(&*$target)
63                                );
64                            }
65                            break 'block Some($result.into())
66                        }
67                    }
68                    _ => ()
69                }
70                $crate::netlist_match! { @RULE@ $design $target $($rest)* }
71            }
72        }
73    };
74    ( @NEW@ [ $pat:ident $( @ $cap:ident )? $( ( $($exparg:tt)+ ) )* $( [ $($patarg:tt)+ ] )* ] ) => {
75        $pat::new( $( $($exparg)+, )* $( $crate::netlist_match!( @NEW@ [ $($patarg)+ ] ) ),*)
76    };
77    ( @PAT@ [ $pat:ident $( ( $($exparg:tt)+ ) )* $( [ $($patarg:tt)+ ] )* ] ) => {
78        (_, $( $crate::netlist_match!( @PAT@ [ $($patarg)+ ] ) ),*)
79    };
80    ( @PAT@ [ $pat:ident @ $cap:ident $( ( $($exparg:tt)+ ) )* $( [ $($patarg:tt)+ ] )* ] ) => {
81        ($cap, $( $crate::netlist_match!( @PAT@ [ $($patarg)+ ] ) ),*)
82    };
83}
84
85#[macro_export]
86macro_rules! netlist_replace {
87    { [ $($rule:tt)* ] $($rest:tt)* } => {
88        |design: &dyn $crate::DesignDyn, target: &prjunnamed_netlist::Value| -> bool {
89            $crate::netlist_replace! { @TOP@ design target [ $($rule)* ] $($rest)* }
90        }
91    };
92    { @TOP@ $design:ident $target:ident $($rest:tt)* } => {
93        let result: Option<Value> = $crate::netlist_match! { @TOP@ $design $target $($rest)* };
94        if let Some(replace) = result {
95            #[allow(unexpected_cfgs)]
96            if cfg!(feature = "trace") {
97                eprintln!(">replace => {}",
98                    $design.inner().display_value(&prjunnamed_netlist::Value::from(replace.clone()))
99                );
100            }
101            $design.inner().replace_value($target, &replace);
102            true
103        } else {
104            false
105        }
106    };
107}
108
109#[macro_export]
110macro_rules! assert_netlist {
111    ( $design:expr , $check:expr $( , $( $assertarg:tt)+ )? ) => {
112        {
113            $design.apply();
114            let check = $check;
115            let mut matches = $design.iter_cells().all(|cell_ref| {
116                if let prjunnamed_netlist::Cell::Output(_name, value) = &*cell_ref.get() {
117                    check(&$design, value).unwrap_or(false)
118                } else {
119                    true
120                }
121            });
122            if !matches {
123                eprintln!("{}", $design);
124            }
125            assert!(matches $( , $( $assertarg )+ )?);
126        }
127    };
128}
129
130mod traits;
131mod simple;
132mod bitwise;
133mod shift;
134mod arithmetic;
135
136pub use traits::{NetOrValue, DesignDyn, CellCollector};
137
138pub mod patterns {
139    pub use crate::simple::*;
140    pub use crate::bitwise::*;
141    pub use crate::shift::*;
142    pub use crate::arithmetic::*;
143}