From 8edf1b959594a9b338b2ad523412c9483f449bb9 Mon Sep 17 00:00:00 2001 From: Lewis Dale Date: Mon, 2 Jan 2023 18:41:39 +0000 Subject: [PATCH] Parse escape characters properly --- Cargo.toml | 2 +- inputs/hello_world.bas | 2 +- src/basic.rs | 29 +++++++++++++++++++++++++---- src/main.rs | 2 +- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 804b2cb..bcd9f2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -nom = "7.1.2" +nom = { version = "7.1.2", features = ["alloc"] } diff --git a/inputs/hello_world.bas b/inputs/hello_world.bas index ac29b12..975eefc 100644 --- a/inputs/hello_world.bas +++ b/inputs/hello_world.bas @@ -1 +1 @@ -10 PRINT "Hello, world." \ No newline at end of file +10 PRINT "Hello, \"world\"." \ No newline at end of file diff --git a/src/basic.rs b/src/basic.rs index dea8f02..23bb8d6 100644 --- a/src/basic.rs +++ b/src/basic.rs @@ -1,6 +1,6 @@ use nom::{ - bytes::complete::{tag, take_until}, - character::complete::u32 as ccu32, + bytes::complete::{tag, take_until, escaped}, + character::{complete::{u32 as ccu32, one_of}, streaming::none_of}, combinator::map, sequence::{delimited, terminated, tuple}, IResult, @@ -15,14 +15,19 @@ pub enum Command<'a> { } fn read_string(i: &str) -> IResult<&str, &str> { - take_until("\"")(i) + // take_until("\"")(i) + delimited( + tag("\""), + escaped(none_of("\\\""), '\\', one_of("\"\\")), + tag("\"") + )(i) } fn parse_command(i: &str) -> IResult<&str, Command> { let (i, (command, _)) = tuple((take_until(" "), tag(" ")))(i)?; let (i, cmd) = match command { - "PRINT" => map(delimited(tag("\""), read_string, tag("\"")), Command::Print)(i)?, + "PRINT" => map(read_string, Command::Print)(i)?, _ => (i, Command::None), }; @@ -45,4 +50,20 @@ mod tests { let (_, result) = super::parse_line(input).unwrap(); assert_eq!(expected, result); } + + #[test] + fn it_reads_a_string() { + let input = r#""Hello, \"World\"""#; + let (_, output) = super::read_string(input).unwrap(); + assert_eq!(r#"Hello, \"World\""#, output); + } + + #[test] + fn it_parses_a_print_command_with_escaped_quotes() { + let input = r#"10 PRINT "Hello, \"world\"""#; + let expected = (10, super::Command::Print(r#"Hello, \"world\""#)); + + let (_, result) = super::parse_line(input).unwrap(); + assert_eq!(expected, result); + } } diff --git a/src/main.rs b/src/main.rs index 6afda37..c6cd6e9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ fn main() { let (_, (_, command)) = basic::parse_line(lines).unwrap(); match command { basic::Command::Print(input) => { - println!("{}", input); + println!("{}", input.replace("\\", "")); } _ => { panic!("Command not recognised");