nom_gcode/
parse_comments.rs1use 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
17pub 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
35pub 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 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
72pub fn seimcolon_comment<'r>(input: &'r str,) -> IResult<&'r str, &'r str> {
74 preceded(
75 char(';'),
76 not_line_ending,
77 )(input)
78}
79
80pub 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
88pub 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
116pub 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}