1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use nom::{
character::complete::*,
error::VerboseError,
};
use nom::branch::*;
use nom::combinator::*;
use nom::sequence::*;
use super::{
parse_command,
parse_args,
comment,
doc_comment,
GCodeParseError,
GCodeLine,
M,
GCodeParseError::*,
};
const STRING_ARG_MCODES: [u32; 7] = [
23,
28,
30,
36,
38,
117,
118,
];
pub fn parse_gcode(input: &str) -> Result<(&str, Option<GCodeLine>), GCodeParseError> {
let original_input = input;
let demarcator = map(
pair(char('%'), not_line_ending),
|_: (char, &str)| GCodeLine::FileDemarcator,
);
let (input, _) = space0::<_, VerboseError<&str>>(input)
.map_err(|_|
InvalidGCode(original_input.to_string())
)?;
if input.is_empty() {
return Ok((input, None));
};
let mut non_gcode_line= alt((
map(newline, |_| None),
map(
alt((
demarcator,
map(doc_comment, |doc| GCodeLine::DocComment(doc)),
map(comment, |comment| GCodeLine::Comment(comment))
)),
|line| Some(line),
),
));
if let Ok((input, gcode_line)) = non_gcode_line(input) {
return Ok((input, gcode_line));
};
let (input, mut gcode) = parse_command(input)
.map_err(|_|
GCodeParseError::InvalidGCode(original_input.to_string())
)?;
let string_arg_mcode =
gcode.mnemonic == M
&& gcode.minor == 0
&& STRING_ARG_MCODES.contains(&gcode.major);
let (input, args_or_comments) = parse_args(
string_arg_mcode,
input,
)
.map_err(|_| InvalidArguments(original_input.to_string()))?;
gcode.args_or_comments = args_or_comments;
Ok((input, Some(GCodeLine::GCode(gcode))))
}