nom_gcode/
parse_args.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 nom::AsChar;
11
12use crate::{seimcolon_comment, Comment, comment};
13
14use super::{
15    ArgOrComment,
16};
17
18type ArgOrCommentResult<'r> = IResult<&'r str, ArgOrComment<'r>>;
19pub type ManyArgOrCommentsResult<'r> = IResult<&'r str, Option<Vec<ArgOrComment<'r>>>>;
20
21/*
22 * Conditionally parses a string arg if enabled is true.
23 */
24// #[inline(always)]
25fn string_arg<'r>(input: &'r str) -> ArgOrCommentResult<'r> {
26    map(
27        preceded(
28            space1,
29            escaped(
30                is_not("\n\r;("),
31                '\\',
32                one_of("(); \t\n\\"),
33            ),
34        ),
35        ArgOrComment::TextArg
36    )(input)
37}
38
39#[inline(always)]
40fn key_value_arg<'r>(input: &'r str) -> ArgOrCommentResult<'r> {
41    map(
42        pair(
43            satisfy(AsChar::is_alpha),
44            opt(map_res(
45                is_not(" \t\n\r;("),
46                |s: &str| s.parse(),
47            )),
48        ),
49        ArgOrComment::KeyValue,
50    )(input)
51}
52
53fn combine_args_and_comments<'r>(
54    parser_outputs: (Vec<ArgOrComment<'r>>, Option<&'r str>),
55) -> Option<Vec<ArgOrComment<'r>>> {
56    let (mut args_or_comments, final_comment) = parser_outputs;
57
58    if let Some(final_comment) = final_comment {
59        args_or_comments.push(
60            ArgOrComment::Comment(Comment(final_comment)),
61        );
62    }
63
64    if args_or_comments.is_empty() {
65        None
66    } else {
67        Some(args_or_comments)
68    }
69}
70
71// #[inline(always)]
72pub fn parse_args<'r>(
73    string_arg_mcode: bool,
74    input: &'r str,
75) -> ManyArgOrCommentsResult<'r> {
76    if string_arg_mcode {
77        // Add a Text argument for the string arg of certain MCodes (eg. M28 teg.gcode)
78        map(
79            tuple((
80                    opt(map(comment, |c| ArgOrComment::Comment(c))),
81                    opt(string_arg),
82                    opt(map(comment, |c| ArgOrComment::Comment(c))),
83                ),
84            ),
85            |(c1, arg, c2)| Some(vec![c1, arg, c2].into_iter().flatten().collect()),
86        )(input)
87    } else {
88        map(
89            tuple((
90                many0(
91                    alt((
92                        // Add the rest of the args and comments
93                        preceded(
94                            space1,
95                            key_value_arg,
96                        ),
97                        map(comment, |c| ArgOrComment::Comment(c)),
98                    )),
99                ),
100                opt(seimcolon_comment),
101            )),
102            combine_args_and_comments,
103        )(input)
104    }
105}
106
107
108// #[inline(always)]
109pub fn parse_kv_arg<'r>(
110    input: &'r str,
111) -> ArgOrCommentResult<'r> {
112    // if string_arg_mcode {
113    //     // Add a Text argument for the string arg of certain MCodes (eg. M28 teg.gcode)
114    //     alt((
115    //         string_arg,
116    //         map(comment, |c| ArgOrComment::Comment(c)),
117    //     ))(input)
118    // } else {
119    alt((
120        // Add the rest of the args and comments
121        preceded(
122            space1,
123            key_value_arg,
124        ),
125        map(comment, ArgOrComment::Comment),
126    ))(input)
127}