-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial data model for inline elements (#38)
- Loading branch information
Showing
9 changed files
with
306 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
use nom::{multi::many1, IResult}; | ||
|
||
use crate::{ | ||
primitives::{non_empty_line, trim_input_for_rem}, | ||
HasSpan, Span, | ||
}; | ||
|
||
/// An inline element is a phrase (i.e., span of content) within a block element | ||
/// or one of its attributes in an AsciiDoc document. | ||
#[derive(Clone, Debug, Eq, PartialEq)] | ||
#[non_exhaustive] | ||
pub enum Inline<'a> { | ||
/// Uninterpreted text (i.e., plain text) is text (character data) for which | ||
/// all inline grammar rules fail to match. | ||
Uninterpreted(Span<'a>), | ||
|
||
/// A sequence of other inline blocks. | ||
Sequence(Vec<Self>, Span<'a>), | ||
} | ||
|
||
impl<'a> Inline<'a> { | ||
/// Parse a span (typically a line) of any type and return an `Inline` that | ||
/// describes it. | ||
#[allow(dead_code)] | ||
pub(crate) fn parse(i: Span<'a>) -> IResult<Span, Self> { | ||
// TEMPORARY: Naive approach ... everything is a plain span. | ||
// Assuming for now that it's a line. | ||
|
||
let (rem, span) = non_empty_line(i)?; | ||
Ok((rem, Self::Uninterpreted(span))) | ||
} | ||
|
||
/// Parse a sequence of non-empty lines as a single `Inline` that | ||
/// describes it. | ||
#[allow(dead_code)] | ||
pub(crate) fn parse_lines(i: Span<'a>) -> IResult<Span, Self> { | ||
let (rem, first_line) = Self::parse(i)?; | ||
|
||
if let Ok((rem2, mut more_inlines)) = many1(Self::parse)(rem) { | ||
more_inlines.insert(0, first_line); | ||
|
||
let source = trim_input_for_rem(i, rem2); | ||
Ok((rem2, Self::Sequence(more_inlines, source))) | ||
} else { | ||
Ok((rem, first_line)) | ||
} | ||
} | ||
} | ||
|
||
impl<'a> HasSpan<'a> for Inline<'a> { | ||
fn span(&'a self) -> &'a Span<'a> { | ||
match self { | ||
Self::Uninterpreted(i) => i, | ||
Self::Sequence(_, i) => i, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
//! An inline element is a phrase (i.e., span of content) within a block element | ||
//! or one of its attributes in an AsciiDoc document. | ||
|
||
mod inline; | ||
pub use inline::Inline; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
use crate::{inlines::Inline, tests::fixtures::span::TSpan}; | ||
|
||
#[derive(Debug, Eq, PartialEq)] | ||
pub(crate) enum TInline { | ||
Uninterpreted(TSpan), | ||
Sequence(Vec<Self>, TSpan), | ||
} | ||
|
||
impl<'a> PartialEq<Inline<'a>> for TInline { | ||
fn eq(&self, other: &Inline<'a>) -> bool { | ||
tinline_eq(self, other) | ||
} | ||
} | ||
|
||
impl<'a> PartialEq<TInline> for Inline<'a> { | ||
fn eq(&self, other: &TInline) -> bool { | ||
tinline_eq(other, self) | ||
} | ||
} | ||
|
||
fn tinline_eq(tinline: &TInline, inline: &Inline) -> bool { | ||
match tinline { | ||
TInline::Uninterpreted(ref tspan) => match inline { | ||
Inline::Uninterpreted(ref span) => tspan == span, | ||
_ => false, | ||
}, | ||
|
||
TInline::Sequence(ref tinlines, ref tspan) => match inline { | ||
Inline::Sequence(ref inlines, ref span) => { | ||
if tinlines.len() != inlines.len() { | ||
return false; | ||
} | ||
|
||
for (tinline, inline) in tinlines.iter().zip(inlines.iter()) { | ||
if tinline != inline { | ||
return false; | ||
} | ||
} | ||
|
||
tspan == span | ||
} | ||
_ => false, | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
mod inline; | ||
pub(crate) use inline::TInline; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
mod uninterpreted { | ||
use nom::{ | ||
error::{Error, ErrorKind}, | ||
Err, | ||
}; | ||
use pretty_assertions_sorted::assert_eq; | ||
|
||
use crate::{ | ||
inlines::Inline, | ||
tests::fixtures::{inlines::TInline, TSpan}, | ||
HasSpan, Span, | ||
}; | ||
|
||
#[test] | ||
fn impl_clone() { | ||
// Silly test to mark the #[derive(...)] line as covered. | ||
let (_, b1) = Inline::parse(Span::new("abc", true)).unwrap(); | ||
let b2 = b1.clone(); | ||
assert_eq!(b1, b2); | ||
} | ||
|
||
#[test] | ||
fn empty_source() { | ||
let expected_err = Err::Error(Error::new(Span::new("", true), ErrorKind::TakeTill1)); | ||
|
||
let actual_err = Inline::parse(Span::new("", true)).unwrap_err(); | ||
|
||
assert_eq!(expected_err, actual_err); | ||
} | ||
|
||
#[test] | ||
fn only_spaces() { | ||
let expected_err = Err::Error(Error::new(Span::new(" ", true), ErrorKind::TakeTill1)); | ||
|
||
let actual_err = Inline::parse(Span::new(" ", true)).unwrap_err(); | ||
|
||
assert_eq!(expected_err, actual_err); | ||
} | ||
|
||
#[test] | ||
fn simple_line() { | ||
let (rem, inline) = Inline::parse(Span::new("abc", true)).unwrap(); | ||
|
||
assert_eq!( | ||
rem, | ||
TSpan { | ||
data: "", | ||
line: 1, | ||
col: 4, | ||
offset: 3 | ||
} | ||
); | ||
|
||
assert_eq!( | ||
inline, | ||
TInline::Uninterpreted(TSpan { | ||
data: "abc", | ||
line: 1, | ||
col: 1, | ||
offset: 0 | ||
}) | ||
); | ||
|
||
assert_eq!( | ||
inline.span(), | ||
TSpan { | ||
data: "abc", | ||
line: 1, | ||
col: 1, | ||
offset: 0, | ||
} | ||
); | ||
} | ||
} | ||
|
||
mod parse_lines { | ||
use nom::{ | ||
error::{Error, ErrorKind}, | ||
Err, | ||
}; | ||
use pretty_assertions_sorted::assert_eq; | ||
|
||
use crate::{ | ||
inlines::Inline, | ||
tests::fixtures::{inlines::TInline, TSpan}, | ||
HasSpan, Span, | ||
}; | ||
|
||
#[test] | ||
fn empty_source() { | ||
let expected_err = Err::Error(Error::new(Span::new("", true), ErrorKind::TakeTill1)); | ||
|
||
let actual_err = Inline::parse_lines(Span::new("", true)).unwrap_err(); | ||
|
||
assert_eq!(expected_err, actual_err); | ||
} | ||
|
||
#[test] | ||
fn only_spaces() { | ||
let expected_err = Err::Error(Error::new(Span::new(" ", true), ErrorKind::TakeTill1)); | ||
|
||
let actual_err = Inline::parse_lines(Span::new(" ", true)).unwrap_err(); | ||
|
||
assert_eq!(expected_err, actual_err); | ||
} | ||
|
||
#[test] | ||
fn simple_line() { | ||
let (rem, inline) = Inline::parse_lines(Span::new("abc", true)).unwrap(); | ||
|
||
assert_eq!( | ||
rem, | ||
TSpan { | ||
data: "", | ||
line: 1, | ||
col: 4, | ||
offset: 3 | ||
} | ||
); | ||
|
||
assert_eq!( | ||
inline, | ||
TInline::Uninterpreted(TSpan { | ||
data: "abc", | ||
line: 1, | ||
col: 1, | ||
offset: 0 | ||
}) | ||
); | ||
|
||
assert_eq!( | ||
inline.span(), | ||
TSpan { | ||
data: "abc", | ||
line: 1, | ||
col: 1, | ||
offset: 0, | ||
} | ||
); | ||
} | ||
|
||
#[test] | ||
fn two_lines() { | ||
let (rem, inline) = Inline::parse_lines(Span::new("abc\ndef", true)).unwrap(); | ||
|
||
assert_eq!( | ||
rem, | ||
TSpan { | ||
data: "", | ||
line: 2, | ||
col: 4, | ||
offset: 7 | ||
} | ||
); | ||
|
||
assert_eq!( | ||
inline, | ||
TInline::Sequence( | ||
vec!( | ||
TInline::Uninterpreted(TSpan { | ||
data: "abc", | ||
line: 1, | ||
col: 1, | ||
offset: 0 | ||
}), | ||
TInline::Uninterpreted(TSpan { | ||
data: "def", | ||
line: 2, | ||
col: 1, | ||
offset: 4 | ||
}) | ||
), | ||
TSpan { | ||
data: "abc\ndef", | ||
line: 1, | ||
col: 1, | ||
offset: 0, | ||
} | ||
) | ||
); | ||
|
||
assert_eq!( | ||
inline.span(), | ||
TSpan { | ||
data: "abc\ndef", | ||
line: 1, | ||
col: 1, | ||
offset: 0, | ||
} | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
mod inline; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,5 +10,6 @@ mod blocks; | |
mod document; | ||
mod error; | ||
pub(crate) mod fixtures; | ||
mod inlines; | ||
mod primitives; | ||
mod strings; |