reda_sp/parse/
source.rs

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
9/// I/V<name> pos neg <value>
10pub 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)); // default
262    }
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)"; // 缺频率参数
329        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)"; // 少一个值(奇数个参数)
336        let res = source(input);
337        assert!(matches!(res, Err(Err::Failure(_))));
338    }
339    
340}