1use crate::ast::*;
10use crate::lexer::{LexError, Spanned, lex};
11use crate::token::*;
12
13#[derive(Debug, Clone, PartialEq)]
15pub struct ParseError {
16 pub msg: String,
17 pub line: u32,
18 pub col: u32,
19}
20
21impl std::fmt::Display for ParseError {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 write!(f, "{}:{}: {}", self.line, self.col, self.msg)
24 }
25}
26
27impl From<LexError> for ParseError {
28 fn from(e: LexError) -> Self {
29 ParseError {
30 msg: e.msg,
31 line: e.line,
32 col: e.col,
33 }
34 }
35}
36
37pub fn parse(src: &str) -> Result<Picture, ParseError> {
39 let toks = lex(src)?;
40 let toks = preprocess(toks)?;
41 Parser::new(toks).parse_picture()
42}
43
44use std::collections::HashMap;
52
53fn preprocess(input: Vec<Spanned>) -> Result<Vec<Spanned>, ParseError> {
54 let mut macros: HashMap<String, Vec<Spanned>> = HashMap::new();
55 expand(&input, &mut macros, 0)
56}
57
58fn loc(toks: &[Spanned], i: usize) -> (u32, u32) {
59 toks.get(i).map(|s| (s.line, s.col)).unwrap_or((0, 0))
60}
61
62fn expand(
63 toks: &[Spanned],
64 macros: &mut HashMap<String, Vec<Spanned>>,
65 depth: usize,
66) -> Result<Vec<Spanned>, ParseError> {
67 if depth > 64 {
68 return Err(ParseError {
69 msg: "macro expansion too deep (recursive define?)".into(),
70 line: 0,
71 col: 0,
72 });
73 }
74 let mut out = Vec::new();
75 let mut i = 0;
76 while i < toks.len() {
77 match &toks[i].tok {
78 Token::Kw(Kw::Define) => {
79 let (l, c) = loc(toks, i);
80 i += 1;
81 let name = match toks.get(i).map(|s| &s.tok) {
82 Some(Token::Name(n)) | Some(Token::Label(n)) => n.clone(),
83 _ => {
84 return Err(ParseError {
85 msg: "define: expected a macro name".into(),
86 line: l,
87 col: c,
88 });
89 }
90 };
91 i += 1;
92 if toks.get(i).map(|s| &s.tok) != Some(&Token::LeftBrace) {
93 let (l, c) = loc(toks, i);
94 return Err(ParseError {
95 msg: "define: expected `{` (only `define name { body }` is supported)"
96 .into(),
97 line: l,
98 col: c,
99 });
100 }
101 i += 1; let start = i;
103 let mut bd = 1;
104 while i < toks.len() && bd > 0 {
105 match &toks[i].tok {
106 Token::LeftBrace => bd += 1,
107 Token::RightBrace => {
108 bd -= 1;
109 if bd == 0 {
110 break;
111 }
112 }
113 _ => {}
114 }
115 i += 1;
116 }
117 if bd != 0 {
118 return Err(ParseError {
119 msg: "define: unterminated `{` body".into(),
120 line: l,
121 col: c,
122 });
123 }
124 let body = toks[start..i].to_vec();
125 i += 1; macros.insert(name, body);
127 }
128 Token::Kw(Kw::Undef) => {
129 i += 1;
130 if let Some(Token::Name(n)) | Some(Token::Label(n)) = toks.get(i).map(|s| &s.tok) {
131 macros.remove(n);
132 }
133 i += 1;
134 }
135 Token::Name(n) if macros.contains_key(n) => {
136 let body = macros.get(n).unwrap().clone();
137 i += 1;
138 let args = if toks.get(i).map(|s| &s.tok) == Some(&Token::Lparen) {
139 i += 1;
140 let (a, ni) = read_args(toks, i)?;
141 i = ni;
142 a
143 } else {
144 Vec::new()
145 };
146 let sub = substitute(&body, &args);
147 let expanded = expand(&sub, macros, depth + 1)?;
148 out.extend(expanded);
149 }
150 _ => {
151 out.push(toks[i].clone());
152 i += 1;
153 }
154 }
155 }
156 Ok(out)
157}
158
159fn read_args(toks: &[Spanned], mut i: usize) -> Result<(Vec<Vec<Spanned>>, usize), ParseError> {
162 let mut args: Vec<Vec<Spanned>> = Vec::new();
163 let mut cur: Vec<Spanned> = Vec::new();
164 let mut depth = 0i32;
165 loop {
166 let Some(s) = toks.get(i) else {
167 return Err(ParseError {
168 msg: "unterminated macro arguments".into(),
169 line: 0,
170 col: 0,
171 });
172 };
173 match &s.tok {
174 Token::Lparen | Token::LeftBrack | Token::LeftBrace => {
175 depth += 1;
176 cur.push(s.clone());
177 i += 1;
178 }
179 Token::Rparen if depth == 0 => {
180 i += 1;
181 if !cur.is_empty() || !args.is_empty() {
182 args.push(cur);
183 }
184 break;
185 }
186 Token::Rparen | Token::RightBrack | Token::RightBrace => {
187 depth -= 1;
188 cur.push(s.clone());
189 i += 1;
190 }
191 Token::Comma if depth == 0 => {
192 args.push(std::mem::take(&mut cur));
193 i += 1;
194 }
195 _ => {
196 cur.push(s.clone());
197 i += 1;
198 }
199 }
200 }
201 Ok((args, i))
202}
203
204fn substitute(body: &[Spanned], args: &[Vec<Spanned>]) -> Vec<Spanned> {
206 let mut out = Vec::new();
207 for s in body {
208 if let Token::Arg(k) = s.tok {
209 if let Some(a) = args.get((k as usize).wrapping_sub(1)) {
210 out.extend(a.iter().cloned());
211 }
212 } else {
213 out.push(s.clone());
214 }
215 }
216 out
217}
218
219type PResult<T> = Result<T, ParseError>;
220
221struct Parser {
222 toks: Vec<Spanned>,
223 idx: usize,
224}
225
226impl Parser {
227 fn new(toks: Vec<Spanned>) -> Self {
228 Parser { toks, idx: 0 }
229 }
230
231 fn cur(&self) -> &Token {
234 &self.toks[self.idx].tok
235 }
236 fn peek(&self, n: usize) -> &Token {
237 self.toks
238 .get(self.idx + n)
239 .map(|s| &s.tok)
240 .unwrap_or(&Token::Eof)
241 }
242 fn at(&self, t: &Token) -> bool {
243 self.cur() == t
244 }
245 fn bump(&mut self) -> Token {
246 let t = self.toks[self.idx].tok.clone();
247 if self.idx + 1 < self.toks.len() {
248 self.idx += 1;
249 }
250 t
251 }
252 fn eat(&mut self, t: &Token) -> bool {
253 if self.at(t) {
254 self.bump();
255 true
256 } else {
257 false
258 }
259 }
260 fn expect(&mut self, t: &Token) -> PResult<()> {
261 if self.eat(t) {
262 Ok(())
263 } else {
264 self.err(format!("expected {t:?}, found {:?}", self.cur()))
265 }
266 }
267 fn err<T>(&self, msg: impl Into<String>) -> PResult<T> {
268 let s = &self.toks[self.idx];
269 Err(ParseError {
270 msg: msg.into(),
271 line: s.line,
272 col: s.col,
273 })
274 }
275 fn at_kw(&self, k: Kw) -> bool {
276 matches!(self.cur(), Token::Kw(x) if *x == k)
277 }
278 fn eat_kw(&mut self, k: Kw) -> bool {
279 if self.at_kw(k) {
280 self.bump();
281 true
282 } else {
283 false
284 }
285 }
286 fn skip_newlines(&mut self) {
287 while self.at(&Token::Newline) {
288 self.bump();
289 }
290 }
291
292 fn parse_picture(&mut self) -> PResult<Picture> {
295 let (mut width, mut height) = (None, None);
299 let mut seen_ps = false;
300 let mut stmts = Vec::new();
301 loop {
302 self.skip_newlines();
303 match self.cur() {
304 Token::Eof => break,
305 Token::DotPS => {
306 self.bump();
307 if !seen_ps && self.starts_scalar() {
308 width = Some(self.parse_expr()?);
309 if self.starts_scalar() {
310 height = Some(self.parse_expr()?);
311 }
312 }
313 seen_ps = true;
314 while !self.at(&Token::Newline) && !self.at(&Token::Eof) {
315 self.bump();
316 }
317 continue;
318 }
319 Token::DotPE => {
320 self.bump();
321 continue;
322 }
323 _ => {}
324 }
325 stmts.push(self.parse_element()?);
326 if !self.at(&Token::Newline)
327 && !self.at(&Token::Eof)
328 && !self.at(&Token::DotPE)
329 && !self.at(&Token::DotPS)
330 {
331 return self.err(format!("unexpected {:?} after statement", self.cur()));
332 }
333 }
334 Ok(Picture {
335 width,
336 height,
337 stmts,
338 })
339 }
340
341 fn parse_elementlist(&mut self, terminators: &[Token]) -> PResult<Vec<Stmt>> {
343 let mut stmts = Vec::new();
344 loop {
345 self.skip_newlines();
346 if self.at(&Token::Eof) || terminators.iter().any(|t| self.at(t)) {
347 break;
348 }
349 let s = self.parse_element()?;
350 stmts.push(s);
351 if !self.at(&Token::Newline)
353 && !self.at(&Token::Eof)
354 && !terminators.iter().any(|t| self.at(t))
355 {
356 return self.err(format!("unexpected {:?} after statement", self.cur()));
357 }
358 }
359 Ok(stmts)
360 }
361
362 fn parse_element(&mut self) -> PResult<Stmt> {
365 if self.at_kw(Kw::Animate) {
367 return Ok(Stmt::Animate(self.parse_animate()?));
368 }
369
370 match self.cur() {
372 Token::Kw(Kw::If) => return self.parse_if(),
373 Token::Kw(Kw::For) => return self.parse_for(),
374 Token::Kw(Kw::Print) => return self.parse_print(),
375 Token::Kw(Kw::Reset) => return self.parse_reset(),
376 _ => {}
377 }
378
379 if let Token::Kw(k) = self.cur() {
382 match k {
383 Kw::Define | Kw::Undef => {
384 return self.err("only the `define name { body }` macro form is supported");
385 }
386 Kw::Sh | Kw::Exec | Kw::Command | Kw::Copy => {
387 let kw = format!("{k:?}").to_lowercase();
388 return self.err(format!("`{kw}` is not supported yet (planned milestone)"));
389 }
390 _ => {}
391 }
392 }
393
394 if self.eat(&Token::LeftBrace) {
396 let stmts = self.parse_elementlist(&[Token::RightBrace])?;
397 self.expect(&Token::RightBrace)?;
398 return Ok(Stmt::Group(stmts));
399 }
400
401 if matches!(self.cur(), Token::Label(_)) && self.label_colon_ahead() {
403 let label = self.parse_label()?;
404 self.expect(&Token::Colon)?;
405 if self.at_object_start() {
406 let object = self.parse_object()?;
407 return Ok(Stmt::Object {
408 label: Some(label),
409 object,
410 });
411 } else {
412 let pos = self.parse_position()?;
413 return Ok(Stmt::Place { label, pos });
414 }
415 }
416
417 if self.at_assignment_start() {
419 return Ok(Stmt::Assign(self.parse_assignlist()?));
420 }
421
422 if let Token::Dir(d) = self.cur() {
424 let d = *d;
425 if matches!(self.peek(1), Token::Newline | Token::Eof) {
427 self.bump();
428 return Ok(Stmt::Direction(d));
429 }
430 }
431
432 let object = self.parse_object()?;
434 Ok(Stmt::Object {
435 label: None,
436 object,
437 })
438 }
439
440 fn parse_if(&mut self) -> PResult<Stmt> {
441 self.expect_kw(Kw::If)?;
442 let cond = self.parse_expr()?;
443 self.expect_kw(Kw::Then)?;
444 self.expect(&Token::LeftBrace)?;
445 let then_body = self.parse_elementlist(&[Token::RightBrace])?;
446 self.expect(&Token::RightBrace)?;
447 let else_body = if self.eat_kw(Kw::Else) {
448 self.expect(&Token::LeftBrace)?;
449 let b = self.parse_elementlist(&[Token::RightBrace])?;
450 self.expect(&Token::RightBrace)?;
451 Some(b)
452 } else {
453 None
454 };
455 Ok(Stmt::If {
456 cond,
457 then_body,
458 else_body,
459 })
460 }
461
462 fn parse_for(&mut self) -> PResult<Stmt> {
463 self.expect_kw(Kw::For)?;
464 let var = match self.bump() {
465 Token::Name(s) => s,
466 other => return self.err(format!("expected loop variable, found {other:?}")),
467 };
468 match self.bump() {
469 Token::Eq | Token::ColonEq => {}
470 other => return self.err(format!("expected `=` in for, found {other:?}")),
471 }
472 let from = self.parse_expr()?;
473 self.expect_kw(Kw::To)?;
474 let to = self.parse_expr()?;
475 let mut by = Expr::Num(1.0);
476 let mut mult = false;
477 if self.eat_kw(Kw::By) {
478 mult = self.eat(&Token::Mult);
479 by = self.parse_expr()?;
480 }
481 self.expect_kw(Kw::Do)?;
482 self.expect(&Token::LeftBrace)?;
483 let body = self.parse_elementlist(&[Token::RightBrace])?;
484 self.expect(&Token::RightBrace)?;
485 Ok(Stmt::For {
486 var,
487 from,
488 to,
489 by,
490 mult,
491 body,
492 })
493 }
494
495 fn parse_print(&mut self) -> PResult<Stmt> {
496 self.expect_kw(Kw::Print)?;
497 let item = if self.at_string_start() {
498 PrintItem::Str(self.parse_stringexpr()?)
499 } else {
500 PrintItem::Expr(self.parse_expr()?)
501 };
502 Ok(Stmt::Print(item))
503 }
504
505 fn parse_reset(&mut self) -> PResult<Stmt> {
506 self.expect_kw(Kw::Reset)?;
507 let mut list = Vec::new();
508 if let Token::EnvVar(v) = self.cur() {
509 list.push(*v);
510 self.bump();
511 while self.eat(&Token::Comma) {
512 match self.cur() {
513 Token::EnvVar(v) => {
514 list.push(*v);
515 self.bump();
516 }
517 other => {
518 return self.err(format!("expected environment variable, found {other:?}"));
519 }
520 }
521 }
522 }
523 Ok(Stmt::Reset(list))
524 }
525
526 fn at_string_start(&self) -> bool {
527 matches!(
528 self.cur(),
529 Token::Str(_) | Token::Arg(_) | Token::Kw(Kw::Sprintf)
530 )
531 }
532
533 fn parse_animate(&mut self) -> PResult<Animate> {
534 self.expect_kw(Kw::Animate)?;
535 let target = self.parse_place()?;
536 self.expect_kw(Kw::With)?;
537 let effect = self.parse_stringexpr()?;
538 let mut duration = None;
539 let mut timing = Timing::Sequential;
540 let mut delay = None;
541 loop {
542 if self.eat_kw(Kw::For) {
543 duration = Some(self.parse_expr()?);
544 } else if self.eat_kw(Kw::At) {
545 timing = Timing::At(self.parse_expr()?);
546 } else if self.eat_kw(Kw::After) {
547 timing = Timing::After(self.parse_place()?);
548 } else if self.eat_kw(Kw::Delay) {
549 delay = Some(self.parse_expr()?);
550 } else {
551 break;
552 }
553 }
554 Ok(Animate {
555 target,
556 effect,
557 duration,
558 timing,
559 delay,
560 })
561 }
562
563 fn label_colon_ahead(&self) -> bool {
565 match self.peek(1) {
566 Token::Colon => true,
567 Token::LeftBrack => {
568 let mut depth = 0;
570 let mut i = self.idx + 1;
571 while i < self.toks.len() {
572 match &self.toks[i].tok {
573 Token::LeftBrack => depth += 1,
574 Token::RightBrack => {
575 depth -= 1;
576 if depth == 0 {
577 return matches!(
578 self.toks.get(i + 1).map(|s| &s.tok),
579 Some(Token::Colon)
580 );
581 }
582 }
583 Token::Newline | Token::Eof => return false,
584 _ => {}
585 }
586 i += 1;
587 }
588 false
589 }
590 _ => false,
591 }
592 }
593
594 fn at_object_start(&self) -> bool {
595 matches!(
596 self.cur(),
597 Token::Prim(_) | Token::LeftBrack | Token::Block | Token::Str(_)
598 )
599 }
600
601 fn at_assignment_start(&self) -> bool {
602 let assignop = |t: &Token| {
603 matches!(
604 t,
605 Token::Eq
606 | Token::ColonEq
607 | Token::PlusEq
608 | Token::MinusEq
609 | Token::MultEq
610 | Token::DivEq
611 | Token::RemEq
612 )
613 };
614 match self.cur() {
615 Token::Name(_) => assignop(self.peek(1)) || matches!(self.peek(1), Token::LeftBrack),
616 Token::EnvVar(_) => assignop(self.peek(1)),
617 _ => false,
618 }
619 }
620
621 fn parse_label(&mut self) -> PResult<Label> {
622 let name = match self.bump() {
623 Token::Label(s) => s,
624 other => return self.err(format!("expected label, found {other:?}")),
625 };
626 let subscript = if self.eat(&Token::LeftBrack) {
627 let e = self.parse_expr()?;
628 self.expect(&Token::RightBrack)?;
629 Some(e)
630 } else {
631 None
632 };
633 Ok(Label { name, subscript })
634 }
635
636 fn parse_assignlist(&mut self) -> PResult<Vec<Assignment>> {
637 let mut list = vec![self.parse_assignment()?];
638 while self.eat(&Token::Comma) {
639 list.push(self.parse_assignment()?);
640 }
641 Ok(list)
642 }
643
644 fn parse_assignment(&mut self) -> PResult<Assignment> {
645 let target = match self.cur().clone() {
646 Token::Name(name) => {
647 self.bump();
648 let sub = if self.eat(&Token::LeftBrack) {
649 let e = self.parse_expr()?;
650 self.expect(&Token::RightBrack)?;
651 Some(e)
652 } else {
653 None
654 };
655 AssignTarget::Var(name, sub)
656 }
657 Token::EnvVar(v) => {
658 self.bump();
659 AssignTarget::Env(v)
660 }
661 other => return self.err(format!("expected assignment target, found {other:?}")),
662 };
663 let op = match self.bump() {
664 Token::Eq | Token::ColonEq => AssignOp::Set,
665 Token::PlusEq => AssignOp::Add,
666 Token::MinusEq => AssignOp::Sub,
667 Token::MultEq => AssignOp::Mul,
668 Token::DivEq => AssignOp::Div,
669 Token::RemEq => AssignOp::Rem,
670 other => return self.err(format!("expected assignment operator, found {other:?}")),
671 };
672 let value = self.parse_expr()?;
673 Ok(Assignment { target, op, value })
674 }
675
676 fn parse_object(&mut self) -> PResult<Object> {
679 let mut attrs = Vec::new();
680 let kind = match self.cur().clone() {
681 Token::Prim(p) => {
682 self.bump();
683 ObjectKind::Primitive(p)
684 }
685 Token::Block => {
686 self.bump();
687 ObjectKind::Empty
688 }
689 Token::LeftBrack => {
690 self.bump();
691 let stmts = self.parse_elementlist(&[Token::RightBrack])?;
692 self.expect(&Token::RightBrack)?;
693 ObjectKind::Block(stmts)
694 }
695 Token::Str(s) => {
696 self.bump();
697 attrs.push(Attr::Text(self.continue_string(StringExpr::Lit(s))?));
698 ObjectKind::Text
699 }
700 other => return self.err(format!("expected an object, found {other:?}")),
701 };
702 loop {
703 match self.parse_attr()? {
704 Some(a) => attrs.push(a),
705 None => break,
706 }
707 }
708 Ok(Object { kind, attrs })
709 }
710
711 fn parse_attr(&mut self) -> PResult<Option<Attr>> {
712 if self.at_string_start() {
714 return Ok(Some(Attr::Text(self.parse_stringexpr()?)));
715 }
716 let attr = match self.cur().clone() {
717 Token::Kw(Kw::Ht) => {
718 self.bump();
719 Attr::Dim(DimKind::Ht, self.parse_expr()?)
720 }
721 Token::Kw(Kw::Wid) => {
722 self.bump();
723 Attr::Dim(DimKind::Wid, self.parse_expr()?)
724 }
725 Token::Kw(Kw::Rad) => {
726 self.bump();
727 Attr::Dim(DimKind::Rad, self.parse_expr()?)
728 }
729 Token::Kw(Kw::Diam) => {
730 self.bump();
731 Attr::Dim(DimKind::Diam, self.parse_expr()?)
732 }
733 Token::Kw(Kw::Thick) => {
734 self.bump();
735 Attr::Dim(DimKind::Thick, self.parse_expr()?)
736 }
737 Token::Kw(Kw::Scaled) => {
738 self.bump();
739 Attr::Dim(DimKind::Scaled, self.parse_expr()?)
740 }
741 Token::Dir(d) => {
742 self.bump();
743 Attr::Direction(d, self.opt_expr()?)
744 }
745 Token::LineType(lt) => {
746 self.bump();
747 Attr::LineStyle(lt, self.opt_expr()?)
748 }
749 Token::Kw(Kw::Chop) => {
750 self.bump();
751 Attr::Chop(self.opt_expr()?)
752 }
753 Token::Kw(Kw::Fill) => {
754 self.bump();
755 Attr::Fill(self.opt_expr()?)
756 }
757 Token::Arrow(a) => {
758 self.bump();
759 Attr::Arrowhead(a, self.opt_expr()?)
760 }
761 Token::Kw(Kw::Then) => {
762 self.bump();
763 Attr::Then
764 }
765 Token::Kw(Kw::Cw) => {
766 self.bump();
767 Attr::Cw
768 }
769 Token::Kw(Kw::Ccw) => {
770 self.bump();
771 Attr::Ccw
772 }
773 Token::Kw(Kw::Same) => {
774 self.bump();
775 Attr::Same
776 }
777 Token::Kw(Kw::Continue) => {
778 self.bump();
779 Attr::Continue
780 }
781 Token::Kw(Kw::From) => {
782 self.bump();
783 Attr::From(self.parse_position()?)
784 }
785 Token::Kw(Kw::To) => {
786 self.bump();
787 Attr::To(self.parse_position()?)
788 }
789 Token::Kw(Kw::At) => {
790 self.bump();
791 Attr::At(self.parse_position()?)
792 }
793 Token::Kw(Kw::By) => {
794 self.bump();
795 Attr::By(self.parse_position()?)
796 }
797 Token::Kw(Kw::With) => {
798 self.bump();
799 let anchor = if let Token::Corner(c) = self.cur() {
800 let c = *c;
801 self.bump();
802 WithAnchor::Corner(c)
803 } else if self.at(&Token::Lparen) {
804 self.bump();
805 let x = self.parse_expr()?;
806 self.expect(&Token::Comma)?;
807 let y = self.parse_expr()?;
808 self.expect(&Token::Rparen)?;
809 WithAnchor::Pair(x, y)
810 } else {
811 WithAnchor::Plain
812 };
813 self.expect_kw(Kw::At)?;
814 Attr::With {
815 anchor,
816 at: self.parse_position()?,
817 }
818 }
819 Token::TextPos(tp) => {
820 self.bump();
821 Attr::TextPos(tp)
822 }
823 Token::Color(c) => {
824 self.bump();
825 let s = self.parse_stringexpr()?;
826 Attr::Color(c, s)
827 }
828 _ => return Ok(None),
829 };
830 Ok(Some(attr))
831 }
832
833 fn expect_kw(&mut self, k: Kw) -> PResult<()> {
834 if self.eat_kw(k) {
835 Ok(())
836 } else {
837 self.err(format!("expected `{k:?}`, found {:?}", self.cur()))
838 }
839 }
840
841 fn parse_stringexpr(&mut self) -> PResult<StringExpr> {
844 let first = self.parse_string_atom()?;
845 self.continue_string(first)
846 }
847
848 fn continue_string(&mut self, first: StringExpr) -> PResult<StringExpr> {
850 let mut e = first;
851 while self.at(&Token::Plus) && self.string_after_plus() {
852 self.bump();
853 let rhs = self.parse_string_atom()?;
854 e = StringExpr::Concat(Box::new(e), Box::new(rhs));
855 }
856 Ok(e)
857 }
858
859 fn string_after_plus(&self) -> bool {
860 matches!(
861 self.peek(1),
862 Token::Str(_) | Token::Arg(_) | Token::Kw(Kw::Sprintf)
863 )
864 }
865
866 fn parse_string_atom(&mut self) -> PResult<StringExpr> {
867 match self.cur().clone() {
868 Token::Str(s) => {
869 self.bump();
870 Ok(StringExpr::Lit(s))
871 }
872 Token::Arg(n) => {
873 self.bump();
874 Ok(StringExpr::Arg(n))
875 }
876 Token::Kw(Kw::Sprintf) => {
877 self.bump();
878 self.expect(&Token::Lparen)?;
879 let fmt = self.parse_stringexpr()?;
880 let mut args = Vec::new();
881 while self.eat(&Token::Comma) {
882 args.push(self.parse_expr()?);
883 }
884 self.expect(&Token::Rparen)?;
885 Ok(StringExpr::Sprintf(Box::new(fmt), args))
886 }
887 other => self.err(format!("expected a string, found {other:?}")),
888 }
889 }
890
891 fn parse_position(&mut self) -> PResult<Position> {
894 if self.at(&Token::Lparen) || self.at_place_start() {
895 let loc = self.parse_location_operand()?;
896 let shifts = self.parse_shifts()?;
897 return Ok(Position::Place(loc, shifts));
898 }
899 let e1 = self.parse_expr()?;
901 if self.eat(&Token::Comma) {
902 let e2 = self.parse_expr()?;
903 return Ok(Position::Pair(e1, e2));
904 }
905 let of_the_way = if self.eat_kw(Kw::Of) {
906 self.expect_kw(Kw::The)?;
907 self.expect_kw(Kw::Way)?;
908 self.expect_kw(Kw::Between)?;
909 true
910 } else if self.eat_kw(Kw::Between) {
911 false
912 } else {
913 return self.err("expected `,`, `between`, or `of the way between` in position");
914 };
915 let a = self.parse_position()?;
916 self.expect_kw(Kw::And)?;
917 let b = self.parse_position()?;
918 Ok(Position::Between {
919 frac: Box::new(e1),
920 a: Box::new(a),
921 b: Box::new(b),
922 of_the_way,
923 })
924 }
925
926 fn parse_shifts(&mut self) -> PResult<Vec<Shift>> {
927 let mut shifts = Vec::new();
928 loop {
929 let sign = if self.at(&Token::Plus) {
930 Sign::Plus
931 } else if self.at(&Token::Minus) {
932 Sign::Minus
933 } else {
934 break;
935 };
936 self.bump();
937 let loc = self.parse_location_operand()?;
938 shifts.push(Shift { sign, loc });
939 }
940 Ok(shifts)
941 }
942
943 fn parse_location_operand(&mut self) -> PResult<Location> {
946 if self.eat(&Token::Lparen) {
947 let p1 = self.parse_position()?;
948 if self.eat(&Token::Comma) {
949 let p2 = self.parse_position()?;
950 self.expect(&Token::Rparen)?;
951 Ok(Location::ParenPair(Box::new(p1), Box::new(p2)))
952 } else {
953 self.expect(&Token::Rparen)?;
954 Ok(Location::Paren(Box::new(p1)))
955 }
956 } else {
957 Ok(Location::Place(self.parse_place()?))
958 }
959 }
960
961 fn at_place_start(&self) -> bool {
962 match self.cur() {
963 Token::Label(_) | Token::Block | Token::Corner(_) => true,
964 Token::Kw(Kw::Last) | Token::Kw(Kw::Here) => true,
965 Token::Float(_) => matches!(self.peek(1), Token::Kw(Kw::Nth)),
966 _ => false,
967 }
968 }
969
970 fn parse_place(&mut self) -> PResult<Place> {
971 if let Token::Corner(c) = self.cur() {
973 let c = *c;
974 self.bump();
975 self.eat_kw(Kw::Of);
976 let inner = self.parse_place()?;
977 return Ok(Place::CornerOf(c, Box::new(inner)));
978 }
979
980 let mut place = self.parse_place_base()?;
981
982 loop {
984 if let Token::Corner(c) = self.cur() {
985 let c = *c;
986 self.bump();
987 place = Place::Corner(Box::new(place), c);
988 } else if self.at(&Token::Dot) {
989 self.bump();
990 let rhs = self.parse_place_base()?;
991 place = Place::Member(Box::new(place), Box::new(rhs));
992 } else {
993 break;
994 }
995 }
996 Ok(place)
997 }
998
999 fn parse_place_base(&mut self) -> PResult<Place> {
1000 match self.cur().clone() {
1001 Token::Kw(Kw::Here) => {
1002 self.bump();
1003 Ok(Place::Here)
1004 }
1005 Token::Label(name) => {
1006 self.bump();
1007 let subscript = if self.eat(&Token::LeftBrack) {
1008 let e = self.parse_expr()?;
1009 self.expect(&Token::RightBrack)?;
1010 Some(Box::new(e))
1011 } else {
1012 None
1013 };
1014 Ok(Place::Name { name, subscript })
1015 }
1016 Token::Kw(Kw::Last) | Token::Float(_) => {
1017 let count = self.parse_nth()?;
1018 let obj = self.parse_primobj()?;
1019 Ok(Place::Nth { count, obj })
1020 }
1021 other => self.err(format!("expected a place, found {other:?}")),
1022 }
1023 }
1024
1025 fn parse_nth(&mut self) -> PResult<Nth> {
1026 if self.eat_kw(Kw::Last) {
1027 return Ok(Nth::Last);
1028 }
1029 let e = self.parse_ncount()?;
1031 self.expect_kw(Kw::Nth)?;
1032 let from_last = self.eat_kw(Kw::Last);
1033 Ok(Nth::Count(Box::new(e), from_last))
1034 }
1035
1036 fn parse_ncount(&mut self) -> PResult<Expr> {
1040 match self.cur().clone() {
1041 Token::Float(v) => {
1042 self.bump();
1043 Ok(Expr::Num(v))
1044 }
1045 Token::LeftBrace => {
1046 self.bump();
1047 let e = self.parse_expr()?;
1048 self.expect(&Token::RightBrace)?;
1049 Ok(e)
1050 }
1051 Token::LeftQuote => {
1052 self.bump();
1053 let e = self.parse_expr()?;
1054 self.expect(&Token::RightQuote)?;
1055 Ok(e)
1056 }
1057 other => self.err(format!("expected an ordinal count, found {other:?}")),
1058 }
1059 }
1060
1061 fn parse_primobj(&mut self) -> PResult<PrimObj> {
1062 match self.cur().clone() {
1063 Token::Prim(p) => {
1064 self.bump();
1065 Ok(PrimObj::Prim(p))
1066 }
1067 Token::Block => {
1068 self.bump();
1069 Ok(PrimObj::Block)
1070 }
1071 Token::Str(s) => {
1072 self.bump();
1073 Ok(PrimObj::Str(s))
1074 }
1075 Token::LeftBrack => {
1076 self.bump();
1077 self.expect(&Token::RightBrack)?;
1078 Ok(PrimObj::EmptyBrack)
1079 }
1080 other => self.err(format!("expected a primitive object, found {other:?}")),
1081 }
1082 }
1083
1084 fn opt_expr(&mut self) -> PResult<Option<Expr>> {
1087 if self.starts_scalar() {
1088 Ok(Some(self.parse_expr()?))
1089 } else {
1090 Ok(None)
1091 }
1092 }
1093
1094 fn starts_scalar(&self) -> bool {
1095 matches!(
1096 self.cur(),
1097 Token::Float(_)
1098 | Token::Name(_)
1099 | Token::EnvVar(_)
1100 | Token::Lparen
1101 | Token::Minus
1102 | Token::Plus
1103 | Token::Not
1104 | Token::Func1(_)
1105 | Token::Func2(_)
1106 | Token::Kw(Kw::Rand)
1107 )
1108 }
1109
1110 fn parse_expr(&mut self) -> PResult<Expr> {
1111 self.parse_or()
1112 }
1113
1114 fn parse_or(&mut self) -> PResult<Expr> {
1115 let mut e = self.parse_and()?;
1116 while self.eat(&Token::OrOr) {
1117 let r = self.parse_and()?;
1118 e = Expr::Bin(BinOp::Or, Box::new(e), Box::new(r));
1119 }
1120 Ok(e)
1121 }
1122
1123 fn parse_and(&mut self) -> PResult<Expr> {
1124 let mut e = self.parse_cmp()?;
1125 while self.eat(&Token::AndAnd) {
1126 let r = self.parse_cmp()?;
1127 e = Expr::Bin(BinOp::And, Box::new(e), Box::new(r));
1128 }
1129 Ok(e)
1130 }
1131
1132 fn parse_cmp(&mut self) -> PResult<Expr> {
1133 let mut e = self.parse_add()?;
1134 loop {
1135 let op = match self.cur() {
1136 Token::EqEq => BinOp::Eq,
1137 Token::Neq => BinOp::Ne,
1138 Token::Lt => BinOp::Lt,
1139 Token::Le => BinOp::Le,
1140 Token::Gt => BinOp::Gt,
1141 Token::Ge => BinOp::Ge,
1142 _ => break,
1143 };
1144 self.bump();
1145 let r = self.parse_add()?;
1146 e = Expr::Bin(op, Box::new(e), Box::new(r));
1147 }
1148 Ok(e)
1149 }
1150
1151 fn parse_add(&mut self) -> PResult<Expr> {
1152 let mut e = self.parse_mul()?;
1153 loop {
1154 let op = match self.cur() {
1155 Token::Plus => BinOp::Add,
1156 Token::Minus => BinOp::Sub,
1157 _ => break,
1158 };
1159 self.bump();
1160 let r = self.parse_mul()?;
1161 e = Expr::Bin(op, Box::new(e), Box::new(r));
1162 }
1163 Ok(e)
1164 }
1165
1166 fn parse_mul(&mut self) -> PResult<Expr> {
1167 let mut e = self.parse_unary()?;
1168 loop {
1169 let op = match self.cur() {
1170 Token::Mult => BinOp::Mul,
1171 Token::Div => BinOp::Div,
1172 Token::Percent => BinOp::Mod,
1173 _ => break,
1174 };
1175 self.bump();
1176 let r = self.parse_unary()?;
1177 e = Expr::Bin(op, Box::new(e), Box::new(r));
1178 }
1179 Ok(e)
1180 }
1181
1182 fn parse_unary(&mut self) -> PResult<Expr> {
1183 let op = match self.cur() {
1184 Token::Minus => Some(UnOp::Neg),
1185 Token::Plus => Some(UnOp::Pos),
1186 Token::Not => Some(UnOp::Not),
1187 _ => None,
1188 };
1189 if let Some(op) = op {
1190 self.bump();
1191 let e = self.parse_unary()?;
1192 Ok(Expr::Unary(op, Box::new(e)))
1193 } else {
1194 self.parse_pow()
1195 }
1196 }
1197
1198 fn parse_pow(&mut self) -> PResult<Expr> {
1199 let base = self.parse_primary()?;
1200 if self.eat(&Token::Caret) {
1201 let exp = self.parse_unary()?; Ok(Expr::Bin(BinOp::Pow, Box::new(base), Box::new(exp)))
1203 } else {
1204 Ok(base)
1205 }
1206 }
1207
1208 fn parse_primary(&mut self) -> PResult<Expr> {
1209 if self.at_place_start() {
1211 return self.parse_place_scalar();
1212 }
1213 match self.cur().clone() {
1214 Token::Float(v) => {
1215 self.bump();
1216 Ok(Expr::Num(v))
1217 }
1218 Token::Name(name) => {
1219 self.bump();
1220 if self.eat(&Token::LeftBrack) {
1222 let _ = self.parse_expr()?;
1223 self.expect(&Token::RightBrack)?;
1224 }
1225 Ok(Expr::Var(name))
1226 }
1227 Token::EnvVar(v) => {
1228 self.bump();
1229 Ok(Expr::Env(v))
1230 }
1231 Token::Lparen => {
1232 self.bump();
1233 let e = self.parse_expr()?;
1235 self.expect(&Token::Rparen)?;
1236 Ok(e)
1237 }
1238 Token::Func1(f) => {
1239 self.bump();
1240 self.expect(&Token::Lparen)?;
1241 let e = self.parse_expr()?;
1242 self.expect(&Token::Rparen)?;
1243 Ok(Expr::Func1(f, Box::new(e)))
1244 }
1245 Token::Func2(f) => {
1246 self.bump();
1247 self.expect(&Token::Lparen)?;
1248 let a = self.parse_expr()?;
1249 self.expect(&Token::Comma)?;
1250 let b = self.parse_expr()?;
1251 self.expect(&Token::Rparen)?;
1252 Ok(Expr::Func2(f, Box::new(a), Box::new(b)))
1253 }
1254 Token::Kw(Kw::Rand) => {
1255 self.bump();
1256 self.expect(&Token::Lparen)?;
1257 let arg = if self.at(&Token::Rparen) {
1258 None
1259 } else {
1260 Some(Box::new(self.parse_expr()?))
1261 };
1262 self.expect(&Token::Rparen)?;
1263 Ok(Expr::Rand(arg))
1264 }
1265 other => self.err(format!("expected an expression, found {other:?}")),
1266 }
1267 }
1268
1269 fn parse_place_scalar(&mut self) -> PResult<Expr> {
1271 let place = self.parse_place()?;
1272 match self.cur().clone() {
1273 Token::DotX => {
1274 self.bump();
1275 Ok(Expr::DotX(Location::Place(place)))
1276 }
1277 Token::DotY => {
1278 self.bump();
1279 Ok(Expr::DotY(Location::Place(place)))
1280 }
1281 Token::Param(p) => {
1282 self.bump();
1283 Ok(Expr::PlaceAttr(place, p))
1284 }
1285 other => self.err(format!(
1286 "a place is not a number here; expected `.x`, `.y`, or an attribute, found {other:?}"
1287 )),
1288 }
1289 }
1290}
1291
1292#[cfg(test)]
1293mod tests {
1294 use super::*;
1295
1296 fn pic(src: &str) -> Picture {
1297 parse(src).unwrap_or_else(|e| panic!("parse error: {e}"))
1298 }
1299
1300 #[test]
1301 fn kernighan_pipeline() {
1302 let p = pic(r#".PS
1303ellipse "document"
1304arrow
1305box "PIC"
1306arrow
1307box "TBL/EQN" "(optional)" dashed
1308arrow
1309box "TROFF"
1310arrow
1311ellipse "typesetter"
1312.PE
1313"#);
1314 assert_eq!(p.stmts.len(), 9);
1315 if let Stmt::Object { object, .. } = &p.stmts[4] {
1317 assert_eq!(object.kind, ObjectKind::Primitive(Prim::Box));
1318 let texts = object
1319 .attrs
1320 .iter()
1321 .filter(|a| matches!(a, Attr::Text(_)))
1322 .count();
1323 assert_eq!(texts, 2);
1324 assert!(
1325 object
1326 .attrs
1327 .iter()
1328 .any(|a| matches!(a, Attr::LineStyle(LineType::Dashed, _)))
1329 );
1330 } else {
1331 panic!("expected object");
1332 }
1333 }
1334
1335 #[test]
1336 fn box_with_dims_and_at() {
1337 let p = pic("box ht 0.3 wid 0.5 at 0.25,0.15");
1338 let Stmt::Object { object, .. } = &p.stmts[0] else {
1339 panic!()
1340 };
1341 assert!(matches!(object.attrs[0], Attr::Dim(DimKind::Ht, _)));
1342 assert!(matches!(object.attrs[1], Attr::Dim(DimKind::Wid, _)));
1343 assert!(matches!(object.attrs[2], Attr::At(Position::Pair(_, _))));
1344 }
1345
1346 #[test]
1347 fn labeled_and_corners() {
1348 let p = pic("B1: box\narc -> from top of B1 to last box.ne");
1349 assert!(matches!(p.stmts[0], Stmt::Object { label: Some(_), .. }));
1350 let Stmt::Object { object, .. } = &p.stmts[1] else {
1351 panic!()
1352 };
1353 assert_eq!(object.kind, ObjectKind::Primitive(Prim::Arc));
1354 assert!(
1355 object
1356 .attrs
1357 .iter()
1358 .any(|a| matches!(a, Attr::Arrowhead(Arrow::Right, _)))
1359 );
1360 assert!(object.attrs.iter().any(|a| matches!(
1362 a,
1363 Attr::From(Position::Place(
1364 Location::Place(Place::CornerOf(Corner::N, _)),
1365 _
1366 ))
1367 )));
1368 }
1369
1370 #[test]
1371 fn with_at_and_shift() {
1372 let p = pic("ellipse \"2\" with .nw at last ellipse.se + (0.1,0)");
1373 let Stmt::Object { object, .. } = &p.stmts[0] else {
1374 panic!()
1375 };
1376 let with = object
1377 .attrs
1378 .iter()
1379 .find(|a| matches!(a, Attr::With { .. }))
1380 .unwrap();
1381 let Attr::With { anchor, at } = with else {
1382 panic!()
1383 };
1384 assert_eq!(*anchor, WithAnchor::Corner(Corner::Nw));
1385 assert!(matches!(at, Position::Place(_, shifts) if shifts.len() == 1));
1386 }
1387
1388 #[test]
1389 fn expression_precedence() {
1390 let p = pic("x = 2 + 3 * 4 ^ 2");
1392 let Stmt::Assign(list) = &p.stmts[0] else {
1393 panic!()
1394 };
1395 let Expr::Bin(BinOp::Add, _, rhs) = &list[0].value else {
1397 panic!("expected top-level add")
1398 };
1399 assert!(matches!(**rhs, Expr::Bin(BinOp::Mul, _, _)));
1400 }
1401
1402 #[test]
1403 fn between_position() {
1404 let p = pic("arrow from 1/3 of the way between A.ne and A.se");
1405 let Stmt::Object { object, .. } = &p.stmts[0] else {
1406 panic!()
1407 };
1408 assert!(object.attrs.iter().any(|a| matches!(
1409 a,
1410 Attr::From(Position::Between {
1411 of_the_way: true,
1412 ..
1413 })
1414 )));
1415 }
1416
1417 #[test]
1418 fn assignment_list_and_envvar() {
1419 let p = pic("boxht = 0.3; boxwid = 2 * boxht");
1420 assert_eq!(p.stmts.len(), 2);
1421 let Stmt::Assign(a0) = &p.stmts[0] else {
1422 panic!()
1423 };
1424 assert_eq!(a0[0].target, AssignTarget::Env(EnvVar::Boxht));
1425 }
1426
1427 #[test]
1428 fn block_object() {
1429 let p = pic("[ box; circle ] with .nw at Here");
1430 let Stmt::Object { object, .. } = &p.stmts[0] else {
1431 panic!()
1432 };
1433 let ObjectKind::Block(inner) = &object.kind else {
1434 panic!()
1435 };
1436 assert_eq!(inner.len(), 2);
1437 }
1438
1439 #[test]
1440 fn diamond_line_with_then() {
1441 let p = pic("line up right then down right then down left then up left");
1442 let Stmt::Object { object, .. } = &p.stmts[0] else {
1443 panic!()
1444 };
1445 let thens = object
1446 .attrs
1447 .iter()
1448 .filter(|a| matches!(a, Attr::Then))
1449 .count();
1450 assert_eq!(thens, 3);
1451 }
1452
1453 #[test]
1454 fn unsupported_control_is_clear() {
1455 let e = parse("sh \"ls\"").unwrap_err();
1456 assert!(e.msg.contains("not supported yet"));
1457 }
1458
1459 #[test]
1460 fn control_constructs_parse() {
1461 assert!(parse("for i = 1 to 3 do { box }").is_ok());
1462 assert!(parse("if 1 > 0 then { box } else { circle }").is_ok());
1463 assert!(parse("reset boxht, boxwid").is_ok());
1464 let p = parse("define e { box }\ne\ne").unwrap();
1466 assert_eq!(p.stmts.len(), 2);
1467 }
1468}