Skip to content

Commit 6a7248c

Browse files
authored
feat(v1): add rudimentary, optional, KDL v1 parsing (#104)
This is kinda rough right now, since it involves actually pulling in the old kdl v1. Not ideal, but workable as a stepping stone while a real v1 parser gets written.
1 parent 683e87a commit 6a7248c

File tree

8 files changed

+214
-6
lines changed

8 files changed

+214
-6
lines changed

Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,21 @@ readme = "README.md"
88
homepage = "https://kdl.dev"
99
repository = "https://github.com/kdl-org/kdl-rs"
1010
keywords = ["kdl", "document", "serialization", "config"]
11-
rust-version = "1.56.0"
11+
rust-version = "1.70.0"
1212
edition = "2021"
1313

1414
[features]
15-
default = ["span"]
15+
default = ["span", "v1"]
1616
span = []
17+
v1-fallback = ["v1"]
18+
v1 = ["kdlv1"]
1719

1820
[dependencies]
1921
miette = "7.2.0"
2022
num = "0.4.2"
2123
thiserror = "1.0.40"
2224
winnow = { version = "0.6.20", features = ["alloc", "unstable-recover"] }
25+
kdlv1 = { package = "kdl", version = "4.7.0", optional = true }
2326

2427
[dev-dependencies]
2528
miette = { version = "7.2.0", features = ["fancy"] }

clippy.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
msrv = "1.56.0"
1+
msrv = "1.70.0"

src/document.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,13 +334,53 @@ impl KdlDocument {
334334
// .query_all(query)?
335335
// .filter_map(move |node| node.get(key.clone())))
336336
// }
337+
338+
/// Parses a string into a document.
339+
///
340+
/// If the `v1-fallback` feature is enabled, this method will first try to
341+
/// parse the string as a KDL v2 document, and, if that fails, it will try
342+
/// to parse again as a KDL v1 document. If both fail, only the v2 parse
343+
/// errors will be returned.
344+
pub fn parse(s: &str) -> Result<Self, KdlParseFailure> {
345+
#[cfg(not(feature = "v1-fallback"))]
346+
{
347+
crate::v2_parser::try_parse(crate::v2_parser::document, s)
348+
}
349+
#[cfg(feature = "v1-fallback")]
350+
{
351+
crate::v2_parser::try_parse(crate::v2_parser::document, s)
352+
.or_else(|e| KdlDocument::parse_v1(s).map_err(|_| e))
353+
}
354+
}
355+
356+
/// Parses a KDL v1 string into a document.
357+
#[cfg(feature = "v1")]
358+
pub fn parse_v1(s: &str) -> Result<Self, KdlParseFailure> {
359+
let ret: Result<kdlv1::KdlDocument, kdlv1::KdlError> = s.parse();
360+
ret.map(|x| x.into()).map_err(|e| e.into())
361+
}
362+
}
363+
364+
#[cfg(feature = "v1")]
365+
impl From<kdlv1::KdlDocument> for KdlDocument {
366+
fn from(value: kdlv1::KdlDocument) -> Self {
367+
KdlDocument {
368+
nodes: value.nodes().iter().map(|x| x.clone().into()).collect(),
369+
format: Some(KdlDocumentFormat {
370+
leading: value.leading().unwrap_or("").into(),
371+
trailing: value.trailing().unwrap_or("").into(),
372+
}),
373+
#[cfg(feature = "span")]
374+
span: SourceSpan::new(value.span().offset().into(), value.span().len()),
375+
}
376+
}
337377
}
338378

339379
impl std::str::FromStr for KdlDocument {
340380
type Err = KdlParseFailure;
341381

342382
fn from_str(s: &str) -> Result<Self, Self::Err> {
343-
crate::v2_parser::try_parse(crate::v2_parser::document, s)
383+
KdlDocument::parse(s)
344384
}
345385
}
346386

src/entry.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,50 @@ impl KdlEntry {
178178
name.autoformat();
179179
}
180180
}
181+
182+
/// Parses a string into a entry.
183+
///
184+
/// If the `v1-fallback` feature is enabled, this method will first try to
185+
/// parse the string as a KDL v2 entry, and, if that fails, it will try
186+
/// to parse again as a KDL v1 entry. If both fail, only the v2 parse
187+
/// errors will be returned.
188+
pub fn parse(s: &str) -> Result<Self, KdlParseFailure> {
189+
#[cfg(not(feature = "v1-fallback"))]
190+
{
191+
v2_parser::try_parse(v2_parser::padded_node_entry, s)
192+
}
193+
#[cfg(feature = "v1-fallback")]
194+
{
195+
v2_parser::try_parse(v2_parser::padded_node_entry, s)
196+
.or_else(|e| KdlEntry::parse_v1(s).map_err(|_| e))
197+
}
198+
}
199+
200+
/// Parses a KDL v1 string into an entry.
201+
#[cfg(feature = "v1")]
202+
pub fn parse_v1(s: &str) -> Result<Self, KdlParseFailure> {
203+
let ret: Result<kdlv1::KdlEntry, kdlv1::KdlError> = s.parse();
204+
ret.map(|x| x.into()).map_err(|e| e.into())
205+
}
206+
}
207+
208+
#[cfg(feature = "v1")]
209+
impl From<kdlv1::KdlEntry> for KdlEntry {
210+
fn from(value: kdlv1::KdlEntry) -> Self {
211+
KdlEntry {
212+
ty: value.ty().map(|x| x.clone().into()),
213+
value: value.value().clone().into(),
214+
name: value.name().map(|x| x.clone().into()),
215+
format: Some(KdlEntryFormat {
216+
value_repr: value.value_repr().unwrap_or("").into(),
217+
leading: value.leading().unwrap_or("").into(),
218+
trailing: value.trailing().unwrap_or("").into(),
219+
..Default::default()
220+
}),
221+
#[cfg(feature = "span")]
222+
span: SourceSpan::new(value.span().offset().into(), value.span().len()),
223+
}
224+
}
181225
}
182226

183227
impl Display for KdlEntry {
@@ -249,7 +293,7 @@ impl FromStr for KdlEntry {
249293
type Err = KdlParseFailure;
250294

251295
fn from_str(s: &str) -> Result<Self, Self::Err> {
252-
v2_parser::try_parse(v2_parser::padded_node_entry, s)
296+
KdlEntry::parse(s)
253297
}
254298
}
255299

src/error.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,21 @@ pub struct KdlDiagnostic {
7474
#[diagnostic(severity)]
7575
pub severity: miette::Severity,
7676
}
77+
78+
#[cfg(feature = "v1")]
79+
impl From<kdlv1::KdlError> for KdlParseFailure {
80+
fn from(value: kdlv1::KdlError) -> Self {
81+
let input = Arc::new(value.input);
82+
KdlParseFailure {
83+
input: input.clone(),
84+
diagnostics: vec![KdlDiagnostic {
85+
input,
86+
span: SourceSpan::new(value.span.offset().into(), value.span.len()),
87+
message: Some(format!("{}", value.kind)),
88+
label: value.label.map(|x| x.into()),
89+
help: value.help.map(|x| x.into()),
90+
severity: miette::Severity::Error,
91+
}],
92+
}
93+
}
94+
}

src/identifier.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,43 @@ impl KdlIdentifier {
8787
pub fn autoformat(&mut self) {
8888
self.repr = None;
8989
}
90+
91+
/// Parses a string into a entry.
92+
///
93+
/// If the `v1-fallback` feature is enabled, this method will first try to
94+
/// parse the string as a KDL v2 entry, and, if that fails, it will try
95+
/// to parse again as a KDL v1 entry. If both fail, only the v2 parse
96+
/// errors will be returned.
97+
pub fn parse(s: &str) -> Result<Self, KdlParseFailure> {
98+
#[cfg(not(feature = "v1-fallback"))]
99+
{
100+
v2_parser::try_parse(v2_parser::identifier, s)
101+
}
102+
#[cfg(feature = "v1-fallback")]
103+
{
104+
v2_parser::try_parse(v2_parser::identifier, s)
105+
.or_else(|e| KdlIdentifier::parse_v1(s).map_err(|_| e))
106+
}
107+
}
108+
109+
/// Parses a KDL v1 string into an entry.
110+
#[cfg(feature = "v1")]
111+
pub fn parse_v1(s: &str) -> Result<Self, KdlParseFailure> {
112+
let ret: Result<kdlv1::KdlIdentifier, kdlv1::KdlError> = s.parse();
113+
ret.map(|x| x.into()).map_err(|e| e.into())
114+
}
115+
}
116+
117+
#[cfg(feature = "v1")]
118+
impl From<kdlv1::KdlIdentifier> for KdlIdentifier {
119+
fn from(value: kdlv1::KdlIdentifier) -> Self {
120+
KdlIdentifier {
121+
value: value.value().into(),
122+
repr: value.repr().map(|x| x.into()),
123+
#[cfg(feature = "span")]
124+
span: SourceSpan::new(value.span().offset().into(), value.span().len()),
125+
}
126+
}
90127
}
91128

92129
impl Display for KdlIdentifier {
@@ -131,7 +168,7 @@ impl FromStr for KdlIdentifier {
131168
type Err = KdlParseFailure;
132169

133170
fn from_str(s: &str) -> Result<Self, Self::Err> {
134-
v2_parser::try_parse(v2_parser::identifier, s)
171+
KdlIdentifier::parse(s)
135172
}
136173
}
137174

src/node.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,55 @@ impl KdlNode {
325325
}
326326
}
327327
}
328+
329+
/// Parses a string into a node.
330+
///
331+
/// If the `v1-fallback` feature is enabled, this method will first try to
332+
/// parse the string as a KDL v2 node, and, if that fails, it will try
333+
/// to parse again as a KDL v1 node. If both fail, only the v2 parse
334+
/// errors will be returned.
335+
pub fn parse(s: &str) -> Result<Self, KdlParseFailure> {
336+
#[cfg(not(feature = "v1-fallback"))]
337+
{
338+
v2_parser::try_parse(v2_parser::padded_node, s)
339+
}
340+
#[cfg(feature = "v1-fallback")]
341+
{
342+
v2_parser::try_parse(v2_parser::padded_node, s)
343+
.or_else(|e| KdlNode::parse_v1(s).map_err(|_| e))
344+
}
345+
}
346+
347+
/// Parses a KDL v1 string into a document.
348+
#[cfg(feature = "v1")]
349+
pub fn parse_v1(s: &str) -> Result<Self, KdlParseFailure> {
350+
let ret: Result<kdlv1::KdlNode, kdlv1::KdlError> = s.parse();
351+
ret.map(|x| x.into()).map_err(|e| e.into())
352+
}
353+
}
354+
355+
#[cfg(feature = "v1")]
356+
impl From<kdlv1::KdlNode> for KdlNode {
357+
fn from(value: kdlv1::KdlNode) -> Self {
358+
KdlNode {
359+
ty: value.ty().map(|x| x.clone().into()),
360+
name: value.name().clone().into(),
361+
entries: value.entries().iter().map(|x| x.clone().into()).collect(),
362+
children: value.children().map(|x| x.clone().into()),
363+
format: Some(KdlNodeFormat {
364+
leading: value.leading().unwrap_or("").into(),
365+
before_ty_name: "".into(),
366+
after_ty_name: "".into(),
367+
after_ty: "".into(),
368+
before_children: value.before_children().unwrap_or("").into(),
369+
before_terminator: "".into(),
370+
terminator: "".into(),
371+
trailing: value.trailing().unwrap_or("").into(),
372+
}),
373+
#[cfg(feature = "span")]
374+
span: SourceSpan::new(value.span().offset().into(), value.span().len()),
375+
}
376+
}
328377
}
329378

330379
// Query language

src/value.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,23 @@ where
261261
}
262262
}
263263

264+
#[cfg(feature = "v1")]
265+
impl From<kdlv1::KdlValue> for KdlValue {
266+
fn from(value: kdlv1::KdlValue) -> Self {
267+
match value {
268+
kdlv1::KdlValue::RawString(s) => KdlValue::String(s),
269+
kdlv1::KdlValue::String(s) => KdlValue::String(s),
270+
kdlv1::KdlValue::Base2(i) => KdlValue::Integer(i.into()),
271+
kdlv1::KdlValue::Base8(i) => KdlValue::Integer(i.into()),
272+
kdlv1::KdlValue::Base10(i) => KdlValue::Integer(i.into()),
273+
kdlv1::KdlValue::Base10Float(f) => KdlValue::Float(f),
274+
kdlv1::KdlValue::Base16(i) => KdlValue::Integer(i.into()),
275+
kdlv1::KdlValue::Bool(b) => KdlValue::Bool(b),
276+
kdlv1::KdlValue::Null => KdlValue::Null,
277+
}
278+
}
279+
}
280+
264281
#[cfg(test)]
265282
mod test {
266283
use super::*;

0 commit comments

Comments
 (0)