ptx-parser 0.1.6

parser for ptx files
Documentation
use nom::{
    bytes::complete::{tag, take_while1},
    character::complete::{char, space1},
    combinator::opt,
    sequence::{preceded, Tuple},
    IResult, Parser,
};

use super::{comment::many1_comments_or_whitespace, parse_name, Preamble};

#[derive(Debug, PartialEq)]
pub(super) struct Version<'a> {
    major: &'a str,
    minor: &'a str,
}

#[derive(Debug, PartialEq)]
pub(super) struct Target<'a> {
    target: &'a str,
}

#[derive(Debug, PartialEq)]
pub(super) struct AddressSize<'a> {
    size: &'a str,
}

pub(super) fn parse_preamble(input: &str) -> IResult<&str, Preamble> {
    (
        preceded(
            opt(many1_comments_or_whitespace), 
            parse_version
        ),
        preceded(
            many1_comments_or_whitespace,
            parse_target
        ),
        preceded(
            many1_comments_or_whitespace,
            parse_address_size
        )
    )
    .parse(input)
    .map(|(input, (version, target, address_size))| {
        (
            input,
            Preamble {
                version,
                target,
                address_size,
            },
        )
    })
}

fn parse_version(input: &str) -> IResult<&str, Version> {
    (
        preceded(tag(".version").and(space1), take_while1(char::is_numeric)),
        preceded(char('.'), take_while1(char::is_numeric)),
    )
    .parse(input)
    .map(|(input, (major, minor))| (input, Version { major, minor }))
}

fn parse_target(input: &str) -> IResult<&str, Target> {
    preceded(
        tag(".target").and(space1),
        parse_name.map(|target| Target { target }),
    )(input)
}

fn parse_address_size(input: &str) -> IResult<&str, AddressSize> {
    preceded(
        tag(".address_size").and(space1),
        parse_name.map(|size| AddressSize { size }),
    )(input)
}

#[cfg(test)]
mod test_parse_version {
    use super::*;

    #[test]
    fn no_whitespace() {
        assert_eq!(
            parse_version(".version 1.0"),
            Ok((
                "",
                Version {
                    major: "1",
                    minor: "0"
                }
            ))
        );
    }

    #[test]
    fn leading_whitespace() {
        assert!(parse_version("  .version 1.0").is_err());
    }

    #[test]
    fn trailing_whitespace() {
        assert_eq!(
            parse_version(".version 1.0  "),
            Ok((
                "  ",
                Version {
                    major: "1",
                    minor: "0"
                }
            ))
        );
    }

    #[test]
    fn immediate_comment() {
        assert_eq!(
            parse_version(".version 1.0// This is a comment"),
            Ok((
                "// This is a comment",
                Version {
                    major: "1",
                    minor: "0"
                }
            ))
        );
    }
}

#[cfg(test)]
mod test_parse_target {
    use super::{parse_target, Target};

    #[test]
    fn no_whitespace() {
        assert_eq!(
            parse_target(".target sm_30"),
            Ok(("", Target { target: "sm_30" }))
        );
    }

    #[test]
    fn leading_whitespace() {
        assert!(parse_target("  .target sm_30").is_err());
    }

    #[test]
    fn trailing_whitespace() {
        assert_eq!(
            parse_target(".target sm_30  "),
            Ok(("  ", Target { target: "sm_30" }))
        );
    }

    #[test]
    fn immediate_comment() {
        assert_eq!(
            parse_target(".target sm_30// This is a comment"),
            Ok(("// This is a comment", Target { target: "sm_30" }))
        );
    }
}

#[cfg(test)]
mod test_parse_address_size {
    use super::{parse_address_size, AddressSize};

    #[test]
    fn no_whitespace() {
        assert_eq!(
            parse_address_size(".address_size 64"),
            Ok(("", AddressSize { size: "64" }))
        );
    }

    #[test]
    fn leading_whitespace() {
        assert!(parse_address_size("  .address_size 64").is_err());
    }

    #[test]
    fn trailing_whitespace() {
        assert_eq!(
            parse_address_size(".address_size 64  "),
            Ok(("  ", AddressSize { size: "64" }))
        );
    }

    #[test]
    fn immediate_comment() {
        assert_eq!(
            parse_address_size(".address_size 64// This is a comment"),
            Ok(("// This is a comment", AddressSize { size: "64" }))
        );
    }
}

#[cfg(test)]
mod test_parse_preamble {
    use super::{parse_preamble, AddressSize, Preamble, Target, Version};

    #[test]
    fn no_whitespace() {
        assert_eq!(
            parse_preamble(".version 1.0\n.target sm_30\n.address_size 64"),
            Ok((
                "",
                (Preamble {
                    version: Version {
                        major: "1",
                        minor: "0"
                    },
                    target: Target { target: "sm_30" },
                    address_size: AddressSize { size: "64" }
                })
            ))
        );
    }

    #[test]
    fn leading_whitespace() {
        assert_eq!(
            parse_preamble("  .version 1.0\n.target sm_30\n.address_size 64"),
            Ok((
                "",
                (Preamble {
                    version: Version {
                        major: "1",
                        minor: "0"
                    },
                    target: Target { target: "sm_30" },
                    address_size: AddressSize { size: "64" }
                })
            ))
        );
    }

    #[test]
    fn leading_newline() {
        assert_eq!(
            parse_preamble(" \n .version 1.0\n.target sm_30\n.address_size 64"),
            Ok((
                "",
                (Preamble {
                    version: Version {
                        major: "1",
                        minor: "0"
                    },
                    target: Target { target: "sm_30" },
                    address_size: AddressSize { size: "64" }
                })
            ))
        );
    }

    #[test]
    fn trailing_whitespace() {
        assert_eq!(
            parse_preamble(".version 1.0\n.target sm_30\n.address_size 64  "),
            Ok((
                "  ",
                (Preamble {
                    version: Version {
                        major: "1",
                        minor: "0"
                    },
                    target: Target { target: "sm_30" },
                    address_size: AddressSize { size: "64" }
                })
            ))
        );
    }

    #[test]
    fn immediate_comment() {
        assert_eq!(
            parse_preamble(".version 1.0\n.target sm_30\n.address_size 64// This is a comment"),
            Ok((
                "// This is a comment",
                (Preamble {
                    version: Version {
                        major: "1",
                        minor: "0"
                    },
                    target: Target { target: "sm_30" },
                    address_size: AddressSize { size: "64" }
                })
            ))
        );
    }

    #[test]
    fn trailing_comment() {
        assert_eq!(
            parse_preamble(".version 1.0\n.target sm_30\n.address_size 64\n// This is a comment"),
            Ok((
                "\n// This is a comment",
                (Preamble {
                    version: Version {
                        major: "1",
                        minor: "0"
                    },
                    target: Target { target: "sm_30" },
                    address_size: AddressSize { size: "64" }
                })
            ))
        );
    }
}