1use nom::{bytes::complete::tag_no_case, error::{context, VerboseError, VerboseErrorKind}};
2use nom::character::complete::char;
3use nom::combinator::{opt, map};
4use nom::branch::alt;
5use reda_unit::{num, u, Current, Voltage};
6use crate::{model::{AcCurrent, PulseVoltage, PwlVoltage, SineVoltage, Source, SourceKind, SourceValue}, AcVoltage};
7use super::{angle_number, current_number, frequency_number, hws, identifier, node, number, time_number, voltage_number, NomResult, ToFailure};
8
9pub fn source(input: &str) -> NomResult<Source> {
11 context("source", |input| {
12 let (input, name) = context("name", hws(identifier))(input)?;
13 let first_char = name.chars().next().unwrap_or_default().to_ascii_uppercase();
14
15 let src_kind = if first_char == 'V' {
16 SourceKind::Voltage
17 } else if first_char == 'I' {
18 SourceKind::Current
19 } else {
20 return Err(nom::Err::Error(VerboseError {
21 errors: [(input, VerboseErrorKind::Context("Source must begin with V or I"))].into(),
22 }));
23 };
24
25 let (input, node_pos) = context("node_pos", hws(node))(input).to_failure()?;
26 let (input, node_neg) = context("node_neg", hws(node))(input).to_failure()?;
27 let (input, value) = context("source_value", hws(move |i| source_value(i, src_kind)))(input).to_failure()?;
28
29 Ok((
30 input,
31 Source {
32 name: name[1..].to_string(),
33 node_pos: node_pos.to_string(),
34 node_neg: node_neg.to_string(),
35 value,
36 },
37 ))
38 })(input)
39}
40
41pub fn source_value(input: &str, kind: SourceKind) -> NomResult<SourceValue> {
42 match kind {
43 SourceKind::Voltage => context("source_value", alt((
44 map(dc_voltage, SourceValue::DcVoltage),
45 map(ac_voltage, SourceValue::AcVoltage),
46 map(sine_voltage, SourceValue::Sin),
47 map(pwl_voltage, SourceValue::Pwl),
48 map(pulse_voltage, SourceValue::Pulse),
49 )))(input),
50 SourceKind::Current => context("source_value", alt((
51 map(dc_current, SourceValue::DcCurrent),
52 map(ac_current, SourceValue::AcCurrent),
53 map(sine_voltage, SourceValue::Sin),
54 map(pwl_voltage, SourceValue::Pwl),
55 map(pulse_voltage, SourceValue::Pulse),
56 )))(input)
57 }
58}
59
60pub fn dc_voltage(input: &str) -> NomResult<Voltage> {
61 context("dc", |input| {
62 let (input, opt_result) = opt(alt((
63 hws(tag_no_case("DC=")),
64 hws(tag_no_case("DC")),
65 )))(input)?;
66
67 let (input, value) = if opt_result.is_some() {
68 hws(voltage_number)(input).to_failure()?
69 } else {
70 hws(voltage_number)(input)?
71 };
72
73 Ok((input, value))
74 })(input)
75}
76
77pub fn dc_current(input: &str) -> NomResult<Current> {
78 context("dc", |input| {
79 let (input, opt_result) = opt(alt((
80 hws(tag_no_case("DC=")),
81 hws(tag_no_case("DC")),
82 )))(input)?;
83
84 let (input, value) = if opt_result.is_some() {
85 hws(current_number)(input).to_failure()?
86 } else {
87 hws(current_number)(input)?
88 };
89
90 Ok((input, value))
91 })(input)
92}
93
94pub fn ac_voltage(input: &str) -> NomResult<AcVoltage> {
95 context("ac voltage", |input| {
96 let (input, opt_result) = opt(alt((
97 hws(tag_no_case("AC=")),
98 hws(tag_no_case("AC")),
99 )))(input)?;
100
101 let (input, (magnitude, phase_deg)) = if opt_result.is_some() {
102 let (input, magnitude) = hws(voltage_number)(input).to_failure()?;
103 let (input, phase_deg) = hws(angle_number)(input).to_failure()?;
104 (input, (magnitude, phase_deg))
105 } else {
106 let (input, magnitude) = hws(voltage_number)(input)?;
107 let (input, phase_deg) = hws(angle_number)(input)?;
108 (input, (magnitude, phase_deg))
109 };
110
111 Ok((input, AcVoltage { magnitude, phase_deg }))
112 })(input)
113}
114
115pub fn ac_current(input: &str) -> NomResult<AcCurrent> {
116 context("ac current", |input| {
117 let (input, opt_result) = opt(alt((
118 hws(tag_no_case("AC=")),
119 hws(tag_no_case("AC")),
120 )))(input)?;
121
122 let (input, (magnitude, phase_deg)) = if opt_result.is_some() {
123 let (input, magnitude) = hws(current_number)(input).to_failure()?;
124 let (input, phase_deg) = hws(angle_number)(input).to_failure()?;
125 (input, (magnitude, phase_deg))
126 } else {
127 let (input, magnitude) = hws(current_number)(input)?;
128 let (input, phase_deg) = hws(angle_number)(input)?;
129 (input, (magnitude, phase_deg))
130 };
131
132 Ok((input, AcCurrent { magnitude, phase_deg }))
133 })(input)
134}
135
136pub fn sine_voltage(input: &str) -> NomResult<SineVoltage> {
137 context("SIN", |input| {
138 let (input, _) = hws(tag_no_case("SIN"))(input)?;
139 let (input, _) = hws(char('('))(input).to_failure()?;
140
141 let (input, vo) = context("vo", hws(voltage_number))(input).to_failure()?;
142 let (input, va) = context("va", hws(voltage_number))(input).to_failure()?;
143 let (input, freq_hz) = context("freq", hws(frequency_number))(input).to_failure()?;
144 let (input, delay) = context("td", opt(hws(time_number)))(input).to_failure()?;
145 let (input, damping) = context("a", opt(hws(frequency_number)))(input).to_failure()?;
146 let (input, phase_deg) = context("phase", opt(hws(number)))(input).to_failure()?;
147 let (input, _) = hws(char(')'))(input).to_failure()?;
148
149 Ok((
150 input,
151 SineVoltage {
152 vo,
153 va,
154 freq_hz,
155 delay: delay.unwrap_or(u!(0.0 s)),
156 damping: damping.unwrap_or(u!(0.0 hz)),
157 phase_deg: phase_deg.unwrap_or(num!(0.0)),
158 },
159 ))
160 })(input)
161}
162
163pub fn pwl_voltage(input: &str) -> NomResult<PwlVoltage> {
164 context("PWL", |input| {
165 let (input, _) = hws(tag_no_case("PWL"))(input)?;
166 let (input, _) = hws(char('('))(input).to_failure()?;
167
168 let mut points = Vec::new();
169 let mut input = input;
170
171 loop {
172 let (i, t) = hws(time_number)(input).to_failure()?;
173 let (i, v) = hws(voltage_number)(i).to_failure()?;
174 points.push((t, v));
175 input = i;
176
177 let (i, end) = opt(hws(char(')')))(input).to_failure()?;
178 if end.is_some() {
179 input = i;
180 break;
181 }
182 }
183
184 Ok((input, PwlVoltage { points }))
185 })(input)
186}
187
188pub fn pulse_voltage(input: &str) -> NomResult<PulseVoltage> {
189 context("PULSE", |input| {
190 let (input, _) = hws(tag_no_case("PULSE"))(input)?;
191 let (input, _) = hws(char('('))(input).to_failure()?;
192
193 let (input, v0) = context("v0", hws(voltage_number))(input).to_failure()?;
194 let (input, v1) = context("v1", hws(voltage_number))(input).to_failure()?;
195 let (input, delay) = context("td", hws(time_number))(input).to_failure()?;
196 let (input, rise) = context("tr", hws(time_number))(input).to_failure()?;
197 let (input, fall) = context("tf", hws(time_number))(input).to_failure()?;
198 let (input, width) = context("tw", hws(time_number))(input).to_failure()?;
199 let (input, period) = context("to", hws(time_number))(input).to_failure()?;
200 let (input, _) = hws(char(')'))(input).to_failure()?;
201
202 Ok((
203 input,
204 PulseVoltage {
205 v0,
206 v1,
207 delay,
208 rise,
209 fall,
210 width,
211 period,
212 },
213 ))
214 })(input)
215}
216
217#[allow(unused)]
218#[cfg(test)]
219mod test {
220 use nom::Err;
221
222 use reda_unit::{num, u};
223 use super::*;
224
225 #[test]
226 fn test_dc_source_voltage() {
227 let (_, s) = dc_voltage("DC 5V").unwrap();
228 assert_eq!(s, u!(5.0 V));
229 }
230
231 #[test]
232 fn test_dc_source_current_no_keyword() {
233 let (_, s) = dc_current("1.2mA").unwrap();
234 assert_eq!(s, u!(1.2 mA));
235 }
236
237 #[test]
238 fn test_dc_source_equals_syntax() {
239 let (_, s) = dc_current("DC=1.0").unwrap();
240 assert_eq!(s, u!(1.0 A));
241 }
242
243 #[test]
244 fn test_ac_voltage_source() {
245 let (_, src) = ac_voltage("AC 1.0 90").unwrap();
246 assert_eq!(src.magnitude, u!(1.0 V));
247 assert_eq!(src.phase_deg, u!(90.0 rad));
248 }
249
250 #[test]
251 fn test_ac_current_source_with_ac_eq() {
252 let (_, src) = ac_current("AC=2.5 180").unwrap();
253 assert_eq!(src.magnitude, u!(2.5 A));
254 assert_eq!(src.phase_deg, u!(180.0 rad));
255 }
256
257 #[test]
258 fn test_sine_voltage_basic() {
259 let (_, s) = sine_voltage("SIN(0 1 1k)").unwrap();
260 assert_eq!(s.freq_hz, u!(1.0 kHz));
261 assert_eq!(s.phase_deg, num!(0.0)); }
263
264 #[test]
265 fn test_pwl_voltage_points() {
266 let (_, s) = pwl_voltage("PWL(0 0 1n 1.8 2n 0)").unwrap();
267 assert_eq!(s.points.len(), 3);
268 }
269
270 #[test]
271 fn test_pulse_voltage() {
272 let (_, s) = pulse_voltage("PULSE(0 1 1n 1n 1n 10n 20n)").unwrap();
273 assert_eq!(s.v1, u!(1.0 V));
274 assert_eq!(s.width, u!(10.0 ns));
275 }
276
277 #[test]
278 fn test_source_sine() {
279 let (_, src) = source("Vsig n1 0 SIN(0 1 1k 0.1 0.05 45)").unwrap();
280 assert_eq!(src.name, "sig");
281 match src.value {
282 SourceValue::Sin(s) => {
283 assert_eq!(s.freq_hz, u!(1.0 kHz));
284 assert_eq!(s.phase_deg, num!(45.0));
285 },
286 _ => panic!("Expected sine voltage"),
287 }
288 }
289
290 #[test]
291 fn test_source_dc_voltage() {
292 let (_, src) = source("Vdd vdd 0 1.8").unwrap();
293 match src.value {
294 SourceValue::DcVoltage(dc) => {
295 assert_eq!(dc, u!(1.8 V));
296 },
297 _ => panic!("Expected DC source"),
298 }
299 }
300
301 #[test]
302 fn test_source_ac_current() {
303 let (_, src) = source("Iin in 0 AC 2.0 180").unwrap();
304 match src.value {
305 SourceValue::AcCurrent(ac) => {
306 assert_eq!(ac.magnitude, u!(2.0 A));
307 },
308 _ => panic!("Expected AC source"),
309 }
310 }
311
312 #[test]
313 fn test_source_bad_prefix() {
314 let input = "X1 0 N001 5";
315 let res = source(input);
316 assert!(matches!(res, Err(Err::Error(_))));
317 }
318
319 #[test]
320 fn test_source_missing_value() {
321 let input = "V1 0 N001";
322 let res = source(input);
323 assert!(matches!(res, Err(Err::Failure(_))));
324 }
325
326 #[test]
327 fn test_source_invalid_sin_format() {
328 let input = "V1 0 N001 SIN(1 0.5)"; let res = source(input);
330 assert!(matches!(res, Err(Err::Failure(_))));
331 }
332
333 #[test]
334 fn test_source_invalid_pwl_point() {
335 let input = "I1 N1 N2 PWL(0 1 2)"; let res = source(input);
337 assert!(matches!(res, Err(Err::Failure(_))));
338 }
339
340}