refactor: clean up parser/FromStr toplevel stuff and add one for KdlIdentifier

This commit is contained in:
Kat Marchán 2022-04-22 21:29:37 -07:00
parent 8ed6a5cd06
commit a1555949ed
5 changed files with 46 additions and 86 deletions

View File

@ -1,8 +1,6 @@
use std::{fmt::Display, str::FromStr}; use std::{fmt::Display, str::FromStr};
use nom::{combinator::all_consuming, Finish}; use crate::{parser, KdlError, KdlNode, KdlValue};
use crate::{parser::document, KdlError, KdlErrorKind, KdlNode, KdlValue};
/// Represents a KDL /// Represents a KDL
/// [`Document`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#document). /// [`Document`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#document).
@ -13,7 +11,6 @@ use crate::{parser::document, KdlError, KdlErrorKind, KdlNode, KdlValue};
#[derive(Debug, Default, Clone, PartialEq)] #[derive(Debug, Default, Clone, PartialEq)]
pub struct KdlDocument { pub struct KdlDocument {
pub(crate) leading: Option<String>, pub(crate) leading: Option<String>,
// TODO: Consider using `hashlink` for this, later?
pub(crate) nodes: Vec<KdlNode>, pub(crate) nodes: Vec<KdlNode>,
pub(crate) trailing: Option<String>, pub(crate) trailing: Option<String>,
} }
@ -209,34 +206,11 @@ impl IntoIterator for KdlDocument {
} }
} }
impl KdlDocument {
/// Parse a KDL document from a string into a [`KdlDocument`] object model.
fn parse(input: &str) -> Result<KdlDocument, KdlError> {
all_consuming(document)(input)
.finish()
.map(|(_, arg)| arg)
.map_err(|e| {
let prefix = &input[..(input.len() - e.input.len())];
KdlError {
input: input.into(),
offset: prefix.chars().count(),
kind: if let Some(kind) = e.kind {
kind
} else if let Some(ctx) = e.context {
KdlErrorKind::Context(ctx)
} else {
KdlErrorKind::Other
},
}
})
}
}
impl FromStr for KdlDocument { impl FromStr for KdlDocument {
type Err = KdlError; type Err = KdlError;
fn from_str(input: &str) -> Result<Self, Self::Err> { fn from_str(input: &str) -> Result<Self, Self::Err> {
KdlDocument::parse(input) parser::parse(input, parser::document)
} }
} }

View File

@ -1,8 +1,6 @@
use std::{fmt::Display, str::FromStr}; use std::{fmt::Display, str::FromStr};
use nom::{combinator::all_consuming, Finish}; use crate::{parser, KdlError, KdlIdentifier, KdlValue};
use crate::{KdlError, KdlErrorKind, KdlIdentifier, KdlValue};
/// KDL Entries are the "arguments" to KDL nodes: either a (positional) /// KDL Entries are the "arguments" to KDL nodes: either a (positional)
/// [`Argument`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#argument) or /// [`Argument`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#argument) or
@ -149,32 +147,10 @@ impl FromStr for KdlEntry {
type Err = KdlError; type Err = KdlError;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
KdlEntry::parse(s) parser::parse(s, parser::entry)
} }
} }
impl KdlEntry {
/// Parse a KDL document from a string into a [`KdlDocument`] object model.
fn parse(input: &str) -> Result<KdlEntry, KdlError> {
all_consuming(crate::parser::entry)(input)
.finish()
.map(|(_, arg)| arg)
.map_err(|e| {
let prefix = &input[..(input.len() - e.input.len())];
KdlError {
input: input.into(),
offset: prefix.chars().count(),
kind: if let Some(kind) = e.kind {
kind
} else if let Some(ctx) = e.context {
KdlErrorKind::Context(ctx)
} else {
KdlErrorKind::Other
},
}
})
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View File

@ -1,4 +1,6 @@
use std::fmt::Display; use std::{fmt::Display, str::FromStr};
use crate::{parser, KdlError};
/// Represents a KDL /// Represents a KDL
/// [Identifier](https://github.com/kdl-org/kdl/blob/main/SPEC.md#identifier). /// [Identifier](https://github.com/kdl-org/kdl/blob/main/SPEC.md#identifier).
@ -139,6 +141,14 @@ impl From<KdlIdentifier> for String {
} }
} }
impl FromStr for KdlIdentifier {
type Err = KdlError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
parser::parse(s, parser::identifier)
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View File

@ -4,9 +4,7 @@ use std::{
str::FromStr, str::FromStr,
}; };
use nom::{combinator::all_consuming, Finish}; use crate::{parser, KdlDocument, KdlEntry, KdlError, KdlIdentifier, KdlValue};
use crate::{KdlDocument, KdlEntry, KdlError, KdlErrorKind, KdlIdentifier, KdlValue};
/// Represents an individual KDL /// Represents an individual KDL
/// [`Node`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#node) inside a /// [`Node`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#node) inside a
@ -393,34 +391,11 @@ impl IndexMut<&str> for KdlNode {
} }
} }
impl KdlNode {
/// Parse a KDL document from a string into a [`KdlDocument`] object model.
fn parse(input: &str) -> Result<KdlNode, KdlError> {
all_consuming(crate::parser::node)(input)
.finish()
.map(|(_, arg)| arg)
.map_err(|e| {
let prefix = &input[..(input.len() - e.input.len())];
KdlError {
input: input.into(),
offset: prefix.chars().count(),
kind: if let Some(kind) = e.kind {
kind
} else if let Some(ctx) = e.context {
KdlErrorKind::Context(ctx)
} else {
KdlErrorKind::Other
},
}
})
}
}
impl FromStr for KdlNode { impl FromStr for KdlNode {
type Err = KdlError; type Err = KdlError;
fn from_str(input: &str) -> Result<Self, Self::Err> { fn from_str(input: &str) -> Result<Self, Self::Err> {
KdlNode::parse(input) parser::parse(input, parser::node)
} }
} }

View File

@ -4,12 +4,37 @@ use crate::nom_compat::{many0, many1, many_till};
use nom::branch::alt; use nom::branch::alt;
use nom::bytes::complete::{tag, take_until, take_until1, take_while, take_while_m_n}; use nom::bytes::complete::{tag, take_until, take_until1, take_while, take_while_m_n};
use nom::character::complete::{anychar, char, none_of, one_of}; use nom::character::complete::{anychar, char, none_of, one_of};
use nom::combinator::{cut, eof, map, map_opt, map_res, opt, recognize}; use nom::combinator::{all_consuming, cut, eof, map, map_opt, map_res, opt, recognize};
use nom::error::{context, ParseError}; use nom::error::{context, ParseError};
use nom::sequence::{delimited, preceded, terminated, tuple}; use nom::sequence::{delimited, preceded, terminated, tuple};
use nom::{IResult, Offset, Parser, Slice}; use nom::{Finish, IResult, Offset, Parser, Slice};
use crate::{KdlDocument, KdlEntry, KdlIdentifier, KdlNode, KdlParseError, KdlValue}; use crate::{
KdlDocument, KdlEntry, KdlError, KdlErrorKind, KdlIdentifier, KdlNode, KdlParseError, KdlValue,
};
pub(crate) fn parse<'a, T, P>(input: &'a str, parser: P) -> Result<T, KdlError>
where
P: Parser<&'a str, T, KdlParseError<&'a str>>,
{
all_consuming(parser)(input)
.finish()
.map(|(_, arg)| arg)
.map_err(|e| {
let prefix = &input[..(input.len() - e.input.len())];
KdlError {
input: input.into(),
offset: prefix.chars().count(),
kind: if let Some(kind) = e.kind {
kind
} else if let Some(ctx) = e.context {
KdlErrorKind::Context(ctx)
} else {
KdlErrorKind::Other
},
}
})
}
pub(crate) fn document(input: &str) -> IResult<&str, KdlDocument, KdlParseError<&str>> { pub(crate) fn document(input: &str) -> IResult<&str, KdlDocument, KdlParseError<&str>> {
let (input, nodes) = many0(node)(input)?; let (input, nodes) = many0(node)(input)?;
@ -51,7 +76,7 @@ pub(crate) fn node(input: &str) -> IResult<&str, KdlNode, KdlParseError<&str>> {
Ok((input, node)) Ok((input, node))
} }
fn identifier(input: &str) -> IResult<&str, KdlIdentifier, KdlParseError<&str>> { pub(crate) fn identifier(input: &str) -> IResult<&str, KdlIdentifier, KdlParseError<&str>> {
alt((plain_identifier, quoted_identifier))(input) alt((plain_identifier, quoted_identifier))(input)
} }