Skip to main content

glitter_lang/
parser.rs

1//! Format parser, determines the syntax for pretty formats
2
3mod 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
12/// Parse a format
13pub 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
33/// Parse a single expression, expanding nested expressions
34pub 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    // use nom::sequence::delimited;
51
52    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    // sub-parsers for each type of name, this defines what
70    // literal values are translated to what names; must match the
71    // fmt::Display implementation
72    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    // Optional argument sub_tree
93    let prefix = map_err(opt(sub_tree), |_, e| {
94        error::ParseError::add_context(input, "expression", e)
95    });
96
97    // First, read name from input and then read the arguments.
98    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    // create sub-parsers for each style type
138    use Style::*;
139    macro_rules! style {
140        ($tag:expr, $type:expr) => {
141            map(char($tag), |_| $type)
142        };
143    }
144
145    // sub-parsers for each type of style, this defines what
146    // literals translate to what Style Tokens; must match the
147    // fmt::Display implementation
148    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    // more complicated sub-parsers for RGB/Indexed Color styles
172    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/// Indirect fmt::Display in order to configure whether to use color
327#[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                // find a potential matching brace and show interest up to that region
438                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}