Skip to content

Commit

Permalink
feat(parser): Improve tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
epage committed Jul 10, 2023
1 parent dde0404 commit 3543ab5
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 256 deletions.
5 changes: 3 additions & 2 deletions crates/toml_edit/src/parser/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use winnow::combinator::cut_err;
use winnow::combinator::delimited;
use winnow::combinator::opt;
use winnow::combinator::separated1;
use winnow::trace::trace;

use crate::parser::trivia::ws_comment_newline;
use crate::parser::value::value;
Expand All @@ -13,7 +14,7 @@ use crate::parser::prelude::*;

// array = array-open array-values array-close
pub(crate) fn array<'i>(check: RecursionCheck) -> impl Parser<Input<'i>, Array, ContextError<'i>> {
move |input| {
trace("array", move |input| {
delimited(
ARRAY_OPEN,
cut_err(array_values(check)),
Expand All @@ -22,7 +23,7 @@ pub(crate) fn array<'i>(check: RecursionCheck) -> impl Parser<Input<'i>, Array,
.context(StrContext::Expected(StrContextValue::CharLiteral(']'))),
)
.parse_next(input)
}
})
}

// note: we're omitting ws and newlines here, because
Expand Down
123 changes: 68 additions & 55 deletions crates/toml_edit/src/parser/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use winnow::combinator::opt;
use winnow::combinator::preceded;
use winnow::token::one_of;
use winnow::token::take_while;
use winnow::trace::trace;

// ;; Date and Time (as defined in RFC 3339)

Expand All @@ -21,76 +22,88 @@ use winnow::token::take_while;
// local-time = partial-time
// full-time = partial-time time-offset
pub(crate) fn date_time(input: Input<'_>) -> IResult<Input<'_>, Datetime, ContextError<'_>> {
alt((
(full_date, opt((time_delim, partial_time, opt(time_offset))))
.map(|(date, opt)| {
match opt {
// Offset Date-Time
Some((_, time, offset)) => Datetime {
date: Some(date),
time: Some(time),
offset,
},
// Local Date
None => Datetime {
date: Some(date),
time: None,
offset: None,
},
}
})
.context(StrContext::Label("date-time")),
partial_time
.map(|t| t.into())
.context(StrContext::Label("time")),
))
trace(
"date-time",
alt((
(full_date, opt((time_delim, partial_time, opt(time_offset))))
.map(|(date, opt)| {
match opt {
// Offset Date-Time
Some((_, time, offset)) => Datetime {
date: Some(date),
time: Some(time),
offset,
},
// Local Date
None => Datetime {
date: Some(date),
time: None,
offset: None,
},
}
})
.context(StrContext::Label("date-time")),
partial_time
.map(|t| t.into())
.context(StrContext::Label("time")),
)),
)
.parse_next(input)
}

// full-date = date-fullyear "-" date-month "-" date-mday
pub(crate) fn full_date(input: Input<'_>) -> IResult<Input<'_>, Date, ContextError<'_>> {
(date_fullyear, b'-', cut_err((date_month, b'-', date_mday)))
.map(|(year, _, (month, _, day))| Date { year, month, day })
.parse_next(input)
trace(
"full-date",
(date_fullyear, b'-', cut_err((date_month, b'-', date_mday)))
.map(|(year, _, (month, _, day))| Date { year, month, day }),
)
.parse_next(input)
}

// partial-time = time-hour ":" time-minute ":" time-second [time-secfrac]
pub(crate) fn partial_time(input: Input<'_>) -> IResult<Input<'_>, Time, ContextError<'_>> {
(
time_hour,
b':',
cut_err((time_minute, b':', time_second, opt(time_secfrac))),
trace(
"partial-time",
(
time_hour,
b':',
cut_err((time_minute, b':', time_second, opt(time_secfrac))),
)
.map(|(hour, _, (minute, _, second, nanosecond))| Time {
hour,
minute,
second,
nanosecond: nanosecond.unwrap_or_default(),
}),
)
.map(|(hour, _, (minute, _, second, nanosecond))| Time {
hour,
minute,
second,
nanosecond: nanosecond.unwrap_or_default(),
})
.parse_next(input)
.parse_next(input)
}

// time-offset = "Z" / time-numoffset
// time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
pub(crate) fn time_offset(input: Input<'_>) -> IResult<Input<'_>, Offset, ContextError<'_>> {
alt((
one_of((b'Z', b'z')).value(Offset::Z),
(
one_of((b'+', b'-')),
cut_err((time_hour, b':', time_minute)),
)
.map(|(sign, (hours, _, minutes))| {
let sign = match sign {
b'+' => 1,
b'-' => -1,
_ => unreachable!("Parser prevents this"),
};
sign * (hours as i16 * 60 + minutes as i16)
})
.verify(|minutes| ((-24 * 60)..=(24 * 60)).contains(minutes))
.map(|minutes| Offset::Custom { minutes }),
))
.context(StrContext::Label("time offset"))
trace(
"time-offset",
alt((
one_of((b'Z', b'z')).value(Offset::Z),
(
one_of((b'+', b'-')),
cut_err((time_hour, b':', time_minute)),
)
.map(|(sign, (hours, _, minutes))| {
let sign = match sign {
b'+' => 1,
b'-' => -1,
_ => unreachable!("Parser prevents this"),
};
sign * (hours as i16 * 60 + minutes as i16)
})
.verify(|minutes| ((-24 * 60)..=(24 * 60)).contains(minutes))
.map(|minutes| Offset::Custom { minutes }),
))
.context(StrContext::Label("time offset")),
)
.parse_next(input)
}

Expand Down
66 changes: 35 additions & 31 deletions crates/toml_edit/src/parser/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use winnow::combinator::peek;
use winnow::combinator::repeat;
use winnow::token::any;
use winnow::token::one_of;
use winnow::trace::trace;

use crate::document::Document;
use crate::key::Key;
Expand Down Expand Up @@ -108,36 +109,39 @@ pub(crate) fn keyval<'s, 'i>(
pub(crate) fn parse_keyval(
input: Input<'_>,
) -> IResult<Input<'_>, (Vec<Key>, TableKeyValue), ContextError<'_>> {
(
key,
cut_err((
one_of(KEYVAL_SEP)
.context(StrContext::Expected(StrContextValue::CharLiteral('.')))
.context(StrContext::Expected(StrContextValue::CharLiteral('='))),
(
ws.span(),
value(RecursionCheck::default()),
line_trailing
.context(StrContext::Expected(StrContextValue::CharLiteral('\n')))
.context(StrContext::Expected(StrContextValue::CharLiteral('#'))),
),
)),
)
.try_map::<_, _, std::str::Utf8Error>(|(key, (_, v))| {
let mut path = key;
let key = path.pop().expect("grammar ensures at least 1");
trace(
"keyval",
(
key,
cut_err((
one_of(KEYVAL_SEP)
.context(StrContext::Expected(StrContextValue::CharLiteral('.')))
.context(StrContext::Expected(StrContextValue::CharLiteral('='))),
(
ws.span(),
value(RecursionCheck::default()),
line_trailing
.context(StrContext::Expected(StrContextValue::CharLiteral('\n')))
.context(StrContext::Expected(StrContextValue::CharLiteral('#'))),
),
)),
)
.try_map::<_, _, std::str::Utf8Error>(|(key, (_, v))| {
let mut path = key;
let key = path.pop().expect("grammar ensures at least 1");

let (pre, v, suf) = v;
let pre = RawString::with_span(pre);
let suf = RawString::with_span(suf);
let v = v.decorated(pre, suf);
Ok((
path,
TableKeyValue {
key,
value: Item::Value(v),
},
))
})
.parse_next(input)
let (pre, v, suf) = v;
let pre = RawString::with_span(pre);
let suf = RawString::with_span(suf);
let v = v.decorated(pre, suf);
Ok((
path,
TableKeyValue {
key,
value: Item::Value(v),
},
))
}),
)
.parse_next(input)
}
5 changes: 3 additions & 2 deletions crates/toml_edit/src/parser/inline_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use winnow::combinator::cut_err;
use winnow::combinator::delimited;
use winnow::combinator::separated0;
use winnow::token::one_of;
use winnow::trace::trace;

use crate::key::Key;
use crate::parser::errors::CustomError;
Expand All @@ -20,7 +21,7 @@ use indexmap::map::Entry;
pub(crate) fn inline_table<'i>(
check: RecursionCheck,
) -> impl Parser<Input<'i>, InlineTable, ContextError<'i>> {
move |input| {
trace("inline-table", move |input| {
delimited(
INLINE_TABLE_OPEN,
cut_err(inline_table_keyvals(check).try_map(|(kv, p)| table_from_pairs(kv, p))),
Expand All @@ -29,7 +30,7 @@ pub(crate) fn inline_table<'i>(
.context(StrContext::Expected(StrContextValue::CharLiteral('}'))),
)
.parse_next(input)
}
})
}

fn table_from_pairs(
Expand Down
68 changes: 39 additions & 29 deletions crates/toml_edit/src/parser/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use winnow::combinator::peek;
use winnow::combinator::separated1;
use winnow::token::any;
use winnow::token::take_while;
use winnow::trace::trace;

use crate::key::Key;
use crate::parser::errors::CustomError;
Expand All @@ -17,23 +18,26 @@ use crate::RawString;
// key = simple-key / dotted-key
// dotted-key = simple-key 1*( dot-sep simple-key )
pub(crate) fn key(input: Input<'_>) -> IResult<Input<'_>, Vec<Key>, ContextError<'_>> {
separated1(
(ws.span(), simple_key, ws.span()).map(|(pre, (raw, key), suffix)| {
Key::new(key)
.with_repr_unchecked(Repr::new_unchecked(raw))
.with_decor(Decor::new(
RawString::with_span(pre),
RawString::with_span(suffix),
))
trace(
"dotted-key",
separated1(
(ws.span(), simple_key, ws.span()).map(|(pre, (raw, key), suffix)| {
Key::new(key)
.with_repr_unchecked(Repr::new_unchecked(raw))
.with_decor(Decor::new(
RawString::with_span(pre),
RawString::with_span(suffix),
))
}),
DOT_SEP,
)
.context(StrContext::Label("key"))
.try_map(|k: Vec<_>| {
// Inserting the key will require recursion down the line
RecursionCheck::check_depth(k.len())?;
Ok::<_, CustomError>(k)
}),
DOT_SEP,
)
.context(StrContext::Label("key"))
.try_map(|k: Vec<_>| {
// Inserting the key will require recursion down the line
RecursionCheck::check_depth(k.len())?;
Ok::<_, CustomError>(k)
})
.parse_next(input)
}

Expand All @@ -42,25 +46,31 @@ pub(crate) fn key(input: Input<'_>) -> IResult<Input<'_>, Vec<Key>, ContextError
pub(crate) fn simple_key(
input: Input<'_>,
) -> IResult<Input<'_>, (RawString, InternalString), ContextError<'_>> {
dispatch! {peek(any);
crate::parser::strings::QUOTATION_MARK => basic_string
.map(|s: std::borrow::Cow<'_, str>| s.as_ref().into()),
crate::parser::strings::APOSTROPHE => literal_string.map(|s: &str| s.into()),
_ => unquoted_key.map(|s: &str| s.into()),
}
.with_span()
.map(|(k, span)| {
let raw = RawString::with_span(span);
(raw, k)
})
trace(
"simple-key",
dispatch! {peek(any);
crate::parser::strings::QUOTATION_MARK => basic_string
.map(|s: std::borrow::Cow<'_, str>| s.as_ref().into()),
crate::parser::strings::APOSTROPHE => literal_string.map(|s: &str| s.into()),
_ => unquoted_key.map(|s: &str| s.into()),
}
.with_span()
.map(|(k, span)| {
let raw = RawString::with_span(span);
(raw, k)
}),
)
.parse_next(input)
}

// unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _
fn unquoted_key(input: Input<'_>) -> IResult<Input<'_>, &str, ContextError<'_>> {
take_while(1.., UNQUOTED_CHAR)
.map(|b| unsafe { from_utf8_unchecked(b, "`is_unquoted_char` filters out on-ASCII") })
.parse_next(input)
trace(
"unquoted-key",
take_while(1.., UNQUOTED_CHAR)
.map(|b| unsafe { from_utf8_unchecked(b, "`is_unquoted_char` filters out on-ASCII") }),
)
.parse_next(input)
}

pub(crate) fn is_unquoted_char(c: u8) -> bool {
Expand Down
Loading

0 comments on commit 3543ab5

Please sign in to comment.