mirror of https://github.com/kdl-org/kdl-rs.git
feat(parser): update to 2.0.0-draft.5 (#90)
This commit is contained in:
parent
fb7c92b59f
commit
2802578ba0
|
|
@ -436,7 +436,7 @@ second_node /* This time, the comment is here */ param=153 {
|
||||||
/- comment
|
/- comment
|
||||||
/* block comment */
|
/* block comment */
|
||||||
inline /*comment*/ here
|
inline /*comment*/ here
|
||||||
another /-commend there
|
another /-comment there
|
||||||
|
|
||||||
|
|
||||||
after some whitespace
|
after some whitespace
|
||||||
|
|
@ -485,7 +485,7 @@ final;";
|
||||||
);
|
);
|
||||||
|
|
||||||
let foo = doc.get("foo").expect("expected a foo node");
|
let foo = doc.get("foo").expect("expected a foo node");
|
||||||
assert_eq!(foo.format().map(|f| &f.trailing[..]), Some("\n"));
|
assert_eq!(foo.format().map(|f| &f.terminator[..]), Some("\n"));
|
||||||
assert_eq!(&foo[2], &"three".into());
|
assert_eq!(&foo[2], &"three".into());
|
||||||
assert_eq!(&foo["bar"], &"baz".into());
|
assert_eq!(&foo["bar"], &"baz".into());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
@ -527,6 +527,7 @@ final;";
|
||||||
// if you're making KdlEntries this way, you need to inject
|
// if you're making KdlEntries this way, you need to inject
|
||||||
// your own whitespace (or format the node)
|
// your own whitespace (or format the node)
|
||||||
node.push(" \"blah\"=0xDEADbeef".parse::<KdlEntry>()?);
|
node.push(" \"blah\"=0xDEADbeef".parse::<KdlEntry>()?);
|
||||||
|
dbg!(&node);
|
||||||
doc.nodes_mut().push(node);
|
doc.nodes_mut().push(node);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
@ -714,7 +715,8 @@ this {
|
||||||
}
|
}
|
||||||
// that's
|
// that's
|
||||||
nice
|
nice
|
||||||
inline { time; to; live "our" "dreams"; "y;all"; }
|
inline { time; to; live "our" "dreams"; "y;all" }
|
||||||
|
|
||||||
"####;
|
"####;
|
||||||
|
|
||||||
let doc: KdlDocument = input.parse()?;
|
let doc: KdlDocument = input.parse()?;
|
||||||
|
|
@ -724,8 +726,9 @@ inline { time; to; live "our" "dreams"; "y;all"; }
|
||||||
|
|
||||||
// Now check some more interesting concrete spans
|
// Now check some more interesting concrete spans
|
||||||
|
|
||||||
// The whole document should presumably be "the input" again?
|
// The whole document should be everything from the first node until the
|
||||||
check_span(input, doc.span(), &input);
|
// last before_terminator whitespace.
|
||||||
|
check_span(&input[1..(input.len() - 2)], doc.span(), &input);
|
||||||
|
|
||||||
// This one-liner node should be the whole line without leading whitespace
|
// This one-liner node should be the whole line without leading whitespace
|
||||||
let is_node = doc
|
let is_node = doc
|
||||||
|
|
@ -772,13 +775,11 @@ inline { time; to; live "our" "dreams"; "y;all"; }
|
||||||
);
|
);
|
||||||
|
|
||||||
// The child document is a little weird, it's the contents *inside* the braces
|
// The child document is a little weird, it's the contents *inside* the braces
|
||||||
// with extra newlines on both ends.
|
// without the surrounding whitespace/comments. Just the actual contents.
|
||||||
check_span(
|
check_span(
|
||||||
r####"{
|
r####""it" /*shh*/ "has"="💯" ##"the"##
|
||||||
"it" /*shh*/ "has"="💯" ##"the"##
|
|
||||||
Best🎊est
|
Best🎊est
|
||||||
"syntax ever"
|
"syntax ever""####,
|
||||||
}"####,
|
|
||||||
and_node.children().unwrap().span(),
|
and_node.children().unwrap().span(),
|
||||||
&input,
|
&input,
|
||||||
);
|
);
|
||||||
|
|
@ -807,14 +808,14 @@ inline { time; to; live "our" "dreams"; "y;all"; }
|
||||||
// Make sure inline nodes work ok
|
// Make sure inline nodes work ok
|
||||||
let inline_node = doc.get("inline").unwrap();
|
let inline_node = doc.get("inline").unwrap();
|
||||||
check_span(
|
check_span(
|
||||||
r#"inline { time; to; live "our" "dreams"; "y;all"; }"#,
|
r#"inline { time; to; live "our" "dreams"; "y;all" }"#,
|
||||||
inline_node.span(),
|
inline_node.span(),
|
||||||
&input,
|
&input,
|
||||||
);
|
);
|
||||||
|
|
||||||
let inline_children = inline_node.children().unwrap();
|
let inline_children = inline_node.children().unwrap();
|
||||||
check_span(
|
check_span(
|
||||||
r#"{ time; to; live "our" "dreams"; "y;all"; }"#,
|
r#"time; to; live "our" "dreams"; "y;all" "#,
|
||||||
inline_children.span(),
|
inline_children.span(),
|
||||||
&input,
|
&input,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
31
src/node.rs
31
src/node.rs
|
|
@ -515,28 +515,30 @@ impl KdlNode {
|
||||||
pub(crate) fn autoformat_impl(&mut self, indent: usize, no_comments: bool) {
|
pub(crate) fn autoformat_impl(&mut self, indent: usize, no_comments: bool) {
|
||||||
if let Some(KdlNodeFormat {
|
if let Some(KdlNodeFormat {
|
||||||
leading,
|
leading,
|
||||||
|
before_terminator,
|
||||||
|
terminator,
|
||||||
trailing,
|
trailing,
|
||||||
before_children,
|
before_children,
|
||||||
..
|
..
|
||||||
}) = self.format_mut()
|
}) = self.format_mut()
|
||||||
{
|
{
|
||||||
crate::fmt::autoformat_leading(leading, indent, no_comments);
|
crate::fmt::autoformat_leading(leading, indent, no_comments);
|
||||||
|
crate::fmt::autoformat_trailing(before_terminator, no_comments);
|
||||||
crate::fmt::autoformat_trailing(trailing, no_comments);
|
crate::fmt::autoformat_trailing(trailing, no_comments);
|
||||||
*trailing = trailing.trim().into();
|
*trailing = trailing.trim().into();
|
||||||
if trailing.starts_with(';') {
|
if !terminator.starts_with('\n') {
|
||||||
trailing.remove(0);
|
*terminator = "\n".into();
|
||||||
}
|
}
|
||||||
if let Some(c) = trailing.chars().next() {
|
if let Some(c) = trailing.chars().next() {
|
||||||
if !c.is_whitespace() {
|
if !c.is_whitespace() {
|
||||||
trailing.insert(0, ' ');
|
trailing.insert(0, ' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trailing.push('\n');
|
|
||||||
|
|
||||||
*before_children = " ".into();
|
*before_children = " ".into();
|
||||||
} else {
|
} else {
|
||||||
self.set_format(KdlNodeFormat {
|
self.set_format(KdlNodeFormat {
|
||||||
trailing: "\n".into(),
|
terminator: "\n".into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -598,8 +600,14 @@ impl KdlNode {
|
||||||
}
|
}
|
||||||
write!(f, "}}")?;
|
write!(f, "}}")?;
|
||||||
}
|
}
|
||||||
if let Some(KdlNodeFormat { trailing, .. }) = self.format() {
|
if let Some(KdlNodeFormat {
|
||||||
write!(f, "{}", trailing)?;
|
before_terminator,
|
||||||
|
terminator,
|
||||||
|
trailing,
|
||||||
|
..
|
||||||
|
}) = self.format()
|
||||||
|
{
|
||||||
|
write!(f, "{before_terminator}{terminator}{trailing}")?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -618,8 +626,11 @@ pub struct KdlNodeFormat {
|
||||||
pub after_ty: String,
|
pub after_ty: String,
|
||||||
/// Whitespace and comments preceding the node's children block.
|
/// Whitespace and comments preceding the node's children block.
|
||||||
pub before_children: String,
|
pub before_children: String,
|
||||||
/// Whitespace and comments following the node itself, including the
|
/// Whitespace and comments right before the node's terminator.
|
||||||
/// optional semicolon.
|
pub before_terminator: String,
|
||||||
|
/// The terminator for the node.
|
||||||
|
pub terminator: String,
|
||||||
|
/// Whitespace and comments following the node itself, after the terminator.
|
||||||
pub trailing: String,
|
pub trailing: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -652,7 +663,9 @@ mod test {
|
||||||
node.format(),
|
node.format(),
|
||||||
Some(&KdlNodeFormat {
|
Some(&KdlNodeFormat {
|
||||||
leading: "\n\t ".into(),
|
leading: "\n\t ".into(),
|
||||||
trailing: ";\n".into(),
|
before_terminator: "".into(),
|
||||||
|
terminator: ";".into(),
|
||||||
|
trailing: "\n".into(),
|
||||||
before_ty_name: "".into(),
|
before_ty_name: "".into(),
|
||||||
after_ty_name: "".into(),
|
after_ty_name: "".into(),
|
||||||
after_ty: "".into(),
|
after_ty: "".into(),
|
||||||
|
|
|
||||||
351
src/v2_parser.rs
351
src/v2_parser.rs
|
|
@ -9,7 +9,8 @@ use num::CheckedMul;
|
||||||
use winnow::{
|
use winnow::{
|
||||||
ascii::{digit1, hex_digit1, oct_digit1, Caseless},
|
ascii::{digit1, hex_digit1, oct_digit1, Caseless},
|
||||||
combinator::{
|
combinator::{
|
||||||
alt, cut_err, eof, fail, not, opt, peek, preceded, repeat, repeat_till, terminated,
|
alt, cut_err, delimited, eof, fail, not, opt, peek, preceded, repeat, repeat_till,
|
||||||
|
separated, terminated,
|
||||||
},
|
},
|
||||||
error::{
|
error::{
|
||||||
AddContext, ContextError, ErrorKind, FromExternalError, FromRecoverableError, ParserError,
|
AddContext, ContextError, ErrorKind, FromExternalError, FromRecoverableError, ParserError,
|
||||||
|
|
@ -226,12 +227,16 @@ pub(crate) fn document(input: &mut Input<'_>) -> PResult<KdlDocument> {
|
||||||
|
|
||||||
/// `nodes := (line-space* node)* line-space*`
|
/// `nodes := (line-space* node)* line-space*`
|
||||||
fn nodes(input: &mut Input<'_>) -> PResult<KdlDocument> {
|
fn nodes(input: &mut Input<'_>) -> PResult<KdlDocument> {
|
||||||
let ((leading, nodes, trailing), _span) = (
|
let (leading, (nodes, _span), _final_terminator, trailing) = (
|
||||||
repeat(0.., line_space).map(|()| ()).take(),
|
repeat(0.., alt((line_space.void(), (slashdash, base_node).void())))
|
||||||
repeat(0.., node),
|
.map(|()| ())
|
||||||
repeat(0.., line_space).map(|()| ()).take(),
|
.take(),
|
||||||
|
separated(0.., node, node_terminator).with_span(),
|
||||||
|
opt(node_terminator),
|
||||||
|
repeat(0.., alt((line_space.void(), (slashdash, base_node).void())))
|
||||||
|
.map(|()| ())
|
||||||
|
.take(),
|
||||||
)
|
)
|
||||||
.with_span()
|
|
||||||
.parse_next(input)?;
|
.parse_next(input)?;
|
||||||
Ok(KdlDocument {
|
Ok(KdlDocument {
|
||||||
nodes,
|
nodes,
|
||||||
|
|
@ -244,35 +249,69 @@ fn nodes(input: &mut Input<'_>) -> PResult<KdlDocument> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `base-node := type? optional-node-space string (required-node-space node-prop-or-arg)* (required-node-space node-children)?`
|
/// base-node := slashdash? type? node-space* string
|
||||||
|
/// (node-space+ slashdash? node-prop-or-arg)*
|
||||||
|
/// (node-space+ slashdash node-children)*
|
||||||
|
/// (node-space+ node-children)?
|
||||||
|
/// (node-space+ slashdash node-children)*
|
||||||
|
/// node-space*
|
||||||
|
/// node := base-node node-space* node-terminator
|
||||||
|
/// final-node := base-node node-space* node-terminator?
|
||||||
|
fn node(input: &mut Input<'_>) -> PResult<KdlNode> {
|
||||||
|
let leading = repeat(0.., alt((line_space.void(), (slashdash, base_node).void())))
|
||||||
|
.map(|()| ())
|
||||||
|
.take()
|
||||||
|
.parse_next(input)?;
|
||||||
|
let mut nd = base_node.parse_next(input)?;
|
||||||
|
if let Some(fmt) = nd.format_mut() {
|
||||||
|
fmt.leading = leading.into();
|
||||||
|
}
|
||||||
|
Ok(nd)
|
||||||
|
}
|
||||||
|
|
||||||
fn base_node(input: &mut Input<'_>) -> PResult<KdlNode> {
|
fn base_node(input: &mut Input<'_>) -> PResult<KdlNode> {
|
||||||
let ((ty, after_ty, name, entries, children), _span) = (
|
let ((ty, after_ty, name, entries, children), _span) = (
|
||||||
opt(ty),
|
opt(ty),
|
||||||
optional_node_space.take(),
|
node_space0.take(),
|
||||||
identifier,
|
identifier,
|
||||||
repeat(
|
repeat(
|
||||||
0..,
|
0..,
|
||||||
(peek(required_node_space), node_entry).map(|(_, e): ((), _)| e),
|
(peek(node_space1), node_entry).map(|(_, e): ((), _)| e),
|
||||||
)
|
)
|
||||||
.map(|e: Vec<Option<KdlEntry>>| e.into_iter().flatten().collect::<Vec<KdlEntry>>()),
|
.map(|e: Vec<Option<KdlEntry>>| e.into_iter().flatten().collect::<Vec<KdlEntry>>()),
|
||||||
opt((optional_node_space.take(), node_children)),
|
opt((before_node_children.take(), node_children)),
|
||||||
)
|
)
|
||||||
.with_span()
|
.with_span()
|
||||||
.parse_next(input)?;
|
.parse_next(input)?;
|
||||||
|
let (before_terminator, terminator) = if children.is_some() {
|
||||||
|
(
|
||||||
|
opt(slashdashed_children).take(),
|
||||||
|
peek(opt(node_terminator).take()),
|
||||||
|
)
|
||||||
|
.parse_next(input)?
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
before_node_children.take(),
|
||||||
|
peek(opt(node_terminator).take()),
|
||||||
|
)
|
||||||
|
.parse_next(input)?
|
||||||
|
};
|
||||||
let (before_inner_ty, ty, after_inner_ty) = ty.unwrap_or_default();
|
let (before_inner_ty, ty, after_inner_ty) = ty.unwrap_or_default();
|
||||||
let (before_children, children) = children
|
let (before_children, children) = children
|
||||||
.map(|(before_children, children)| (before_children, Some(children)))
|
.map(|(before_children, children)| (before_children.into(), Some(children)))
|
||||||
.unwrap_or(("", None));
|
.unwrap_or(("".into(), None));
|
||||||
Ok(KdlNode {
|
Ok(KdlNode {
|
||||||
ty,
|
ty,
|
||||||
name,
|
name,
|
||||||
entries,
|
entries,
|
||||||
children,
|
children,
|
||||||
format: Some(KdlNodeFormat {
|
format: Some(KdlNodeFormat {
|
||||||
after_ty: after_ty.into(),
|
|
||||||
before_ty_name: before_inner_ty.into(),
|
before_ty_name: before_inner_ty.into(),
|
||||||
after_ty_name: after_inner_ty.into(),
|
after_ty_name: after_inner_ty.into(),
|
||||||
before_children: before_children.into(),
|
after_ty: after_ty.into(),
|
||||||
|
before_children,
|
||||||
|
before_terminator: before_terminator.into(),
|
||||||
|
terminator: terminator.into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
#[cfg(feature = "span")]
|
#[cfg(feature = "span")]
|
||||||
|
|
@ -280,25 +319,6 @@ fn base_node(input: &mut Input<'_>) -> PResult<KdlNode> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `node := base-node optional-node-space node-terminator`
|
|
||||||
fn node(input: &mut Input<'_>) -> PResult<KdlNode> {
|
|
||||||
let (leading, (mut node, _span), (trailing, terminator)) = (
|
|
||||||
repeat(0.., line_space).map(|()| ()).take(),
|
|
||||||
base_node.with_span(),
|
|
||||||
(optional_node_space.take(), node_terminator.take()),
|
|
||||||
)
|
|
||||||
.parse_next(input)?;
|
|
||||||
if let Some(fmt) = node.format_mut() {
|
|
||||||
fmt.leading = leading.into();
|
|
||||||
fmt.trailing = format!("{trailing}{terminator}");
|
|
||||||
}
|
|
||||||
#[cfg(feature = "span")]
|
|
||||||
{
|
|
||||||
node.span = _span.into();
|
|
||||||
}
|
|
||||||
Ok(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_node() {
|
fn test_node() {
|
||||||
|
|
@ -313,20 +333,13 @@ fn test_node() {
|
||||||
},
|
},
|
||||||
entries: vec![],
|
entries: vec![],
|
||||||
children: None,
|
children: None,
|
||||||
format: Some(KdlNodeFormat {
|
format: Some(Default::default()),
|
||||||
after_ty: "".into(),
|
|
||||||
before_ty_name: "".into(),
|
|
||||||
after_ty_name: "".into(),
|
|
||||||
before_children: "".into(),
|
|
||||||
leading: "".into(),
|
|
||||||
trailing: "".into()
|
|
||||||
}),
|
|
||||||
span: (0..7).into()
|
span: (0..7).into()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
base_node.parse(new_input("foo bar")).unwrap(),
|
node.parse(new_input("foo bar")).unwrap(),
|
||||||
KdlNode {
|
KdlNode {
|
||||||
ty: None,
|
ty: None,
|
||||||
name: KdlIdentifier {
|
name: KdlIdentifier {
|
||||||
|
|
@ -349,17 +362,15 @@ fn test_node() {
|
||||||
format: Some(KdlNodeFormat {
|
format: Some(KdlNodeFormat {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
span: (0..7).into()
|
span: (0..8).into()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn padded_node(input: &mut Input<'_>) -> PResult<KdlNode> {
|
pub(crate) fn padded_node(input: &mut Input<'_>) -> PResult<KdlNode> {
|
||||||
let ((leading, mut node, trailing), _span) = (
|
let ((mut node, _terminator, trailing), _span) = (
|
||||||
repeat(0.., alt((line_space, node_space)))
|
|
||||||
.map(|_: ()| ())
|
|
||||||
.take(),
|
|
||||||
node,
|
node,
|
||||||
|
opt(node_terminator),
|
||||||
repeat(0.., alt((line_space, node_space)))
|
repeat(0.., alt((line_space, node_space)))
|
||||||
.map(|_: ()| ())
|
.map(|_: ()| ())
|
||||||
.take(),
|
.take(),
|
||||||
|
|
@ -367,8 +378,7 @@ pub(crate) fn padded_node(input: &mut Input<'_>) -> PResult<KdlNode> {
|
||||||
.with_span()
|
.with_span()
|
||||||
.parse_next(input)?;
|
.parse_next(input)?;
|
||||||
if let Some(fmt) = node.format_mut() {
|
if let Some(fmt) = node.format_mut() {
|
||||||
fmt.leading = format!("{leading}{}", fmt.leading);
|
fmt.trailing = trailing.into();
|
||||||
fmt.trailing = format!("{}{trailing}", fmt.trailing);
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "span")]
|
#[cfg(feature = "span")]
|
||||||
{
|
{
|
||||||
|
|
@ -377,14 +387,6 @@ pub(crate) fn padded_node(input: &mut Input<'_>) -> PResult<KdlNode> {
|
||||||
Ok(node)
|
Ok(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `final-node := base-node optional-node-space node-terminator?`
|
|
||||||
fn final_node(input: &mut Input<'_>) -> PResult<KdlNode> {
|
|
||||||
let node = base_node.parse_next(input)?;
|
|
||||||
optional_node_space.parse_next(input)?;
|
|
||||||
opt(node_terminator).parse_next(input)?;
|
|
||||||
Ok(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn padded_node_entry(input: &mut Input<'_>) -> PResult<KdlEntry> {
|
pub(crate) fn padded_node_entry(input: &mut Input<'_>) -> PResult<KdlEntry> {
|
||||||
let ((leading, entry, trailing), _span) = (
|
let ((leading, entry, trailing), _span) = (
|
||||||
repeat(0.., line_space).map(|_: ()| ()).take(),
|
repeat(0.., line_space).map(|_: ()| ()).take(),
|
||||||
|
|
@ -414,8 +416,11 @@ pub(crate) fn padded_node_entry(input: &mut Input<'_>) -> PResult<KdlEntry> {
|
||||||
|
|
||||||
/// `node-prop-or-arg := prop | value`
|
/// `node-prop-or-arg := prop | value`
|
||||||
fn node_entry(input: &mut Input<'_>) -> PResult<Option<KdlEntry>> {
|
fn node_entry(input: &mut Input<'_>) -> PResult<Option<KdlEntry>> {
|
||||||
let (leading, mut entry) =
|
let (leading, mut entry) = (
|
||||||
(optional_node_space.take(), alt((prop, value))).parse_next(input)?;
|
(node_space0, opt((slashdashed_entries, node_space1))).take(),
|
||||||
|
alt((prop, value)),
|
||||||
|
)
|
||||||
|
.parse_next(input)?;
|
||||||
entry = entry.map(|mut e| {
|
entry = entry.map(|mut e| {
|
||||||
if let Some(fmt) = e.format_mut() {
|
if let Some(fmt) = e.format_mut() {
|
||||||
fmt.leading = leading.into();
|
fmt.leading = leading.into();
|
||||||
|
|
@ -425,6 +430,15 @@ fn node_entry(input: &mut Input<'_>) -> PResult<Option<KdlEntry>> {
|
||||||
Ok(entry)
|
Ok(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn slashdashed_entries(input: &mut Input<'_>) -> PResult<()> {
|
||||||
|
separated(1.., (slashdash, node_entry), node_space1)
|
||||||
|
.map(|()| ())
|
||||||
|
.take()
|
||||||
|
.map(|x| x.to_string())
|
||||||
|
.parse_next(input)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[test]
|
#[test]
|
||||||
fn entry_test() {
|
fn entry_test() {
|
||||||
|
|
@ -455,37 +469,127 @@ fn entry_test() {
|
||||||
span: (0..3).into()
|
span: (0..3).into()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
node_entry.parse(new_input("/-foo bar")).unwrap(),
|
||||||
|
Some(KdlEntry {
|
||||||
|
ty: None,
|
||||||
|
value: KdlValue::String("bar".into()),
|
||||||
|
name: None,
|
||||||
|
format: Some(KdlEntryFormat {
|
||||||
|
value_repr: "bar".into(),
|
||||||
|
leading: "/-foo ".into(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
span: (6..9).into()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
node_entry.parse(new_input("/- foo=1 bar = 2")).unwrap(),
|
||||||
|
Some(KdlEntry {
|
||||||
|
ty: None,
|
||||||
|
value: 2.into(),
|
||||||
|
name: Some(KdlIdentifier {
|
||||||
|
value: "bar".into(),
|
||||||
|
repr: Some("bar".into()),
|
||||||
|
span: (9..12).into(),
|
||||||
|
}),
|
||||||
|
format: Some(KdlEntryFormat {
|
||||||
|
value_repr: "2".into(),
|
||||||
|
leading: "/- foo=1 ".into(),
|
||||||
|
after_ty: " ".into(),
|
||||||
|
after_eq: " ".into(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
span: (9..16).into()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
node_entry.parse(new_input("/- \nfoo = 1 bar = 2")).unwrap(),
|
||||||
|
Some(KdlEntry {
|
||||||
|
ty: None,
|
||||||
|
value: 2.into(),
|
||||||
|
name: Some(KdlIdentifier {
|
||||||
|
value: "bar".into(),
|
||||||
|
repr: Some("bar".into()),
|
||||||
|
span: (12..16).into(),
|
||||||
|
}),
|
||||||
|
format: Some(KdlEntryFormat {
|
||||||
|
value_repr: "2".into(),
|
||||||
|
leading: "/- \nfoo = 1 ".into(),
|
||||||
|
after_ty: " ".into(),
|
||||||
|
after_eq: " ".into(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
span: (12..18).into()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_node_children(input: &mut Input<'_>) -> PResult<()> {
|
||||||
|
alt((
|
||||||
|
(
|
||||||
|
node_space1,
|
||||||
|
slashdashed_entries,
|
||||||
|
// This second one will fail if `node_entry_leading` is empty.
|
||||||
|
node_space1,
|
||||||
|
slashdashed_children,
|
||||||
|
)
|
||||||
|
.take(),
|
||||||
|
(node_space1, slashdashed_entries).take(),
|
||||||
|
(node_space1, slashdashed_children).take(),
|
||||||
|
node_space0.take(),
|
||||||
|
))
|
||||||
|
.void()
|
||||||
|
.parse_next(input)?;
|
||||||
|
node_space0.parse_next(input)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn before_node_children_test() {
|
||||||
|
assert!(before_node_children.parse(new_input(" /- { }")).is_ok());
|
||||||
|
assert!(before_node_children.parse(new_input(" /- { bar }")).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn slashdashed_children(input: &mut Input<'_>) -> PResult<()> {
|
||||||
|
node_space0.parse_next(input)?;
|
||||||
|
separated(
|
||||||
|
1..,
|
||||||
|
(slashdash.void(), node_children.void()).void(),
|
||||||
|
node_space1,
|
||||||
|
)
|
||||||
|
.map(|()| ())
|
||||||
|
.parse_next(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn around_children_test() {
|
||||||
|
assert!(slashdashed_children.parse(new_input("/- { }")).is_ok());
|
||||||
|
assert!(slashdashed_children.parse(new_input("/- { bar }")).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `node-children := '{' nodes final-node? '}'`
|
/// `node-children := '{' nodes final-node? '}'`
|
||||||
fn node_children(input: &mut Input<'_>) -> PResult<KdlDocument> {
|
fn node_children(input: &mut Input<'_>) -> PResult<KdlDocument> {
|
||||||
let _start = input.location();
|
delimited("{", nodes, cut_err("}")).parse_next(input)
|
||||||
"{".parse_next(input)?;
|
|
||||||
let mut ns = nodes.parse_next(input)?;
|
|
||||||
let fin = opt(final_node).parse_next(input)?;
|
|
||||||
if let Some(fin) = fin {
|
|
||||||
ns.nodes.push(fin);
|
|
||||||
}
|
|
||||||
cut_err("}").parse_next(input)?;
|
|
||||||
#[cfg(feature = "span")]
|
|
||||||
{
|
|
||||||
ns.span = (_start..input.location()).into();
|
|
||||||
}
|
|
||||||
Ok(ns)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `node-terminator := single-line-comment | newline | ';' | eof`
|
/// `node-terminator := single-line-comment | newline | ';' | eof`
|
||||||
fn node_terminator(input: &mut Input<'_>) -> PResult<()> {
|
fn node_terminator(input: &mut Input<'_>) -> PResult<()> {
|
||||||
alt((eof.void(), ";".void(), newline, single_line_comment)).parse_next(input)
|
alt((";".void(), newline, single_line_comment)).parse_next(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `prop := string optional-node-space equals-sign optional-node-space value`
|
/// `prop := string optional-node-space equals-sign optional-node-space value`
|
||||||
fn prop(input: &mut Input<'_>) -> PResult<Option<KdlEntry>> {
|
fn prop(input: &mut Input<'_>) -> PResult<Option<KdlEntry>> {
|
||||||
let ((key, after_key, _eqa, after_eq, value), _span) = (
|
let ((key, after_key, _eqa, after_eq, value), _span) = (
|
||||||
identifier,
|
identifier,
|
||||||
optional_node_space.take(),
|
node_space0.take(),
|
||||||
equals_sign.take(),
|
equals_sign.take(),
|
||||||
optional_node_space.take(),
|
node_space0.take(),
|
||||||
cut_err(value),
|
cut_err(value),
|
||||||
)
|
)
|
||||||
.with_span()
|
.with_span()
|
||||||
|
|
@ -507,7 +611,7 @@ fn prop(input: &mut Input<'_>) -> PResult<Option<KdlEntry>> {
|
||||||
/// `value := type? optional-node-space (string | number | keyword)`
|
/// `value := type? optional-node-space (string | number | keyword)`
|
||||||
fn value(input: &mut Input<'_>) -> PResult<Option<KdlEntry>> {
|
fn value(input: &mut Input<'_>) -> PResult<Option<KdlEntry>> {
|
||||||
let ((ty, (value, raw)), _span) = (
|
let ((ty, (value, raw)), _span) = (
|
||||||
opt((ty, optional_node_space.take())),
|
opt((ty, node_space0.take())),
|
||||||
alt((keyword.map(Some), number.map(Some), string)).with_taken(),
|
alt((keyword.map(Some), number.map(Some), string)).with_taken(),
|
||||||
)
|
)
|
||||||
.with_span()
|
.with_span()
|
||||||
|
|
@ -533,71 +637,34 @@ fn value(input: &mut Input<'_>) -> PResult<Option<KdlEntry>> {
|
||||||
fn ty<'s>(input: &mut Input<'s>) -> PResult<(&'s str, Option<KdlIdentifier>, &'s str)> {
|
fn ty<'s>(input: &mut Input<'s>) -> PResult<(&'s str, Option<KdlIdentifier>, &'s str)> {
|
||||||
"(".parse_next(input)?;
|
"(".parse_next(input)?;
|
||||||
let (before_ty, ty, after_ty) = (
|
let (before_ty, ty, after_ty) = (
|
||||||
optional_node_space.take(),
|
node_space0.take(),
|
||||||
cut_err(identifier.context(lbl("type name")))
|
cut_err(identifier.context(lbl("type name")))
|
||||||
.resume_after((badval, peek(")").void(), badval).void()),
|
.resume_after((badval, peek(")").void(), badval).void()),
|
||||||
optional_node_space.take(),
|
node_space0.take(),
|
||||||
)
|
)
|
||||||
.parse_next(input)?;
|
.parse_next(input)?;
|
||||||
cut_err(")").parse_next(input)?;
|
cut_err(")").parse_next(input)?;
|
||||||
Ok((before_ty, ty, after_ty))
|
Ok((before_ty, ty, after_ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `plain-line-space := newline | ws | single-line-comment`
|
/// `line-space := newline | ws | single-line-comment`
|
||||||
fn plain_line_space(input: &mut Input<'_>) -> PResult<()> {
|
fn line_space(input: &mut Input<'_>) -> PResult<()> {
|
||||||
alt((newline, ws, single_line_comment)).parse_next(input)
|
alt((newline, ws, single_line_comment)).parse_next(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `plain-node-space := ws* escline ws* | ws+`
|
/// `node-space := ws* escline ws* | ws+`
|
||||||
fn plain_node_space(input: &mut Input<'_>) -> PResult<()> {
|
fn node_space(input: &mut Input<'_>) -> PResult<()> {
|
||||||
alt(((wss, escline, wss).void(), wsp)).parse_next(input)
|
alt(((wss, escline, wss).void(), wsp)).parse_next(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `line-space := plain-line-space+ | '/-' plain-node-space* node`
|
fn node_space0(input: &mut Input<'_>) -> PResult<()> {
|
||||||
fn line_space(input: &mut Input<'_>) -> PResult<()> {
|
|
||||||
alt((
|
|
||||||
repeat(1.., plain_line_space).map(|_: ()| ()).void(),
|
|
||||||
(
|
|
||||||
"/-",
|
|
||||||
repeat(0.., plain_node_space).map(|_: ()| ()),
|
|
||||||
cut_err(node),
|
|
||||||
)
|
|
||||||
.void()
|
|
||||||
.context(lbl("slashdashed node")),
|
|
||||||
))
|
|
||||||
.parse_next(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `node-space := plain-node-space+ ('/-' plain-node-space* (node-prop-or-arg | node-children))?`
|
|
||||||
fn node_space(input: &mut Input<'_>) -> PResult<()> {
|
|
||||||
repeat(1.., plain_node_space)
|
|
||||||
.map(|_: ()| ())
|
|
||||||
.parse_next(input)?;
|
|
||||||
opt((
|
|
||||||
"/-",
|
|
||||||
repeat(0.., plain_node_space).map(|_: ()| ()),
|
|
||||||
cut_err(alt((
|
|
||||||
node_entry.void().context(lbl("slashdashed entry")),
|
|
||||||
node_children.void().context(lbl("slashdashed children")),
|
|
||||||
))),
|
|
||||||
))
|
|
||||||
.void()
|
|
||||||
.parse_next(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `required-node-space := node-space* plain-node-space+`
|
|
||||||
fn required_node_space(input: &mut Input<'_>) -> PResult<()> {
|
|
||||||
repeat(0.., (node_space, peek(plain_node_space)))
|
|
||||||
.map(|_: ()| ())
|
|
||||||
.parse_next(input)?;
|
|
||||||
repeat(1.., plain_node_space).parse_next(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `optional-node-space := node-space*`
|
|
||||||
fn optional_node_space(input: &mut Input<'_>) -> PResult<()> {
|
|
||||||
repeat(0.., node_space).parse_next(input)
|
repeat(0.., node_space).parse_next(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn node_space1(input: &mut Input<'_>) -> PResult<()> {
|
||||||
|
repeat(1.., node_space).parse_next(input)
|
||||||
|
}
|
||||||
|
|
||||||
/// `string := identifier-string | quoted-string | raw-string`
|
/// `string := identifier-string | quoted-string | raw-string`
|
||||||
pub(crate) fn string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
|
pub(crate) fn string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
|
||||||
alt((identifier_string, raw_string, quoted_string))
|
alt((identifier_string, raw_string, quoted_string))
|
||||||
|
|
@ -1134,7 +1201,7 @@ fn escline(input: &mut Input<'_>) -> PResult<()> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[test]
|
#[test]
|
||||||
fn escline_test() {
|
fn escline_test() {
|
||||||
let node = node.parse(new_input("foo bar\\\n baz\n")).unwrap();
|
let node = node.parse(new_input("foo bar\\\n baz")).unwrap();
|
||||||
assert_eq!(node.entries().len(), 2);
|
assert_eq!(node.entries().len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1231,6 +1298,32 @@ fn multi_line_comment_test() {
|
||||||
.is_ok());
|
.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// slashdash := '/-' line-space*
|
||||||
|
fn slashdash(input: &mut Input<'_>) -> PResult<()> {
|
||||||
|
("/-", repeat(0.., line_space).map(|()| ()))
|
||||||
|
.void()
|
||||||
|
.parse_next(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn slashdash_tests() {
|
||||||
|
assert!(document.parse(new_input("/- foo bar")).is_ok());
|
||||||
|
assert!(node.parse(new_input("/- foo\nbar baz")).is_ok());
|
||||||
|
assert!(node_entry.parse(new_input("/-commented tada")).is_ok());
|
||||||
|
assert!(node.parse(new_input("foo /- { }")).is_ok());
|
||||||
|
assert!(node.parse(new_input("foo /- { bar }")).is_ok());
|
||||||
|
assert!(node
|
||||||
|
.parse(new_input("/- foo bar\nnode /-1 2 { x }"))
|
||||||
|
.is_ok());
|
||||||
|
assert!(node
|
||||||
|
.parse(new_input("/- foo bar\nnode 2 /-3 { x }"))
|
||||||
|
.is_ok());
|
||||||
|
assert!(node
|
||||||
|
.parse(new_input("/- foo bar\nnode /-1 2 /-3 { x }"))
|
||||||
|
.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
/// `number := keyword-number | hex | octal | binary | decimal`
|
/// `number := keyword-number | hex | octal | binary | decimal`
|
||||||
fn number(input: &mut Input<'_>) -> PResult<KdlValue> {
|
fn number(input: &mut Input<'_>) -> PResult<KdlValue> {
|
||||||
alt((float_value, integer_value)).parse_next(input)
|
alt((float_value, integer_value)).parse_next(input)
|
||||||
|
|
@ -1384,7 +1477,7 @@ fn test_hex() {
|
||||||
hex::<i128>
|
hex::<i128>
|
||||||
.parse(new_input("0xABCDEF0123456789abcdef0123456789"))
|
.parse(new_input("0xABCDEF0123456789abcdef0123456789"))
|
||||||
.is_err(),
|
.is_err(),
|
||||||
"i128 overflow"
|
"i128 overflow"
|
||||||
);
|
);
|
||||||
assert!(hex::<i128>.parse(new_input("0x_deadbeef123")).is_err());
|
assert!(hex::<i128>.parse(new_input("0x_deadbeef123")).is_err());
|
||||||
|
|
||||||
|
|
@ -1477,11 +1570,7 @@ fn test_binary() {
|
||||||
fn signum(input: &mut Input<'_>) -> PResult<bool> {
|
fn signum(input: &mut Input<'_>) -> PResult<bool> {
|
||||||
let sign = opt(alt(('+', '-'))).parse_next(input)?;
|
let sign = opt(alt(('+', '-'))).parse_next(input)?;
|
||||||
let mult = if let Some(sign) = sign {
|
let mult = if let Some(sign) = sign {
|
||||||
if sign == '+' {
|
sign == '+'
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ fn spec_compliance() -> miette::Result<()> {
|
||||||
fn validate_res(
|
fn validate_res(
|
||||||
res: Result<KdlDocument, KdlParseFailure>,
|
res: Result<KdlDocument, KdlParseFailure>,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
src: &String,
|
src: &str,
|
||||||
) -> Result<(), ComplianceDiagnostic> {
|
) -> Result<(), ComplianceDiagnostic> {
|
||||||
let file_name = path.file_name().unwrap();
|
let file_name = path.file_name().unwrap();
|
||||||
let expected_dir = path
|
let expected_dir = path
|
||||||
|
|
@ -94,9 +94,9 @@ fn validate_res(
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
return Err(ComplianceDiagnostic::ExpectationMismatch {
|
return Err(ComplianceDiagnostic::ExpectationMismatch {
|
||||||
file: path.into(),
|
file: path.into(),
|
||||||
original: src.clone(),
|
original: src.into(),
|
||||||
expected,
|
expected: expected.replace('\n', "\\n").replace(" ", "."),
|
||||||
actual,
|
actual: actual.replace('\n', "\\n").replace(" ", "."),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if underscored.exists() {
|
} else if underscored.exists() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
node 1 3
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
node 1 3
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
node foo {
|
||||||
|
three
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
node 1 2
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
node 1 3
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
node 1 3
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
node2
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
ノード お名前=ฅ^•ﻌ•^ฅ
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
node /-{
|
||||||
|
child
|
||||||
|
} foo {
|
||||||
|
bar
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
node 1 /- /*
|
||||||
|
multi
|
||||||
|
line
|
||||||
|
comment
|
||||||
|
here
|
||||||
|
*/ 2 3
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
node 1 /-/*two*/2 3
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
node foo /-{
|
||||||
|
one
|
||||||
|
} \
|
||||||
|
/-{
|
||||||
|
two
|
||||||
|
} {
|
||||||
|
three
|
||||||
|
} /-{
|
||||||
|
four
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
node 1 2 /-
|
||||||
|
{
|
||||||
|
child
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
node 1 /-
|
||||||
|
2 3
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
/-
|
||||||
|
node 1 2 3
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
node 1 /- // stuff
|
||||||
|
2 3
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
/- // this is a comment
|
||||||
|
node1
|
||||||
|
node2
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
ノード お名前=ฅ^•ﻌ•^ฅ
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
node {
|
||||||
Loading…
Reference in New Issue