1use crate::ir::{Expr, ExprFunc, ExprOp};
28use crate::scan::evaluate_prefix;
29
30pub const MAX_DEPTH: u32 = 512;
32pub const MAX_NODES: u32 = 10_000;
34const PT_STACKSIZE: usize = 200;
36
37#[derive(Clone, Debug, PartialEq, Eq)]
40pub struct ExprError {
41 pub message: String,
42 pub start: usize,
43 pub end: usize,
44}
45
46pub fn parse_expr(text: &str) -> Result<Expr, ExprError> {
50 let (res, used) = parse_prefix(text);
51 let expr = res?;
52 let rest = &text[used..];
53 if let Some(off) = rest.find(|c: char| !matches!(c, ' ' | '\t')) {
54 return Err(ExprError {
55 message: format!("unexpected `{}` after the expression", rest[off..].trim()),
56 start: used + off,
57 end: text.len(),
58 });
59 }
60 Ok(expr)
61}
62
63pub(crate) fn parse_prefix(text: &str) -> (Result<Expr, ExprError>, usize) {
67 let lower = text.to_ascii_lowercase();
68 let mut lx = Lexer {
69 s: lower.as_bytes(),
70 text: &lower,
71 pos: 0,
72 last: END,
73 last_num: false,
74 prev_vi: false,
75 name_mode: false,
76 };
77 let res = parse(&mut lx).and_then(check);
78 (res, lx.pos)
79}
80
81const END: u8 = 0;
83const PLUS: u8 = 1;
84const MINUS: u8 = 2;
85const TIMES: u8 = 3;
86const DIVIDE: u8 = 4;
87const POWER: u8 = 5;
88const UMINUS: u8 = 6;
89const LPAREN: u8 = 7;
90const RPAREN: u8 = 8;
91const VALUE: u8 = 9;
92const COMMA: u8 = 10;
93
94const G: u8 = 1;
95const L: u8 = 2;
96const E: u8 = 3;
97const R: u8 = 4;
98
99#[rustfmt::skip]
102const PREC: [[u8; 11]; 11] = [
103 [ R, L, L, L, L, L, L, L, R, L, R ],
105 [ G, G, G, L, L, L, L, L, G, L, G ],
106 [ G, G, G, L, L, L, L, L, G, L, G ],
107 [ G, G, G, G, G, L, L, L, G, L, G ],
108 [ G, G, G, G, G, L, L, L, G, L, G ],
109 [ G, G, G, G, G, L, L, L, G, L, G ],
110 [ G, G, G, G, G, G, G, L, G, L, R ],
111 [ R, L, L, L, L, L, L, L, E, L, L ],
112 [ G, G, G, G, G, G, G, R, G, R, G ],
113 [ G, G, G, G, G, G, G, G, G, R, G ],
114 [ G, L, L, L, L, L, L, L, G, L, G ],
115];
116
117#[derive(Debug)]
120enum P {
121 Num(f64),
122 V(String),
123 I(String),
124 Bin(ExprOp, Box<Pn>, Box<Pn>),
125 Comma(Box<Pn>, Box<Pn>),
126 Func(ExprFunc, Box<Pn>),
127 Placeholder(String),
129}
130
131#[derive(Debug)]
132struct Pn {
133 p: P,
134 depth: u32,
135 nodes: u32,
136 start: usize,
137 end: usize,
138}
139
140impl Pn {
141 fn leaf(p: P, start: usize, end: usize) -> Pn {
142 Pn {
143 p,
144 depth: 1,
145 nodes: 1,
146 start,
147 end,
148 }
149 }
150}
151
152#[derive(Debug)]
153enum Val {
154 Num(f64),
155 Str(String),
157 Name(String),
159 Node(Pn),
161}
162
163#[derive(Debug)]
164struct El {
165 tok: u8,
166 val: Option<Val>,
167 start: usize,
168 end: usize,
169}
170
171fn err(message: impl Into<String>, start: usize, end: usize) -> ExprError {
172 ExprError {
173 message: message.into(),
174 start,
175 end,
176 }
177}
178
179struct Lexer<'a> {
180 s: &'a [u8],
181 text: &'a str,
182 pos: usize,
183 last: u8,
186 last_num: bool,
187 prev_vi: bool,
189 name_mode: bool,
191}
192
193impl Lexer<'_> {
194 fn at_end(&self) -> bool {
195 self.pos >= self.s.len() || self.s[self.pos] == 0
196 }
197
198 fn next(&mut self) -> El {
200 while self.pos < self.s.len() && matches!(self.s[self.pos], b' ' | b'\t' | b'=') {
201 self.pos += 1;
202 }
203 let start = self.pos;
204 let after_value = self.last == VALUE || self.last == RPAREN;
205 let mut val = None;
206 let tok = if self.at_end() {
207 END
208 } else {
209 let c = self.s[self.pos];
210 if self.name_mode && !after_value && !matches!(c, b',' | b'(' | b')') {
211 let mut e = self.pos;
212 while e < self.s.len()
213 && !matches!(self.s[e], b' ' | b'\t' | b',' | b'(' | b')' | 0)
214 {
215 e += 1;
216 }
217 val = Some(Val::Name(self.text[self.pos..e].to_string()));
218 self.pos = e;
219 VALUE
220 } else {
221 match c {
222 b',' => {
223 self.pos += 1;
224 COMMA
225 }
226 b'-' => {
227 self.pos += 1;
228 if after_value { MINUS } else { UMINUS }
229 }
230 b'+' => {
231 self.pos += 1;
232 PLUS
233 }
234 b'*' => {
235 self.pos += 1;
236 TIMES
237 }
238 b'/' => {
239 self.pos += 1;
240 DIVIDE
241 }
242 b'^' => {
243 self.pos += 1;
244 POWER
245 }
246 b'(' => {
247 if (self.last == VALUE && self.last_num) || self.last == RPAREN {
248 END
249 } else {
250 self.pos += 1;
251 if self.prev_vi {
252 self.name_mode = true;
253 }
254 LPAREN
255 }
256 }
257 b')' => {
258 self.pos += 1;
259 self.name_mode = false;
260 RPAREN
261 }
262 _ if after_value => END,
263 _ => {
264 if let Some((v, n)) = evaluate_prefix(&self.s[self.pos..]) {
265 self.pos += n;
266 val = Some(Val::Num(v));
267 } else {
268 let mut e = self.pos;
269 while e < self.s.len()
270 && !matches!(
271 self.s[e],
272 b' ' | b'\t'
273 | b'('
274 | b')'
275 | b'^'
276 | b'+'
277 | b'-'
278 | b'*'
279 | b'/'
280 | b','
281 | 0
282 )
283 {
284 e += 1;
285 }
286 val = Some(Val::Str(self.text[self.pos..e].to_string()));
287 self.pos = e;
288 }
289 VALUE
290 }
291 }
292 }
293 };
294 self.last = tok;
295 self.last_num = matches!(val, Some(Val::Num(_)));
296 self.prev_vi = matches!(&val, Some(Val::Str(s)) if s == "v" || s == "i");
297 El {
298 tok,
299 val,
300 start,
301 end: self.pos.max(start),
302 }
303 }
304}
305
306fn parse(lx: &mut Lexer) -> Result<Pn, ExprError> {
308 let mut stack: Vec<El> = vec![El {
309 tok: END,
310 val: None,
311 start: 0,
312 end: 0,
313 }];
314 let mut next = lx.next();
315 loop {
316 let sp = stack.len() - 1;
317 if !(sp > 1 || next.tok != END) {
318 break;
319 }
320 let mut i = sp;
322 while stack[i].tok == VALUE {
323 i -= 1;
324 }
325 match PREC[usize::from(stack[i].tok)][usize::from(next.tok)] {
326 L | E => {
327 if sp == PT_STACKSIZE - 1 {
328 return Err(err(
329 "expression too deeply nested (parser stack overflow)",
330 next.start,
331 next.end,
332 ));
333 }
334 stack.push(next);
335 next = lx.next();
336 }
337 G => reduce(&mut stack)?,
338 _ => {
339 let (s, e) = if next.tok == END {
340 (stack[sp].start, stack[sp].end.max(next.end))
341 } else {
342 (next.start, next.end)
343 };
344 return Err(err("syntax error in expression", s, e));
345 }
346 }
347 }
348 match stack.get_mut(1) {
349 Some(el) => {
350 let (s, e) = (el.start, el.end);
351 makepnode(el)?.ok_or_else(|| err("syntax error in expression", s, e))
352 }
353 None => Err(err("empty expression", next.start, next.end)),
354 }
355}
356
357fn reduce(stack: &mut Vec<El>) -> Result<(), ExprError> {
360 let st = stack.len() - 1;
361 let mut sp = st;
362 let syntax = |stack: &[El]| {
363 let s = stack.get(1).map_or(0, |e| e.start);
364 let e = stack.last().map_or(0, |e| e.end);
365 err("syntax error in expression", s, e)
366 };
367 if stack[sp].tok == VALUE {
368 sp -= 1;
369 }
370 while sp > 0 {
371 let i = if stack[sp - 1].tok == VALUE { 2 } else { 1 };
372 if sp < i {
373 return Err(syntax(stack));
374 }
375 if PREC[usize::from(stack[sp - i].tok)][usize::from(stack[sp].tok)] == L {
376 break;
377 }
378 sp -= i;
379 }
380 if sp >= 1 && stack[sp - 1].tok == VALUE {
381 sp -= 1;
382 }
383 if sp == 0 {
384 return Err(syntax(stack));
385 }
386 let (hs, he) = (stack[sp].start, stack[st].end);
387 let pn = if st == sp {
388 take_node(stack, st)?
389 } else if stack[sp].tok == UMINUS && st == sp + 1 {
390 let arg = take_node(stack, st)?;
391 mkfnode("-", arg, hs, he)?
392 } else if stack[sp].tok == LPAREN && stack[st].tok == RPAREN {
393 take_node(stack, sp + 1)?
394 } else if stack[sp + 1].tok == LPAREN && stack[st].tok == RPAREN {
395 let arg = take_node(stack, sp + 2)?;
396 let fname = match &stack[sp].val {
397 Some(Val::Str(s) | Val::Name(s)) if stack[sp].tok == VALUE => s.clone(),
398 _ => return Err(syntax(stack)),
399 };
400 mkfnode(&fname, arg, hs, he)?
401 } else {
402 let op = stack[sp + 1].tok;
403 let l = take_node(stack, sp)?;
404 let r = take_node(stack, st)?;
405 mkbnode(op, l, r, hs, he)?
406 };
407 stack.truncate(sp);
408 stack.push(El {
409 tok: VALUE,
410 val: Some(Val::Node(pn)),
411 start: hs,
412 end: he,
413 });
414 Ok(())
415}
416
417fn take_node(stack: &mut [El], i: usize) -> Result<Pn, ExprError> {
420 let el = &mut stack[i];
421 let (s, e) = (el.start, el.end);
422 makepnode(el)?.ok_or_else(|| err("syntax error in expression", s, e))
423}
424
425fn makepnode(el: &mut El) -> Result<Option<Pn>, ExprError> {
428 if el.tok != VALUE {
429 return Ok(None);
430 }
431 let (s, e) = (el.start, el.end);
432 Ok(match el.val.take() {
433 Some(Val::Num(v)) => Some(Pn::leaf(P::Num(v), s, e)),
434 Some(Val::Str(w)) => Some(mksnode(w, s, e)?),
435 Some(Val::Name(w)) => Some(Pn::leaf(P::Placeholder(w), s, e)),
436 Some(Val::Node(pn)) => Some(pn),
437 None => None,
438 })
439}
440
441fn mksnode(w: String, s: usize, e: usize) -> Result<Pn, ExprError> {
444 match w.as_str() {
445 "time" => Err(err(
449 "`time` is not available in a 3f5 B source (its load rejects it); \
450 ngspice's time-dependent B sources are not ported",
451 s,
452 e,
453 )),
454 "e" => Ok(Pn::leaf(P::Num(std::f64::consts::E), s, e)),
455 "pi" => Ok(Pn::leaf(P::Num(std::f64::consts::PI), s, e)),
456 _ => Ok(Pn::leaf(P::Placeholder(w), s, e)),
457 }
458}
459
460fn mkbnode(op: u8, l: Pn, r: Pn, s: usize, e: usize) -> Result<Pn, ExprError> {
462 let depth = 1 + l.depth.max(r.depth);
463 let nodes = 1 + l.nodes + r.nodes;
464 let (l, r) = (Box::new(l), Box::new(r));
465 let node = match op {
466 PLUS => P::Bin(ExprOp::Plus, l, r),
467 MINUS => P::Bin(ExprOp::Minus, l, r),
468 TIMES => P::Bin(ExprOp::Times, l, r),
469 DIVIDE => P::Bin(ExprOp::Divide, l, r),
470 POWER => P::Bin(ExprOp::Power, l, r),
471 COMMA => P::Comma(l, r),
472 _ => return Err(err("syntax error in expression", s, e)),
473 };
474 finish(node, depth, nodes, s, e)
475}
476
477fn finish(p: P, depth: u32, nodes: u32, s: usize, e: usize) -> Result<Pn, ExprError> {
478 if depth > MAX_DEPTH {
479 return Err(err(
480 format!("expression nested deeper than {MAX_DEPTH} levels"),
481 s,
482 e,
483 ));
484 }
485 if nodes > MAX_NODES {
486 return Err(err(
487 format!("expression larger than {MAX_NODES} terms"),
488 s,
489 e,
490 ));
491 }
492 Ok(Pn {
493 p,
494 depth,
495 nodes,
496 start: s,
497 end: e,
498 })
499}
500
501fn mkfnode(fname: &str, arg: Pn, s: usize, e: usize) -> Result<Pn, ExprError> {
503 match fname {
504 "v" => match arg.p {
505 P::Placeholder(n) => Ok(Pn::leaf(P::V(n), s, e)),
506 P::Num(c) => Ok(Pn::leaf(P::V(c_int(c).to_string()), s, e)),
507 P::Comma(a, b) => {
510 let (sa, ea, sb, eb) = (a.start, a.end, b.start, b.end);
511 let l = mkfnode("v", *a, sa, ea)?;
512 let r = mkfnode("v", *b, sb, eb)?;
513 mkbnode(MINUS, l, r, s, e)
514 }
515 _ => Err(err("badly formed node voltage", s, e)),
516 },
517 "i" => match arg.p {
518 P::Placeholder(n) => Ok(Pn::leaf(P::I(n), s, e)),
519 P::Num(c) => Ok(Pn::leaf(P::I(c_int(c).to_string()), s, e)),
520 _ => Err(err("badly formed branch current", s, e)),
521 },
522 "-" => {
523 let (d, n) = (1 + arg.depth, 1 + arg.nodes);
524 finish(P::Func(ExprFunc::Neg, Box::new(arg)), d, n, s, e)
525 }
526 _ => match ExprFunc::TABLE.iter().find(|(n, _)| *n == fname) {
527 Some(&(_, f)) => {
528 let (d, n) = (1 + arg.depth, 1 + arg.nodes);
529 finish(P::Func(f, Box::new(arg)), d, n, s, e)
530 }
531 None => Err(err(format!("no such function `{fname}`"), s, e)),
532 },
533 }
534}
535
536fn c_int(c: f64) -> i64 {
539 if c.is_nan() {
540 0
541 } else {
542 c.trunc().clamp(-2.147_483_648e9, 2.147_483_647e9) as i64
543 }
544}
545
546fn check(pn: Pn) -> Result<Expr, ExprError> {
549 let (s, e) = (pn.start, pn.end);
550 Ok(match pn.p {
551 P::Num(v) => Expr::Num(v),
552 P::V(n) => Expr::V(n),
553 P::I(n) => Expr::I(n),
554 P::Bin(op, l, r) => Expr::Bin(op, Box::new(check(*l)?), Box::new(check(*r)?)),
555 P::Func(f, a) => Expr::Call(f, Box::new(check(*a)?)),
556 P::Comma(..) => return Err(err("misplaced `,` in expression", s, e)),
557 P::Placeholder(w) => {
558 return Err(err(
559 format!(
560 "unknown name `{w}` in expression (expected a number, e, pi, v(…), i(…) or a function call)"
561 ),
562 s,
563 e,
564 ));
565 }
566 })
567}
568
569#[cfg(test)]
570mod tests {
571 use super::*;
572 use Expr::*;
573
574 fn p(s: &str) -> Expr {
575 parse_expr(s).unwrap_or_else(|e| panic!("{s}: {e:?}"))
576 }
577
578 fn bin(op: ExprOp, l: Expr, r: Expr) -> Expr {
579 Bin(op, Box::new(l), Box::new(r))
580 }
581
582 fn call(f: ExprFunc, a: Expr) -> Expr {
583 Call(f, Box::new(a))
584 }
585
586 #[test]
587 fn precedence_and_associativity() {
588 use ExprOp::*;
589 assert_eq!(
591 p("1-2+3*4"),
592 bin(
593 Plus,
594 bin(Minus, Num(1.0), Num(2.0)),
595 bin(Times, Num(3.0), Num(4.0))
596 )
597 );
598 assert_eq!(
600 p("2*3^4^5"),
601 bin(
602 Times,
603 Num(2.0),
604 bin(Power, Num(3.0), bin(Power, Num(4.0), Num(5.0)))
605 )
606 );
607 assert_eq!(
609 p("-2^2"),
610 bin(Power, call(ExprFunc::Neg, Num(2.0)), Num(2.0))
611 );
612 assert_eq!(
613 p("2^-x(1)".replace("x", "v").as_str()),
614 bin(Power, Num(2.0), call(ExprFunc::Neg, V("1".into())))
615 );
616 }
617
618 #[test]
619 fn functions_and_references() {
620 use ExprOp::*;
621 assert_eq!(
622 p("cos(v(1))+sin(v(2))"),
623 bin(
624 Plus,
625 call(ExprFunc::Cos, V("1".into())),
626 call(ExprFunc::Sin, V("2".into()))
627 )
628 );
629 assert_eq!(p("v(a,b)"), bin(Minus, V("a".into()), V("b".into())));
630 assert_eq!(
631 p("v(a,b,c)"),
632 bin(
633 Minus,
634 bin(Minus, V("a".into()), V("b".into())),
635 V("c".into())
636 )
637 );
638 assert_eq!(p("I(VDD)"), I("vdd".into()));
639 assert_eq!(
640 p("exp(pi^i(vdd))"),
641 call(
642 ExprFunc::Exp,
643 bin(Power, Num(std::f64::consts::PI), I("vdd".into()))
644 )
645 );
646 assert_eq!(p("2k*v(1)"), bin(Times, Num(2000.0), V("1".into())));
647 assert_eq!(p("v(1a)"), V("1a".into()));
649 assert_eq!(p("v(e)"), V("e".into()));
650 assert_eq!(p("v( x1.n-2 )"), V("x1.n-2".into()));
651 assert_eq!(p("e"), Num(std::f64::consts::E));
652 }
653
654 #[test]
655 fn prefix_stops_where_a_value_follows_a_value() {
656 let (r, used) = parse_prefix("v(1)*2 i=3");
657 assert!(r.is_ok());
658 assert_eq!(&"v(1)*2 i=3"[used..], "i=3");
659 let (r, used) = parse_prefix("2(3)");
660 assert_eq!(r, Ok(Num(2.0)));
661 assert_eq!(used, 1);
662 }
663
664 #[test]
665 fn errors_have_spans_and_never_panic() {
666 for bad in [
667 "",
668 "+1",
669 "1+",
670 "(",
671 ")",
672 "()",
673 "sin()",
674 "foo(1)",
675 "v()",
676 "v(1)+",
677 "v(sin(1))",
678 "i(1,2)",
679 "x",
680 "1,2",
681 "time",
682 "v(",
683 "((((",
684 "1 + * 2",
685 "-",
686 "sin 1",
687 "v(a,)",
688 ] {
689 let e = parse_expr(bad).expect_err(bad);
690 assert!(
691 e.start <= e.end && e.end <= bad.len().max(e.end),
692 "{bad}: {e:?}"
693 );
694 }
695 let deep = "(".repeat(5000) + "1" + &")".repeat(5000);
697 assert!(parse_expr(&deep).is_err());
698 let long = vec!["1"; 20_000].join("+");
699 assert!(parse_expr(&long).is_err());
700 let neg = "-".repeat(5000) + "1";
701 assert!(parse_expr(&neg).is_err());
702 let pow = vec!["2"; 3000].join("^");
703 assert!(parse_expr(&pow).is_err());
704 }
705}