netlist_db/parser/
instance.rs

1use super::utils::{
2    key_value, loss_sep, many0_dummyfirst, multiline_sep, name, name_char, name_str, ports_params,
3    value,
4};
5use crate::{
6    instance::{
7        BJTBuilder, CapacitorBuilder, CurrentBuilder, CurrentSourceBuilder, DiodeBuilder,
8        InductorBuilder, InstanceBuilder, InstanceCtxBuilder, MOSFETBuilder, PWLBuilder,
9        ResistorBuilder, SubcktBuilder, TimeValuePointBuilder, VoltageBuilder,
10        VoltageSourceBuilder,
11    },
12    span::LocatedSpan,
13};
14use nom::{
15    IResult, Parser,
16    branch::alt,
17    character::char,
18    combinator::{map, map_res},
19    multi::many1,
20};
21
22#[inline]
23pub(super) fn instance(mut i: LocatedSpan) -> IResult<LocatedSpan, InstanceBuilder> {
24    let first_char;
25    let name;
26    (i, (first_char, name)) = name_char(i)?;
27    let parser = match first_char.to_ascii_lowercase() {
28        b'r' => _resistor,
29        b'c' => _capacitor,
30        b'l' => _inductor,
31        b'v' => _voltage,
32        b'i' => _current,
33        b'm' => _mosfet,
34        b'q' => _bjt,
35        b'd' => _diode,
36        b'x' => _subckt,
37        r#type => {
38            return map(ports_params, |(nodes, params)| InstanceBuilder {
39                name,
40                ctx: InstanceCtxBuilder::Unknown {
41                    r#type,
42                    nodes,
43                    params,
44                },
45            })
46            .parse_complete(i);
47        }
48    };
49    map(parser, |ctx| InstanceBuilder { name, ctx }).parse_complete(i)
50}
51
52#[inline]
53fn _resistor(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
54    map(
55        (
56            multiline_sep(name),
57            multiline_sep(name),
58            multiline_sep(value),
59        ),
60        |(n1, n2, value)| InstanceCtxBuilder::Resistor(ResistorBuilder { n1, n2, value }),
61    )
62    .parse_complete(i)
63}
64#[inline]
65fn _capacitor(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
66    map(
67        (
68            multiline_sep(name),
69            multiline_sep(name),
70            multiline_sep(value),
71        ),
72        |(n1, n2, value)| InstanceCtxBuilder::Capacitor(CapacitorBuilder { n1, n2, value }),
73    )
74    .parse_complete(i)
75}
76#[inline]
77fn _inductor(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
78    map(
79        (
80            multiline_sep(name),
81            multiline_sep(name),
82            multiline_sep(value),
83        ),
84        |(n1, n2, value)| InstanceCtxBuilder::Inductor(InductorBuilder { n1, n2, value }),
85    )
86    .parse_complete(i)
87}
88#[inline]
89fn _mosfet(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
90    map_res(ports_params, |(ports, params)| match ports.len() {
91        4 => Ok(InstanceCtxBuilder::MOSFET(MOSFETBuilder {
92            nd: ports[0],
93            ng: ports[1],
94            ns: ports[2],
95            nb: None,
96            mname: ports[3],
97            params,
98        })),
99        5 => Ok(InstanceCtxBuilder::MOSFET(MOSFETBuilder {
100            nd: ports[0],
101            ng: ports[1],
102            ns: ports[2],
103            nb: Some(ports[3]),
104            mname: ports[4],
105            params,
106        })),
107        0 => Err("There is no model name".to_string()),
108        n => Err(format!(
109            "MOSFET is 3/4 ports device, but found {} port(s)",
110            n - 1
111        )),
112    })
113    .parse_complete(i)
114}
115#[inline]
116fn _bjt(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
117    map_res(ports_params, |(ports, params)| match ports.len() {
118        4 => Ok(InstanceCtxBuilder::BJT(BJTBuilder {
119            nc: ports[0],
120            nb: ports[1],
121            ne: ports[2],
122            ns: None,
123            mname: ports[3],
124            params,
125        })),
126        5 => Ok(InstanceCtxBuilder::BJT(BJTBuilder {
127            nc: ports[0],
128            nb: ports[1],
129            ne: ports[2],
130            ns: Some(ports[3]),
131            mname: ports[4],
132            params,
133        })),
134        0 => Err("There is no model name".to_string()),
135        n => Err(format!(
136            "BJT is 3/4 ports device, but found {} port(s)",
137            n - 1
138        )),
139    })
140    .parse_complete(i)
141}
142#[inline]
143fn _diode(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
144    map_res(ports_params, |(ports, params)| match ports.len() {
145        3 => Ok(InstanceCtxBuilder::Diode(DiodeBuilder {
146            nplus: ports[0],
147            nminus: ports[1],
148            mname: ports[2],
149            params,
150        })),
151        0 => Err("There is no model name".to_string()),
152        n => Err(format!(
153            "Diode is 2 ports device, but found {} port(s)",
154            n - 1
155        )),
156    })
157    .parse_complete(i)
158}
159#[inline]
160fn _subckt(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
161    map_res(ports_params, |(mut nodes, params)| {
162        if let Some(cktname) = nodes.pop() {
163            Ok(InstanceCtxBuilder::Subckt(SubcktBuilder {
164                nodes,
165                cktname,
166                params,
167            }))
168        } else {
169            Err("There is no subckt name")
170        }
171    })
172    .parse_complete(i)
173}
174#[inline]
175fn _pwl(i: LocatedSpan) -> IResult<LocatedSpan, PWLBuilder> {
176    map_res(
177        (
178            multiline_sep(name_str),
179            loss_sep,
180            char('('),
181            loss_sep,
182            value,
183            many0_dummyfirst(multiline_sep(value)),
184            loss_sep,
185            char(')'),
186        ),
187        |((tag, _), _, _, _, first, mut points, _, _)| {
188            if tag.to_ascii_uppercase().eq("PWL") {
189                if let Some(dummy_first) = points.first_mut() {
190                    *dummy_first = first;
191                    if points.len() % 2 != 0 {
192                        Err("points should be 2N numbers")
193                    } else {
194                        Ok(PWLBuilder {
195                            points: points
196                                .chunks_exact(2)
197                                .map(|values| TimeValuePointBuilder {
198                                    time: values[0],
199                                    value: values[1],
200                                })
201                                .collect(),
202                            ..Default::default()
203                        })
204                    }
205                } else {
206                    Err("points should at least 2")
207                }
208            } else {
209                Err("Want PWL keyword")
210            }
211        },
212    )
213    .parse_complete(i)
214}
215#[inline]
216fn _voltage(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
217    map(
218        (
219            multiline_sep(name),
220            multiline_sep(name),
221            alt((
222                map(many1(multiline_sep(key_value)), |params| {
223                    VoltageSourceBuilder::Params(params)
224                }),
225                map(_pwl, VoltageSourceBuilder::PWL),
226                map(multiline_sep(value), VoltageSourceBuilder::Value),
227            )),
228        ),
229        |(n1, n2, source)| InstanceCtxBuilder::Voltage(VoltageBuilder { n1, n2, source }),
230    )
231    .parse_complete(i)
232}
233#[inline]
234fn _current(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
235    map(
236        (
237            multiline_sep(name),
238            multiline_sep(name),
239            alt((
240                map(many1(multiline_sep(key_value)), |params| {
241                    CurrentSourceBuilder::Params(params)
242                }),
243                map(_pwl, CurrentSourceBuilder::PWL),
244                map(multiline_sep(value), CurrentSourceBuilder::Value),
245            )),
246        ),
247        |(n1, n2, source)| InstanceCtxBuilder::Current(CurrentBuilder { n1, n2, source }),
248    )
249    .parse_complete(i)
250}