Skip to content

Commit

Permalink
Fixed #13
Browse files Browse the repository at this point in the history
+ Added support for Windows \r\n (also in tests)
+ Bumped version to 0.5.4
  • Loading branch information
Genarito committed Apr 1, 2024
1 parent 127e63e commit 5ae794f
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 17 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ keywords = ["parse", "dump", "serialize", "deserialize", "stringify"]
license = "MIT"
name = "gura"
repository = "https://github.com/gura-conf/gura-rs-parser"
version = "0.5.3"
version = "0.5.4"

[dependencies]
float-pretty-print = "0.1.0"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Add the dependency to your `Cargo.toml`:

```toml
[dependencies]
gura = "0.5.1"
gura = "0.5.4"
```


Expand Down
34 changes: 23 additions & 11 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ const INF_AND_NAN: &str = "in"; // The rest of the chars are defined in hex_oct_
/// Acceptable chars for keys
const KEY_ACCEPTABLE_CHARS: &str = "0-9A-Za-z_";

/// New line chars
const NEW_LINE_CHARS: &str = "\n\x0c\x0b\x08";
/// New line chars (U+000A, U+000C, U+000B, U+0008). Used in new_line() method
/// * \n - U+000A
/// * \f - U+000C
/// * \v - U+000B
/// * \r - U+0008
const NEW_LINE_CHARS: &str = "\n\r\n\x0c\x0b\x08";

lazy_static! {
/// Special characters that need escaped when parsing Gura texts
Expand All @@ -36,6 +40,7 @@ lazy_static! {
m.insert("f", "\x0c");
m.insert("n", "\n");
m.insert("r", "\r");
m.insert("rn", "\r\n");
m.insert("t", "\t");
m.insert("\"", "\"");
m.insert("\\", "\\");
Expand All @@ -50,6 +55,7 @@ lazy_static! {
m.insert("\x0c", "\\f");
m.insert("\n", "\\n");
m.insert("\r", "\\r");
m.insert("\r\n", "\\r\\n");
m.insert("\t", "\\t");
m.insert("\"", "\\\"");
m.insert("\\", "\\\\");
Expand Down Expand Up @@ -434,7 +440,7 @@ fn useless_line(text: &mut Input) -> RuleResult {
maybe_match(text, vec![Box::new(new_line)])?;
let is_new_line = (text.line - initial_line) == 1;

if comment.is_none() && !is_new_line {
if comment.is_none() && !is_new_line && !is_end_of_file(text) {
return Err(GuraError {
pos: text.pos + 1,
line: text.line,
Expand Down Expand Up @@ -475,9 +481,9 @@ fn basic_string(text: &mut Input) -> RuleResult {

let is_multiline = quote == "\"\"\"";

// NOTE: a newline immediately following the opening delimiter will be trimmed.All other whitespace and
// NOTE: a newline immediately following the opening delimiter will be trimmed. All other whitespace and
// newline characters remain intact.
if is_multiline && maybe_char(text, &Some(String::from("\n")))?.is_some() {
if is_multiline && maybe_char(text, &Some(String::from(NEW_LINE_CHARS)))?.is_some() {
text.line += 1;
}

Expand All @@ -494,7 +500,7 @@ fn basic_string(text: &mut Input) -> RuleResult {
let escape = char(text, &None)?;

// Checks backslash followed by a newline to trim all whitespaces
if is_multiline && escape == "\n" {
if is_multiline && (escape == "\n" || escape == "\r\n") {
eat_ws_and_new_lines(text)
} else {
// Supports Unicode of 16 and 32 bits representation
Expand Down Expand Up @@ -683,7 +689,7 @@ fn variable_value(text: &mut Input) -> RuleResult {
/// * ParseError - If EOL has not been reached.
fn assert_end(text: &mut Input) -> Result<(), GuraError> {
if text.pos < text.len {
let error_pos = text.pos + 1;
let error_pos = if !is_end_of_file(text) { text.pos + 1} else { text.pos };
Err(GuraError {
pos: error_pos,
line: text.line,
Expand Down Expand Up @@ -821,7 +827,7 @@ fn keyword(text: &mut Input, keywords: &[&str]) -> Result<String, GuraError> {
}
}

let error_pos = text.pos + 1;
let error_pos = if !is_end_of_file(text) { text.pos + 1} else { text.pos };
Err(GuraError {
pos: error_pos,
line: text.line,
Expand Down Expand Up @@ -998,7 +1004,7 @@ fn comment(text: &mut Input) -> RuleResult {
let pos_usize = (text.pos + 1) as usize;
let char = &text.text[pos_usize];
text.pos += 1;
if String::from("\x0c\x0b\r\n").contains(char) {
if String::from(NEW_LINE_CHARS).contains(char) {
text.line += 1;
break;
}
Expand Down Expand Up @@ -1220,6 +1226,12 @@ fn variable(text: &mut Input) -> RuleResult {
}
}

/// Checks if it's the last position of the text.
/// This prevents issues when reports the error position.
fn is_end_of_file(text: &mut Input) -> bool {
text.pos == text.len
}

/// Matches with a key.A key is an unquoted string followed by a colon (:).
///
/// # Errors
Expand All @@ -1233,7 +1245,7 @@ fn key(text: &mut Input) -> RuleResult {
keyword(text, &[":"])?;
matched_key
} else {
let error_pos = text.pos + 1;
let error_pos = if !is_end_of_file(text) { text.pos + 1} else { text.pos };
Err(GuraError {
pos: error_pos,
line: text.line,
Expand Down Expand Up @@ -1411,7 +1423,7 @@ fn literal_string(text: &mut Input) -> RuleResult {

// NOTE: a newline immediately following the opening delimiter will be trimmed.All other whitespace and
// newline characters remain intact.
if is_multiline && maybe_char(text, &Some(String::from("\n")))?.is_some() {
if is_multiline && maybe_char(text, &Some(String::from(NEW_LINE_CHARS)))?.is_some() {
text.line += 1;
}

Expand Down
14 changes: 10 additions & 4 deletions tests/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ fn get_expected_basic() -> GuraType {
}
}

// Multiline char depends on platform (Windows handles \r\n, Unix \n, etc.)
const MULTILINE_VALUE: &str = "Roses are red\nViolets are blue";
const MULTILINE_VALUE_LINUX: &str = "Roses are red\nViolets are blue";
const MULTILINE_VALUE_WINDOWS: &str = "Roses are red\r\nViolets are blue";
const MULTILINE_VALUE_WITHOUT_NEWLINE: &str = "The quick brown fox jumps over the lazy dog.";
fn get_expected_multiline_basic() -> GuraType {
object! {
str: MULTILINE_VALUE,
str_2: MULTILINE_VALUE,
str: if cfg!(windows) { MULTILINE_VALUE_WINDOWS } else { MULTILINE_VALUE_LINUX },
str_2: if cfg!(windows) { MULTILINE_VALUE_WINDOWS } else { MULTILINE_VALUE_LINUX },
str_3: MULTILINE_VALUE,
with_var: MULTILINE_VALUE,
with_var: if cfg!(windows) { MULTILINE_VALUE_WINDOWS } else { MULTILINE_VALUE_LINUX },
with_env_var: MULTILINE_VALUE,
str_with_backslash: MULTILINE_VALUE_WITHOUT_NEWLINE,
str_with_backslash_2: MULTILINE_VALUE_WITHOUT_NEWLINE,
Expand All @@ -47,9 +50,12 @@ fn get_expected_literal() -> GuraType {
}
}

const LINES_LINUX: &str = "The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n";
const LINES_WINDOWS: &str = "The first newline is\r\ntrimmed in raw strings.\r\n All other whitespace\r\n is preserved.\r\n";

fn get_expected_multiline_literal() -> GuraType {
object! {
lines: "The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n",
lines: if cfg!(windows) { LINES_WINDOWS } else { LINES_LINUX },
regex2: "I [dw]on't need \\d{2} apples",
with_var: "$no_parsed variable!",
escaped_var: ESCAPED_VALUE
Expand Down
6 changes: 6 additions & 0 deletions tests/useless_lines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,9 @@ fn test_in_the_middle_object_complex() {
common::get_file_content_parsed(PARENT_FOLDER, "in_the_middle_object_complex.ura").unwrap();
assert_eq!(parsed_data, get_expected_object_complex());
}

#[test]
/// Tests issue https://github.com/gura-conf/gura-rs-parser/issues/13
fn test_issue_13() {
check_test_file("issue_13.ura");
}
10 changes: 10 additions & 0 deletions tests/useless_lines/tests-files/issue_13.ura
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
a_string: "test string"
int1: +99
int2: 42
int3: 0
int4: -17
int5: 1_000
int6: 5_349_221
int7: 53_49_221


0 comments on commit 5ae794f

Please sign in to comment.