Skip to content

Commit

Permalink
feat(draft): 2.0.0-draft.6 support (#92)
Browse files Browse the repository at this point in the history
This just adds support for the new multiline string syntax. There's no other necessary changes to support draft.6.
  • Loading branch information
zkat authored Dec 4, 2024
1 parent 71bd07b commit 233d4e4
Show file tree
Hide file tree
Showing 20 changed files with 95 additions and 57 deletions.
4 changes: 2 additions & 2 deletions examples/ci.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ jobs {
}
step Clippy { run cargo clippy --all -- -D warnings }
step "Run tests" { run cargo test --all --verbose }
step "Other Stuff" run="
step "Other Stuff" run="""
echo foo
echo bar
echo baz
"
"""
}
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
//! [`kaydle`](https://crates.io/crates/kaydle) instead for serde (or
//! serde-like) parsing.
//!
//! This crate supports parsing [KDL
//! 2.0.0-draft.6](https://github.com/kdl-org/kdl/releases/tag/2.0.0-draft.6)
//!
//! ## Example
//!
//! ```rust
Expand Down
87 changes: 55 additions & 32 deletions src/v2_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -766,13 +766,13 @@ fn equals_sign(input: &mut Input<'_>) -> PResult<()> {
}

/// ```text
/// quoted-string := '"' (single-line-string-body | newline multi-line-string-body newline unicode-space*) '"'
/// quoted-string := '"' single-line-string-body '"' | '"""' newline multi-line-string-body newline unicode-space*) '"""'
/// single-line-string-body := (string-character - newline)*
/// multi-line-string-body := string-character*
/// ```
fn quoted_string<'s>(input: &mut Input<'s>) -> PResult<Option<KdlValue>> {
"\"".parse_next(input)?;
let is_multiline = opt(newline).parse_next(input)?.is_some();
let quotes = alt((("\"\"\"", newline).take(), "\"")).parse_next(input)?;
let is_multiline = quotes.len() > 1;
let ml_prefix: Option<String> = if is_multiline {
Some(
peek(preceded(
Expand All @@ -782,10 +782,13 @@ fn quoted_string<'s>(input: &mut Input<'s>) -> PResult<Option<KdlValue>> {
repeat(0.., (not(newline), opt(ws_escape), string_char)).map(|()| ()),
newline,
),
peek(terminated(repeat(0.., unicode_space).map(|()| ()), "\"")),
peek(terminated(
repeat(0.., unicode_space).map(|()| ()),
"\"\"\"",
)),
)
.map(|((), ())| ()),
terminated(repeat(0.., unicode_space).map(|()| ()).take(), "\""),
terminated(repeat(0.., unicode_space).map(|()| ()).take(), "\"\"\""),
))
.parse_next(input)?
.to_string(),
Expand Down Expand Up @@ -814,7 +817,7 @@ fn quoted_string<'s>(input: &mut Input<'s>) -> PResult<Option<KdlValue>> {
(
&prefix[..],
repeat(0.., unicode_space).map(|()| ()).take(),
peek("\""),
peek("\"\"\""),
),
)
.map(|(s, _): (Vec<String>, (_, _, _))| {
Expand All @@ -836,9 +839,12 @@ fn quoted_string<'s>(input: &mut Input<'s>) -> PResult<Option<KdlValue>> {
.resume_after(quoted_string_badval)
.parse_next(input)?
};
cut_err("\"")
.context(lbl("closing quote"))
.parse_next(input)?;
let closing_quotes = if is_multiline {
"\"\"\"".context(lbl("multiline string closing quotes"))
} else {
"\"".context(lbl("string closing quote"))
};
cut_err(closing_quotes).parse_next(input)?;
Ok(body.map(KdlValue::String))
}

Expand Down Expand Up @@ -903,13 +909,15 @@ fn escaped_char(input: &mut Input<'_>) -> PResult<char> {
}

/// `raw-string := '#' raw-string-quotes '#' | '#' raw-string '#'`
/// `raw-string-quotes := '"' (single-line-raw-string-body | newline multi-line-raw-string-body newline unicode-space*) '"'`
/// `raw-string-quotes := '"' single-line-raw-string-body '"' | '"""' newline multi-line-raw-string-body newline unicode-space*) '"""'`
/// `single-line-raw-string-body := (unicode - newline - disallowed-literal-code-points)*`
/// `multi-line-raw-string-body := (unicode - disallowed-literal-code-points)`
fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
let hashes: String = repeat(1.., "#").parse_next(input)?;
"\"".parse_next(input)?;
let is_multiline = opt(newline).parse_next(input)?.is_some();
let quotes = alt((("\"\"\"", newline).take(), "\"")).parse_next(input)?;
let is_multiline = quotes.len() > 1;
dbg!(&quotes);
dbg!(is_multiline);
let ml_prefix: Option<String> = if is_multiline {
Some(
peek(preceded(
Expand All @@ -921,7 +929,7 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
(
not(newline),
not(disallowed_unicode),
not(("\"", &hashes[..])),
not(("\"\"\"", &hashes[..])),
any,
),
)
Expand All @@ -930,13 +938,13 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
),
peek(terminated(
repeat(0.., unicode_space).map(|()| ()),
("\"", &hashes[..]),
("\"\"\"", &hashes[..]),
)),
)
.map(|((), ())| ()),
terminated(
repeat(0.., unicode_space).map(|()| ()).take(),
("\"", &hashes[..]),
("\"\"\"", &hashes[..]),
),
))
.parse_next(input)?
Expand All @@ -945,6 +953,7 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
} else {
None
};
dbg!(&ml_prefix);
let body: Option<String> = if let Some(prefix) = ml_prefix {
repeat_till(
0..,
Expand All @@ -955,7 +964,7 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
newline.take().map(|_| "\n".to_string()),
repeat_till(
0..,
(not(newline), not(("\"", &hashes[..])), any)
(not(newline), not(("\"\"\"", &hashes[..])), any)
.map(|((), (), _)| ())
.take(),
newline,
Expand All @@ -968,7 +977,7 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
(
&prefix[..],
repeat(0.., unicode_space).map(|()| ()).take(),
peek(("\"", &hashes[..])),
peek(("\"\"\"", &hashes[..])),
),
)
.map(|(s, _): (Vec<String>, (_, _, _))| {
Expand Down Expand Up @@ -996,9 +1005,12 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
.resume_after(raw_string_badval)
.parse_next(input)?
};
cut_err(("\"", &hashes[..]))
.context(lbl("closing quote"))
.parse_next(input)?;
let closing_quotes = if is_multiline {
"\"\"\"".context(lbl("multiline raw string closing quotes"))
} else {
"\"".context(lbl("raw string closing quotes"))
};
cut_err((closing_quotes, &hashes[..])).parse_next(input)?;
Ok(body.map(KdlValue::String))
}

Expand Down Expand Up @@ -1044,40 +1056,46 @@ mod string_tests {
#[test]
fn multiline_quoted_string() {
assert_eq!(
string.parse(new_input("\"\nfoo\nbar\nbaz\n\"")).unwrap(),
string
.parse(new_input("\"\"\"\nfoo\nbar\nbaz\n\"\"\""))
.unwrap(),
Some(KdlValue::String("foo\nbar\nbaz".into()))
);
assert_eq!(
string
.parse(new_input("\"\n foo\n bar\n baz\n \""))
.parse(new_input("\"\"\"\n foo\n bar\n baz\n \"\"\""))
.unwrap(),
Some(KdlValue::String("foo\n bar\nbaz".into()))
);
assert_eq!(
string.parse(new_input("\"\nfoo\r\nbar\nbaz\n\"")).unwrap(),
string
.parse(new_input("\"\"\"\nfoo\r\nbar\nbaz\n\"\"\""))
.unwrap(),
Some(KdlValue::String("foo\nbar\nbaz".into()))
);
assert_eq!(
string
.parse(new_input("\"\n foo\n bar\n baz\n \""))
.parse(new_input("\"\"\"\n foo\n bar\n baz\n \"\"\""))
.unwrap(),
Some(KdlValue::String("foo\n bar\n baz".into()))
);
assert_eq!(
string
.parse(new_input("\"\n \\ foo\n \\ bar\n \\ baz\n \""))
.parse(new_input(
"\"\"\"\n \\ foo\n \\ bar\n \\ baz\n \"\"\""
))
.unwrap(),
Some(KdlValue::String("foo\n bar\n baz".into()))
);
assert_eq!(
string
.parse(new_input("\"\n\n string\t\n \""))
.parse(new_input("\"\"\"\n\n string\t\n \"\"\""))
.unwrap(),
Some(KdlValue::String("\nstring\t".into())),
"Empty line without any indentation"
);
assert!(string
.parse(new_input("\"\nfoo\n bar\n baz\n \""))
.parse(new_input("\"\"\"\nfoo\n bar\n baz\n \"\"\""))
.is_err());
}

Expand All @@ -1092,30 +1110,35 @@ mod string_tests {
#[test]
fn multiline_raw_string() {
assert_eq!(
string.parse(new_input("#\"\nfoo\nbar\nbaz\n\"#")).unwrap(),
string
.parse(new_input("#\"\"\"\nfoo\nbar\nbaz\n\"\"\"#"))
.unwrap(),
Some(KdlValue::String("foo\nbar\nbaz".into()))
);
assert_eq!(
string
.parse(new_input("#\"\nfoo\r\nbar\nbaz\n\"#"))
.parse(new_input("#\"\"\"\nfoo\r\nbar\nbaz\n\"\"\"#"))
.unwrap(),
Some(KdlValue::String("foo\nbar\nbaz".into()))
);
assert_eq!(
string
.parse(new_input("##\"\n foo\n bar\n baz\n \"##"))
.parse(new_input("##\"\"\"\n foo\n bar\n baz\n \"\"\"##"))
.unwrap(),
Some(KdlValue::String("foo\n bar\nbaz".into()))
);
assert_eq!(
string
.parse(new_input("#\"\n foo\n \\nbar\n baz\n \"#"))
.parse(new_input("#\"\"\"\n foo\n \\nbar\n baz\n \"\"\"#"))
.unwrap(),
Some(KdlValue::String("foo\n \\nbar\n baz".into()))
);
assert!(string
.parse(new_input("#\"\nfoo\n bar\n baz\n \"#"))
.parse(new_input("#\"\"\"\nfoo\n bar\n baz\n \"\"\"#"))
.is_err());

assert!(string.parse(new_input("#\"\nfoo\nbar\nbaz\n\"#")).is_err());
assert!(string.parse(new_input("\"\nfoo\nbar\nbaz\n\"")).is_err());
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion tests/test_cases/expected_kdl/unicode_silly.kdl
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ノード お名前=ฅ^•ﻌ•^ฅ
ノード お名前=ฅ^•ﻌ•^ฅ
4 changes: 2 additions & 2 deletions tests/test_cases/input/escaped_whitespace.kdl
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// All of these strings are the same
node \
"Hello\n\tWorld" \
"
"""
Hello
World
" \
""" \
"Hello\n\ \tWorld" \
"Hello\n\
\tWorld" \
Expand Down
4 changes: 2 additions & 2 deletions tests/test_cases/input/multiline_raw_string.kdl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node #"
node #"""
hey
everyone
how goes?
"#
"""#
4 changes: 2 additions & 2 deletions tests/test_cases/input/multiline_raw_string_indented.kdl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node #"
node #"""
hey
everyone
how goes?
"#
"""#
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node #"
node #"""
hey
everyone
how goes?
"#
"""#
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node #"
node #"""
hey
everyone
how goes?
"#
"""#
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node #"""one line"""#
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node #"
hey
everyone
how goes?
"#
4 changes: 2 additions & 2 deletions tests/test_cases/input/multiline_string.kdl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node "
node """
hey
everyone
how goes?
"
"""
4 changes: 2 additions & 2 deletions tests/test_cases/input/multiline_string_indented.kdl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node "
node """
hey
everyone
how goes?
"
"""
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node "
node """
hey
everyone
how goes?
"
"""
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node "
node """
hey
everyone
how goes?
"
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node """one line"""
5 changes: 5 additions & 0 deletions tests/test_cases/input/multiline_string_single_quote_err.kdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node "
hey
everyone
how goes?
"
4 changes: 2 additions & 2 deletions tests/test_cases/input/raw_string_newline.kdl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
node #"
node #"""
hello
world
"#
"""#
4 changes: 2 additions & 2 deletions tests/test_cases/input/slashdash_full_node.kdl
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/- node 1.0 "a" b="
/- node 1.0 "a" b="""
b
"
"""
File renamed without changes.

0 comments on commit 233d4e4

Please sign in to comment.