prjunnamed_pattern/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
pub trait Pattern<Target> {
    type Capture;

    fn execute(&self, design: &dyn DesignDyn, target: &Target) -> Option<Self::Capture>;
}

#[macro_export]
macro_rules! netlist_match {
    { [ $($rule:tt)* ] $($rest:tt)* } => {
        |design: &dyn $crate::DesignDyn, target: &prjunnamed_netlist::Value| {
            $crate::netlist_match! { @TOP@ design target [ $($rule)* ] $($rest)* }
        }
    };
    { @TOP@ $design:ident $target:ident $($rest:tt)* } => {
        {
            if $target.len() > 0 {
                use $crate::{Pattern, DesignDyn};
                let design = $crate::CellCollector::new($design);
                $crate::netlist_match! { @RULE@ design $target $($rest)* }
            } else {
                None
            }
        }
    };
    { @RULE@ $design:ident $target:ident } => { None };
    { @RULE@ $design:ident $target:ident [ $($pat:tt)+ ] $( if $gexpr:expr )? => $result:expr; $($rest:tt)* } => {
        {
            'block: {
                $design.clear();
                let pattern = $crate::netlist_match!( @NEW@ [ $($pat)+ ] );
                match pattern.execute(&$design, $target) {
                    Some($crate::netlist_match!( @PAT@ [ $($pat)+ ] )) => {
                        let _guard = $design.inner().use_metadata_from(&$design.cells());
                        $( if $gexpr )? {
                            if cfg!(feature = "trace") {
                                eprintln!(">match {} => {}",
                                    stringify!([ $($pat)* ] $( if $gexpr )?).replace("\n", " "),
                                    $design.inner().display_value(&*$target)
                                );
                            }
                            break 'block Some($result.into())
                        }
                    }
                    _ => ()
                }
                $crate::netlist_match! { @RULE@ $design $target $($rest)* }
            }
        }
    };
    { @RULE@ $design:ident $target:ident [ $($pat:tt)+ ] if let $gpat:pat = $gexpr:expr => $result:expr; $($rest:tt)* } => {
        {
            'block: {
                $design.clear();
                let pattern = $crate::netlist_match!( @NEW@ [ $($pat)+ ] );
                match pattern.execute(&$design, $target) {
                    Some($crate::netlist_match!( @PAT@ [ $($pat)+ ] )) => {
                        let _guard = $design.inner().use_metadata_from(&$design.cells());
                        if let $gpat = $gexpr {
                            if cfg!(feature = "trace") {
                                eprintln!(">match {} => {}",
                                    stringify!([ $($pat)* ] if let $gpat = $gexpr).replace("\n", " "),
                                    $design.inner().display_value(&*$target)
                                );
                            }
                            break 'block Some($result.into())
                        }
                    }
                    _ => ()
                }
                $crate::netlist_match! { @RULE@ $design $target $($rest)* }
            }
        }
    };
    ( @NEW@ [ $pat:ident $( @ $cap:ident )? $( ( $($exparg:tt)+ ) )* $( [ $($patarg:tt)+ ] )* ] ) => {
        $pat::new( $( $($exparg)+, )* $( $crate::netlist_match!( @NEW@ [ $($patarg)+ ] ) ),*)
    };
    ( @PAT@ [ $pat:ident $( ( $($exparg:tt)+ ) )* $( [ $($patarg:tt)+ ] )* ] ) => {
        (_, $( $crate::netlist_match!( @PAT@ [ $($patarg)+ ] ) ),*)
    };
    ( @PAT@ [ $pat:ident @ $cap:ident $( ( $($exparg:tt)+ ) )* $( [ $($patarg:tt)+ ] )* ] ) => {
        ($cap, $( $crate::netlist_match!( @PAT@ [ $($patarg)+ ] ) ),*)
    };
}

#[macro_export]
macro_rules! netlist_replace {
    { [ $($rule:tt)* ] $($rest:tt)* } => {
        |design: &dyn $crate::DesignDyn, target: &prjunnamed_netlist::Value| -> bool {
            $crate::netlist_replace! { @TOP@ design target [ $($rule)* ] $($rest)* }
        }
    };
    { @TOP@ $design:ident $target:ident $($rest:tt)* } => {
        let result: Option<Value> = $crate::netlist_match! { @TOP@ $design $target $($rest)* };
        if let Some(replace) = result {
            #[allow(unexpected_cfgs)]
            if cfg!(feature = "trace") {
                eprintln!(">replace => {}",
                    $design.inner().display_value(&prjunnamed_netlist::Value::from(replace.clone()))
                );
            }
            $design.inner().replace_value($target, &replace);
            true
        } else {
            false
        }
    };
}

#[macro_export]
macro_rules! assert_netlist {
    ( $design:expr , $check:expr $( , $( $assertarg:tt)+ )? ) => {
        {
            $design.apply();
            let check = $check;
            let mut matches = $design.iter_cells().all(|cell_ref| {
                if let prjunnamed_netlist::Cell::Output(_name, value) = &*cell_ref.get() {
                    check(&$design, value).unwrap_or(false)
                } else {
                    true
                }
            });
            if !matches {
                eprintln!("{}", $design);
            }
            assert!(matches $( , $( $assertarg )+ )?);
        }
    };
}

mod traits;
mod simple;
mod bitwise;
mod shift;
mod arithmetic;

pub use traits::{NetOrValue, DesignDyn, CellCollector};

pub mod patterns {
    pub use crate::simple::*;
    pub use crate::bitwise::*;
    pub use crate::shift::*;
    pub use crate::arithmetic::*;
}