nom_gcode/
parse_comments.rs

1use nom::{
2    IResult,
3    character::complete::*,
4    bytes::complete::*,
5};
6use nom::branch::*;
7use nom::combinator::*;
8use nom::sequence::*;
9use nom::multi::*;
10use std::time::Duration;
11
12use super::{
13    Comment,
14    DocComment,
15};
16
17// #[inline(always)]
18pub fn parentheses_comment<'r>(input: &'r str) -> IResult<&'r str, &'r str> {
19    let parser = preceded(
20        char('('),
21        is_not("\n\r)"),
22    );
23
24    terminated(
25        parser,
26        char(')'),
27    )(input)
28}
29
30pub struct WithComments<'r, O> {
31    pub comments: Option<Vec<&'r str>>,
32    pub value: O,
33}
34
35// #[inline(always)]
36pub fn with_parentheses_comments<
37    'r,
38    T: FnMut(&'r str,) -> IResult<&'r str, O>,
39    O,
40>(
41    parser: T,
42) -> impl FnMut(&'r str,) -> IResult<&'r str, WithComments<'r, O>> {
43    let parser = pair(
44        parser,
45        opt(many1(parentheses_comment)),
46    );
47
48    let parser = pair(
49        opt(many1(parentheses_comment)),
50        parser,
51    );
52
53    map(
54        parser,
55        |(mut comments, (value, more_comments))| {
56            // Merge all comments into one optional vec
57            if let Some(more_comments) = more_comments {
58                comments = Some([
59                    comments.unwrap_or_else(|| vec![]),
60                    more_comments,
61                ].concat())
62            }
63
64            WithComments {
65                comments,
66                value,
67            }
68        }
69    )
70}
71
72// #[inline(always)]
73pub fn seimcolon_comment<'r>(input: &'r str,) -> IResult<&'r str, &'r str> {
74    preceded(
75        char(';'),
76        not_line_ending,
77    )(input)
78}
79
80// #[inline(always)]
81pub fn comment<'r>(input: &'r str) -> IResult<&'r str, Comment<'r>> {
82    map(
83        alt((seimcolon_comment, parentheses_comment)),
84        |comment| Comment(comment),
85    )(input)
86}
87
88// #[inline(always)]
89pub fn doc_comment<'r>(input: &'r str) -> IResult<&'r str, DocComment<'r>> {
90    map_opt(
91        preceded(
92            char(';'),
93            separated_pair(
94                take_until(":"),
95                char(':'),
96                preceded(
97                    space0,
98                    not_line_ending,
99                ),
100            ),
101        ),
102        |(key, value)| {
103            let doc = match key {
104                "FLAVOR" => DocComment::GCodeFlavor(value),
105                "TIME" => DocComment::PrintTime(Duration::from_secs(value.parse().ok()?)),
106                "Filament used" => filament_used(value).ok()?.1,
107                "Layer height" => DocComment::LayerHeight { millis: value.parse().ok()? },
108                _ => return None
109            };
110
111            Some(doc)
112        }
113    )(input)
114}
115
116// #[inline(always)]
117pub fn filament_used<'r>(input: &'r str,) -> IResult<&'r str, DocComment<'r>> {
118    map_opt(
119        terminated(
120            take_until("m"),
121            char('m'),
122        ),
123        |s: &'r str| {
124            let meters = s.parse().ok()?;
125            Some(DocComment::FilamentUsed { meters })
126        }
127    )(input)
128}