Parse escape characters properly

This commit is contained in:
Lewis Dale 2023-01-02 18:46:20 +00:00
parent 8edf1b9595
commit 9f55bef238
2 changed files with 33 additions and 25 deletions

View File

@ -1,26 +1,34 @@
use nom::{ use nom::{
bytes::complete::{tag, take_until, escaped}, branch::alt,
character::{complete::{u32 as ccu32, one_of}, streaming::none_of}, bytes::complete::{escaped_transform, tag, take_until},
combinator::map, character::{
complete::{u32 as ccu32},
streaming::none_of,
},
combinator::{map, value},
sequence::{delimited, terminated, tuple}, sequence::{delimited, terminated, tuple},
IResult, IResult,
}; };
pub type Line<'a> = (u32, Command<'a>); pub type Line = (u32, Command);
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum Command<'a> { pub enum Command {
Print(&'a str), Print(String),
None, None,
} }
fn read_string(i: &str) -> IResult<&str, &str> { fn read_string(i: &str) -> IResult<&str, String> {
// take_until("\"")(i) // take_until("\"")(i)
delimited( delimited(
tag("\""), tag("\""),
escaped(none_of("\\\""), '\\', one_of("\"\\")), escaped_transform(
tag("\"") none_of("\\\""),
)(i) '\\',
alt((value("\\", tag("\\")), value("\"", tag("\"")))),
),
tag("\""),
)(i)
} }
fn parse_command(i: &str) -> IResult<&str, Command> { fn parse_command(i: &str) -> IResult<&str, Command> {
@ -45,25 +53,25 @@ mod tests {
#[test] #[test]
fn it_parses_a_print_command() { fn it_parses_a_print_command() {
let input = "10 PRINT \"Hello, world\""; let input = "10 PRINT \"Hello, world\"";
let expected = (10, super::Command::Print("Hello, world")); let expected = (10, super::Command::Print(String::from("Hello, world")));
let (_, result) = super::parse_line(input).unwrap(); let (_, result) = super::parse_line(input).unwrap();
assert_eq!(expected, result); assert_eq!(expected, result);
} }
#[test] #[test]
fn it_reads_a_string() { fn it_reads_a_string() {
let input = r#""Hello, \"World\"""#; let input = r#""Hello, \"World\"""#;
let (_, output) = super::read_string(input).unwrap(); let (_, output) = super::read_string(input).unwrap();
assert_eq!(r#"Hello, \"World\""#, output); assert_eq!(r#"Hello, "World""#, output);
} }
#[test] #[test]
fn it_parses_a_print_command_with_escaped_quotes() { fn it_parses_a_print_command_with_escaped_quotes() {
let input = r#"10 PRINT "Hello, \"world\"""#; let input = r#"10 PRINT "Hello, \"world\"""#;
let expected = (10, super::Command::Print(r#"Hello, \"world\""#)); let expected = (10, super::Command::Print(String::from(r#"Hello, "world""#)));
let (_, result) = super::parse_line(input).unwrap(); let (_, result) = super::parse_line(input).unwrap();
assert_eq!(expected, result); assert_eq!(expected, result);
} }
} }

View File

@ -8,7 +8,7 @@ fn main() {
let (_, (_, command)) = basic::parse_line(lines).unwrap(); let (_, (_, command)) = basic::parse_line(lines).unwrap();
match command { match command {
basic::Command::Print(input) => { basic::Command::Print(input) => {
println!("{}", input.replace("\\", "")); println!("{}", input);
} }
_ => { _ => {
panic!("Command not recognised"); panic!("Command not recognised");