1mod combinator;
4
5use crate::ast::{Color::*, CompleteStyle, Delimiter, Expression, Name, Separator, Style, Tree};
6use std::fmt::{self, Display};
7use std::str;
8
9use combinator::{delimited_many0, map_err, map_fail};
10use nom::{error, IResult};
11
12pub fn parse<'a>(input: &'a str) -> Result<Tree, ParseError<'a>> {
14 use nom::combinator::all_consuming;
15 use nom::Err;
16
17 all_consuming(expression_tree)(input.as_ref())
18 .map(|(_, tree)| tree)
19 .map_err(|e| match e {
20 Err::Error(e) => e,
21 Err::Failure(e) => e,
22 _ => unreachable!("Parser failed to complete"),
23 })
24}
25
26pub fn expression_tree<'a>(input: &'a str) -> IResult<&str, Tree, ParseError<'a>> {
27 use nom::combinator::map;
28 use nom::multi::many0;
29
30 map(many0(expression), Tree)(input)
31}
32
33pub fn expression<'a>(input: &'a str) -> IResult<&str, Expression, ParseError<'a>> {
35 use nom::branch::alt;
36 use nom::error::context;
37
38 alt((
39 context("group", group_expression),
40 context("string", literal_expression),
41 context("format", format_expression),
42 separator_expression,
43 named_expression,
44 ))(input)
45}
46
47fn sub_tree<'a>(input: &'a str) -> IResult<&str, Tree, ParseError<'a>> {
48 use nom::character::complete::char;
49 use nom::combinator::map;
50 let items = delimited_many0(
53 char('('),
54 expression,
55 map_err(char(')'), |_, e| {
56 ParseError::missing_delimiter(input, e, ')')
57 }),
58 );
59
60 map(items, Tree)(input)
61}
62
63pub fn named_expression<'a>(input: &'a str) -> IResult<&str, Expression, ParseError<'a>> {
64 use nom::branch::alt;
65 use nom::bytes::complete::tag;
66 use nom::character::complete::char;
67 use nom::combinator::{map, opt};
68
69 use Name::*;
73 let name = alt((
74 map(char('h'), |_| Stashed),
75 map(char('b'), |_| Branch),
76 map(char('B'), |_| Remote),
77 map(char('+'), |_| Ahead),
78 map(char('-'), |_| Behind),
79 map(char('u'), |_| Conflict),
80 map(char('A'), |_| Added),
81 map(char('a'), |_| Untracked),
82 map(char('M'), |_| Modified),
83 map(char('m'), |_| Unstaged),
84 map(char('d'), |_| Deleted),
85 map(char('D'), |_| DeletedStaged),
86 map(char('R'), |_| Renamed),
87 map(tag("\\\'"), |_| Quote),
88 ));
89
90 let name = map_err(name, ParseError::missing_name);
91
92 let prefix = map_err(opt(sub_tree), |_, e| {
94 error::ParseError::add_context(input, "expression", e)
95 });
96
97 name(input).and_then(|(input, name)| {
99 map(prefix, |args| Expression::Named {
100 name,
101 sub: args.unwrap_or_else(|| Tree::new()),
102 })(input)
103 })
104}
105
106fn u8_from_bytes<'a>(input: &'a str) -> u8 {
107 input
108 .parse()
109 .expect("attempted to parse a value that was not a number")
110}
111
112fn digit<'a>(input: &'a str) -> IResult<&str, u8, ParseError<'a>> {
113 use nom::bytes::complete::take_while1;
114 use nom::character::is_digit;
115 use nom::combinator::map;
116
117 map(take_while1(|c| is_digit(c as u8)), u8_from_bytes)(input)
118}
119
120fn u8_triple<'a>(input: &'a str) -> IResult<&str, (u8, u8, u8), ParseError<'a>> {
121 use nom::character::complete::char;
122 use nom::sequence::{terminated, tuple};
123
124 tuple((
125 terminated(digit, char(',')),
126 terminated(digit, char(',')),
127 digit,
128 ))(input)
129}
130
131fn style_token<'a>(input: &'a str) -> IResult<&str, Style, ParseError<'a>> {
132 use nom::branch::alt;
133 use nom::character::complete::char;
134 use nom::combinator::{complete, map};
135 use nom::sequence::delimited;
136
137 use Style::*;
139 macro_rules! style {
140 ($tag:expr, $type:expr) => {
141 map(char($tag), |_| $type)
142 };
143 }
144
145 let styles = alt((
149 style!('~', Reset),
150 style!('*', Bold),
151 style!('_', Underline),
152 style!('i', Italic),
153 style!('r', Fg(Red)),
154 style!('R', Bg(Red)),
155 style!('g', Fg(Green)),
156 style!('G', Bg(Green)),
157 style!('y', Fg(Yellow)),
158 style!('Y', Bg(Yellow)),
159 style!('b', Fg(Blue)),
160 style!('B', Bg(Blue)),
161 style!('m', Fg(Magenta)),
162 style!('M', Bg(Magenta)),
163 style!('c', Fg(Cyan)),
164 style!('C', Bg(Cyan)),
165 style!('w', Fg(White)),
166 style!('W', Bg(White)),
167 style!('k', Fg(Black)),
168 style!('K', Bg(Black)),
169 ));
170
171 let fg_rgb = map(
173 complete(delimited(
174 char('['),
175 map_fail(u8_triple, ParseError::invalid_rgb),
176 map_fail(char(']'), ParseError::char_to_delimiter),
177 )),
178 |(r, g, b)| Fg(RGB(r, g, b)),
179 );
180 let bg_rgb = map(
181 complete(delimited(
182 char('{'),
183 map_fail(u8_triple, ParseError::invalid_rgb),
184 map_fail(char('}'), ParseError::char_to_delimiter),
185 )),
186 |(r, g, b)| Bg(RGB(r, g, b)),
187 );
188
189 alt((fg_rgb, bg_rgb, map_err(styles, ParseError::missing_style)))(input)
190}
191
192pub fn format_expression<'a>(input: &'a str) -> IResult<&str, Expression, ParseError<'a>> {
193 use nom::bytes::complete::tag;
194 use nom::combinator::{cut, map};
195 use nom::multi::fold_many1;
196 use nom::sequence::preceded;
197
198 let tokens = fold_many1(
199 style_token,
200 CompleteStyle::default(),
201 |mut complete, style| {
202 complete.add(style);
203 complete
204 },
205 );
206
207 let style = preceded(
208 tag("#"),
209 map_fail(tokens, |i, e| {
210 if let ParseErrorKind::Other(_) = e.error.1 {
211 ParseError::missing_style(i, e)
212 } else {
213 e
214 }
215 }),
216 );
217
218 let arguments = cut(sub_tree);
219
220 style(input).and_then(|(input, style)| {
221 map(arguments, |sub_tree| Expression::Format {
222 style,
223 sub: sub_tree,
224 })(input)
225 })
226}
227
228pub fn group_expression<'a>(input: &'a str) -> IResult<&str, Expression, ParseError<'a>> {
229 use nom::branch::alt;
230 use nom::bytes::complete::tag;
231 use nom::character::complete::char;
232 use nom::combinator::map;
233
234 macro_rules! group {
235 ($l:tt, $r:tt, $type:expr) => {
236 map(
237 delimited_many0(
238 tag($l),
239 expression,
240 map_err(char($r), |_, e| ParseError::char_to_delimiter(input, e)),
241 ),
242 |sub| Expression::Group {
243 d: $type,
244 sub: Tree(sub),
245 },
246 )
247 };
248 }
249
250 alt((
251 group!("<", '>', Delimiter::Angle),
252 group!("[", ']', Delimiter::Square),
253 group!("{", '}', Delimiter::Curly),
254 group!("\\(", ')', Delimiter::Parens),
255 ))(input)
256}
257
258pub fn literal_expression<'a>(input: &'a str) -> IResult<&str, Expression, ParseError<'a>> {
259 use nom::bytes::complete::take_until;
260 use nom::character::complete::char;
261 use nom::combinator::map;
262 use nom::sequence::delimited;
263
264 let contents = map(
265 map_fail(take_until("\'"), |i, mut e: ParseError<'a>| {
266 e.error = (i, UnclosedString);
267 e
268 }),
269 str::to_owned,
270 );
271
272 use ParseErrorKind::UnclosedString;
273
274 map(
275 delimited(char('\''), contents, char('\'')),
276 Expression::Literal,
277 )(input)
278}
279
280pub fn separator_expression<'a>(input: &'a str) -> IResult<&str, Expression, ParseError<'a>> {
281 use nom::branch::alt;
282 use nom::bytes::complete::tag;
283 use nom::combinator::map;
284
285 use Separator::*;
286
287 macro_rules! sep {
288 ($sep:expr) => {
289 map(tag($sep.as_str()), |_| $sep)
290 };
291 }
292
293 map(
294 alt((
295 sep!(At),
296 sep!(Bar),
297 sep!(Dot),
298 sep!(Comma),
299 sep!(Space),
300 sep!(Colon),
301 sep!(Semicolon),
302 sep!(Underscore),
303 )),
304 Expression::Separator,
305 )(input)
306}
307
308#[derive(Debug, PartialEq, Clone)]
309pub struct ParseError<'a> {
310 error: (&'a str, ParseErrorKind),
311 context: Option<(&'a str, &'static str)>,
312 top: Option<(&'a str, &'static str)>,
313}
314
315#[derive(Debug, PartialEq, Clone)]
316enum ParseErrorKind {
317 UnclosedString,
318 MissingDelimiter(char),
319 MissingChar(char),
320 UnrecognizedName,
321 UnrecognizedStyle,
322 InvalidRGB,
323 Other(error::ErrorKind),
324}
325
326#[derive(Debug, Clone)]
328pub struct PrettyPrinter<'a> {
329 error: ParseError<'a>,
330 use_color: bool,
331}
332
333impl<'a> ParseError<'a> {
334 fn missing_delimiter(input: &'a str, mut other: Self, delimiter: char) -> Self {
335 other.error = (input, ParseErrorKind::MissingDelimiter(delimiter));
336 other
337 }
338
339 fn missing_name(input: &'a str, mut other: Self) -> Self {
340 other.error = (input, ParseErrorKind::UnrecognizedName);
341 other
342 }
343
344 fn missing_style(input: &'a str, mut other: Self) -> Self {
345 use ParseErrorKind::UnrecognizedStyle;
346 other.error = (input, UnrecognizedStyle);
347 other
348 }
349
350 fn char_to_delimiter(input: &'a str, mut other: Self) -> Self {
351 use ParseErrorKind::{MissingChar, MissingDelimiter};
352 if let MissingChar(c) = other.error.1 {
353 other.error = (input, MissingDelimiter(c));
354 }
355 other
356 }
357
358 fn invalid_rgb(input: &'a str, mut other: Self) -> Self {
359 other.error = (input, ParseErrorKind::InvalidRGB);
360 other
361 }
362
363 pub fn pretty_print(&self, use_color: bool) -> PrettyPrinter<'a> {
364 PrettyPrinter {
365 use_color,
366 error: self.clone(),
367 }
368 }
369}
370
371impl<'a> error::ParseError<&'a str> for ParseError<'a> {
372 fn from_error_kind(input: &'a str, kind: error::ErrorKind) -> Self {
373 ParseError {
374 error: (input, ParseErrorKind::Other(kind)),
375 context: None,
376 top: None,
377 }
378 }
379
380 fn append(_input: &'a str, _kind: error::ErrorKind, other: Self) -> Self {
381 other
382 }
383
384 fn add_context(input: &'a str, context: &'static str, mut other: Self) -> Self {
385 other.context = other.context.or(Some((input, context)));
386 other.top = Some((input, context));
387 other
388 }
389
390 fn from_char(input: &'a str, missing: char) -> Self {
391 ParseError {
392 error: (input, ParseErrorKind::MissingChar(missing)),
393 context: None,
394 top: None,
395 }
396 }
397}
398
399impl<'a> PrettyPrinter<'a> {
400 pub fn pretty_print(&self, f: &mut fmt::Formatter) -> fmt::Result {
401 use ParseErrorKind::*;
402 match &self.error.error.1 {
403 UnclosedString => self.error_message(self.error.error.0.len(), f, |f, bold| {
404 writeln!(f, "missing closing quote ({})", bold.paint("\'"))
405 }),
406 MissingDelimiter(d) => self.error_message(1, f, |f, bold| {
407 writeln!(f, "reached end without finding matching {}", bold.paint(d))
408 }),
409 MissingChar(c) => {
410 let found: &str = &self.error.error.0.get(0..1).unwrap_or("");
411 self.error_message(1, f, |f, bold| {
412 writeln!(
413 f,
414 "expected \"{}\" here, found \"{}\"",
415 bold.paint(c),
416 bold.paint(found)
417 )
418 })
419 }
420 UnrecognizedName | Other(error::ErrorKind::Eof) => {
421 let found = self.error.error.0.get(0..1).unwrap_or("");
422 self.error_message(found.len().max(1), f, |f, _| {
423 if found == "]" || found == ")" || found == ">" || found == "}" {
424 writeln!(f, "improper close delimiter")
425 } else {
426 writeln!(f, "not recognized as a valid expression")
427 }
428 })
429 }
430 UnrecognizedStyle => {
431 let found: &str = &self.error.error.0.get(0..1).unwrap_or("");
432 self.error_message(1, f, |f, bold| {
433 writeln!(f, "found \"{}\" which is not a style", bold.paint(found))
434 })
435 }
436 InvalidRGB => {
437 let found = self
439 .error
440 .error
441 .0
442 .find(|c| c == ']' || c == '}')
443 .unwrap_or(1);
444 self.error_message(found.min(5).max(1), f, |f, bold| {
445 writeln!(f, "RGB must be in the form \"{}\"", bold.paint("0,0,0"))
446 })
447 }
448 Other(e) => self.error_message(1, f, |f, _| writeln!(f, "{:?}", e)),
449 }
450 }
451
452 fn error_message<F>(&self, error_size: usize, f: &mut fmt::Formatter, message: F) -> fmt::Result
453 where
454 F: Fn(&mut fmt::Formatter, yansi::Style) -> fmt::Result,
455 {
456 use yansi::{Color, Style};
457
458 let bold = if self.use_color {
459 Style::new(Color::Unset).bold()
460 } else {
461 Style::new(Color::Unset)
462 };
463
464 let error = if self.use_color {
465 Style::new(Color::Red).bold()
466 } else {
467 Style::new(Color::Unset)
468 };
469
470 let dim = if self.use_color {
471 Style::new(Color::Unset).dimmed()
472 } else {
473 Style::new(Color::Unset)
474 };
475
476 if let Some((input, context)) = self.error.context {
477 writeln!(f, "{}: unable to parse {}", error.paint("error"), context)?;
478 writeln!(f, " {}", bold.paint("│"))?;
479 writeln!(f, " {} {}", bold.paint("│"), input)?;
480 write!(f, " {} ", bold.paint("│"))?;
481 if let Some(i) = input.rfind(self.error.error.0) {
482 for _ in 0..i {
483 write!(f, " ")?;
484 }
485 }
486 } else {
487 writeln!(f, "{}: unable to parse", error.paint("error"))?;
488 writeln!(f, " {} ", bold.paint("│"))?;
489 writeln!(f, " {} {}", bold.paint("│"), self.error.error.0)?;
490 write!(f, " {} ", bold.paint("│"))?;
491 }
492
493 for _ in 0..error_size {
494 write!(f, "{}", error.paint("^"))?;
495 }
496 write!(f, " ")?;
497 message(f, bold)?;
498
499 writeln!(f, " {}", bold.paint("│"))?;
500 if let (Some((top_input, top)), Some((input, _))) = (self.error.top, self.error.context) {
501 let (pre, input) = top_input.split_at(top_input.rfind(input).unwrap_or(0));
502 let (input, er) = input.split_at(input.rfind(self.error.error.0).unwrap_or(0));
503 let (er, post) = er.split_at(error_size.min(er.len()));
504 write!(
505 f,
506 " = in {}: {}{}{}{}",
507 top,
508 dim.paint(pre),
509 input,
510 error.paint(er),
511 dim.paint(post)
512 )?;
513 }
514
515 Ok(())
516 }
517}
518
519impl<'a> Display for PrettyPrinter<'a> {
520 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
521 self.pretty_print(f)
522 }
523}
524
525impl<'a> Display for ParseError<'a> {
526 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
527 write!(f, "{}", self.pretty_print(false))
528 }
529}
530
531#[cfg(test)]
532mod test {
533 use super::*;
534 use crate::ast::arb_expression;
535
536 proptest! {
537 #[test]
538 fn disp_parse_invariant(expect in arb_expression()) {
539 let test = format!("{}", expect);
540 println!("{} from {:?}", test, expect);
541 let parse = expression(test.as_ref());
542 println!("\t parsed => {:?}", parse);
543 let parse = parse.unwrap().1;
544 println!("expect {} ==\nresult {}\n", expect, parse);
545 assert!(parse == expect)
546 }
547 }
548
549 #[test]
550 fn separator() {
551 use Separator::*;
552 let test = " , | ::";
553 let expect = Tree(vec![
554 Expression::Separator(Space),
555 Expression::Separator(Space),
556 Expression::Separator(Comma),
557 Expression::Separator(Space),
558 Expression::Separator(Bar),
559 Expression::Separator(Space),
560 Expression::Separator(Space),
561 Expression::Separator(Colon),
562 Expression::Separator(Colon),
563 ]);
564 let parse = parse(test).unwrap();
565 assert!(parse == expect, "{:?} != {:?}", parse, expect);
566 }
567
568 #[test]
569 fn japanese_text() {
570 let test = "'日本語は綺麗なのです'['試験'#*('テスト')]";
571 let expect = Tree(vec![
572 Expression::Literal("日本語は綺麗なのです".to_string()),
573 Expression::Group {
574 d: Delimiter::Square,
575 sub: Tree(vec![
576 Expression::Literal("試験".to_string()),
577 Expression::Format {
578 style: (&[Style::Bold]).iter().collect(),
579 sub: Tree(vec![Expression::Literal("テスト".to_string())]),
580 },
581 ]),
582 },
583 ]);
584 let parse = expression_tree(test).unwrap().1;
585 assert!(parse == expect, "{:#?} != {:#?}", parse, expect);
586 }
587
588 #[test]
589 fn named_expression_no_args() {
590 let test = "h";
591 let expect = Expression::Named {
592 name: Name::Stashed,
593 sub: Tree::new(),
594 };
595 let parse = named_expression(test).unwrap().1;
596 assert!(parse == expect, "{:?} != {:?}", parse, expect);
597 }
598
599 #[test]
600 fn named_expression_empty_args() {
601 let test = "b()";
602 let expect = Expression::Named {
603 name: Name::Branch,
604 sub: Tree::new(),
605 };
606 let parse = match named_expression(test) {
607 IResult::Ok((_, exp)) => exp,
608 fail @ _ => panic!("Failed to parse with result {:?}", fail),
609 };
610 assert!(parse == expect, "{:?} != {:?}", parse, expect);
611 }
612
613 #[test]
614 fn named_expression_1_arg() {
615 let test = "b(+)";
616 let expect = Expression::Named {
617 name: Name::Branch,
618 sub: Tree(vec![Expression::Named {
619 name: Name::Ahead,
620 sub: Tree::new(),
621 }]),
622 };
623 let parse = match named_expression(test) {
624 IResult::Ok((_, exp)) => exp,
625 fail @ _ => panic!("Failed to parse with result {:?}", fail),
626 };
627 assert!(parse == expect, "{:?} != {:?}", parse, expect);
628 }
629
630 #[test]
631 fn named_expression_2_arg() {
632 let test = "b(+-)";
633 let expect = Expression::Named {
634 name: Name::Branch,
635 sub: Tree(vec![
636 Expression::Named {
637 name: Name::Ahead,
638 sub: Tree::new(),
639 },
640 Expression::Named {
641 name: Name::Behind,
642 sub: Tree::new(),
643 },
644 ]),
645 };
646 let parse = match named_expression(test) {
647 IResult::Ok((_, exp)) => exp,
648 fail @ _ => panic!("Failed to parse with result {:?}", fail),
649 };
650 assert!(parse == expect, "{:?} != {:?}", parse, expect);
651 }
652
653 #[test]
654 fn format_rgb() {
655 let test = "#[42,0,0]{0,0,42}(bB)";
656 let expect = Expression::Format {
657 style: vec![Style::Fg(RGB(42, 0, 0)), Style::Bg(RGB(0, 0, 42))]
658 .iter()
659 .collect(),
660 sub: Tree(vec![
661 Expression::Named {
662 name: Name::Branch,
663 sub: Tree::new(),
664 },
665 Expression::Named {
666 name: Name::Remote,
667 sub: Tree::new(),
668 },
669 ]),
670 };
671 let parse = match format_expression(test) {
672 IResult::Ok((_, exp)) => exp,
673 fail @ _ => panic!("Failed to parse with result {:?}", fail),
674 };
675 assert!(parse == expect, "{:?} != {:?}", parse, expect);
676 }
677
678 #[test]
679 fn empty_group_expression() {
680 let test = "{}\\()[]<>";
681 let expect = Tree(vec![
682 Expression::Group {
683 d: Delimiter::Curly,
684 sub: Tree::new(),
685 },
686 Expression::Group {
687 d: Delimiter::Parens,
688 sub: Tree::new(),
689 },
690 Expression::Group {
691 d: Delimiter::Square,
692 sub: Tree::new(),
693 },
694 Expression::Group {
695 d: Delimiter::Angle,
696 sub: Tree::new(),
697 },
698 ]);
699 let parse = match expression_tree(test) {
700 IResult::Ok((_, exp)) => exp,
701 fail @ _ => panic!("Failed to parse with result {:?}", fail),
702 };
703 assert!(parse == expect, "{:?} != {:?}", parse, expect);
704 }
705
706 #[test]
707 fn disp() {
708 let expect = "\\('quoted literal'#*(bB))";
709 let parse = match expression_tree(expect) {
710 IResult::Ok((_, exp)) => exp,
711 fail => panic!("Failed to parse with result {:?}", fail),
712 };
713 assert!(
714 format!("{}", parse) == expect,
715 "{} == {}\n\tparsed {:?}",
716 parse,
717 expect,
718 parse
719 );
720
721 let expect = "#b(bB)";
722 let parse = expression_tree(expect).unwrap().1;
723 assert!(
724 format!("{}", parse) == expect,
725 "{} == {}\n\tparsed {:?}",
726 parse,
727 expect,
728 parse
729 );
730 }
731}