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}