Skip to content

Commit

Permalink
Add warnings from Block::parse
Browse files Browse the repository at this point in the history
  • Loading branch information
scouten committed Sep 16, 2024
1 parent 439cfab commit fbb65de
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 49 deletions.
55 changes: 35 additions & 20 deletions src/blocks/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
blocks::{ContentModel, IsBlock, MacroBlock, SectionBlock, SimpleBlock},
span::MatchedItem,
strings::CowStr,
warnings::{MatchAndWarnings, Warning},
HasSpan, Span,
};

Expand Down Expand Up @@ -40,43 +41,57 @@ impl<'src> Block<'src> {
/// Parse a block of any type and return a `Block` that describes it.
///
/// Consumes any blank lines before and after the block.
pub(crate) fn parse(source: Span<'src>) -> Option<MatchedItem<'src, Self>> {
pub(crate) fn parse(
source: Span<'src>,
) -> MatchAndWarnings<'src, Option<MatchedItem<'src, Self>>> {
let mut warnings: Vec<Warning<'src>> = vec![];
let source = source.discard_empty_lines();

// Try to discern the block type by scanning the first line.
let line = source.take_normalized_line();
if line.item.contains("::") {
let macro_block_maw = MacroBlock::parse(source);
if let Some(macro_block) = macro_block_maw.item {
if !macro_block_maw.warnings.is_empty() {
todo!("Propagate warnings up the chain");
}
let mut macro_block_maw = MacroBlock::parse(source);
if !macro_block_maw.warnings.is_empty() {
warnings.append(&mut macro_block_maw.warnings);

Check warning on line 55 in src/blocks/block.rs

View check run for this annotation

Codecov / codecov/patch

src/blocks/block.rs#L55

Added line #L55 was not covered by tests
}

return Some(MatchedItem {
item: Self::Macro(macro_block.item),
after: macro_block.after,
});
if let Some(macro_block) = macro_block_maw.item {
return MatchAndWarnings {
item: Some(MatchedItem {
item: Self::Macro(macro_block.item),
after: macro_block.after,
}),
warnings,
};
}

// A line containing `::` might be some other kind of block, so we
// don't automatically error out on a parse failure.
} else if line.item.starts_with('=') {
}

if line.item.starts_with('=') {
if let Some(section_block) = SectionBlock::parse(source) {
return Some(MatchedItem {
item: Self::Section(section_block.item),
after: section_block.after,
});
return MatchAndWarnings {
item: Some(MatchedItem {
item: Self::Section(section_block.item),
after: section_block.after,
}),
warnings,
};
}

// A line starting with `=` might be some other kind of block, so we
// don't automatically error out on a parse failure.
}

// If no other block kind matches, we can always use SimpleBlock.
SimpleBlock::parse(source).map(|mi| MatchedItem {
item: Self::Simple(mi.item),
after: mi.after,
})
// If no other block kind matches, we can always use SimpleBlock.]
MatchAndWarnings {
item: SimpleBlock::parse(source).map(|mi| MatchedItem {
item: Self::Simple(mi.item),
after: mi.after,
}),
warnings,
}
}
}

Expand Down
36 changes: 29 additions & 7 deletions src/blocks/parse_utils.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,51 @@
use crate::{blocks::Block, span::MatchedItem, Span};
use crate::{
blocks::Block,
span::MatchedItem,
warnings::{MatchAndWarnings, Warning},
Span,
};

/// Parse blocks until end of input or a pre-determined stop condition is
/// reached.
pub(crate) fn parse_blocks_until<'src, F>(
mut source: Span<'src>,
f: F,
) -> Option<MatchedItem<'src, Vec<Block<'src>>>>
) -> MatchAndWarnings<'src, Option<MatchedItem<'src, Vec<Block<'src>>>>>
where
F: Fn(&Span<'src>) -> bool,
{
let mut blocks: Vec<Block<'src>> = vec![];
let mut warnings: Vec<Warning<'src>> = vec![];

source = source.discard_empty_lines();

while !source.data().is_empty() {
if f(&source) {
break;
}

let mi = Block::parse(source)?;
let mut maw = Block::parse(source);

if !maw.warnings.is_empty() {
warnings.append(&mut maw.warnings);

Check warning on line 30 in src/blocks/parse_utils.rs

View check run for this annotation

Codecov / codecov/patch

src/blocks/parse_utils.rs#L30

Added line #L30 was not covered by tests
}

let Some(mi) = maw.item else {
return MatchAndWarnings {
item: None,
warnings,
};

Check warning on line 37 in src/blocks/parse_utils.rs

View check run for this annotation

Codecov / codecov/patch

src/blocks/parse_utils.rs#L34-L37

Added lines #L34 - L37 were not covered by tests
};

source = mi.after;
blocks.push(mi.item);
}

Some(MatchedItem {
item: blocks,
after: source,
})
MatchAndWarnings {
item: Some(MatchedItem {
item: blocks,
after: source,
}),
warnings,
}
}
10 changes: 8 additions & 2 deletions src/blocks/section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,14 @@ impl<'src> SectionBlock<'src> {
pub(crate) fn parse(source: Span<'src>) -> Option<MatchedItem<'src, Self>> {
let source = source.discard_empty_lines();
let level = parse_title_line(source)?;
let blocks =
parse_blocks_until(level.after, |i| peer_or_ancestor_section(*i, level.item.0))?;
let maw_blocks =
parse_blocks_until(level.after, |i| peer_or_ancestor_section(*i, level.item.0));

if !maw_blocks.warnings.is_empty() {
todo!("Propagate warnings up the chain");

Check warning on line 33 in src/blocks/section.rs

View check run for this annotation

Codecov / codecov/patch

src/blocks/section.rs#L33

Added line #L33 was not covered by tests
}

let blocks = maw_blocks.item?;
let source = source.trim_remainder(blocks.after);

Some(MatchedItem {
Expand Down
8 changes: 7 additions & 1 deletion src/document/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ impl<'src> Document<'src> {
(i, None)
};

let blocks = parse_blocks_until(i, |_| false)?;
let maw_blocks = parse_blocks_until(i, |_| false);

if !maw_blocks.warnings.is_empty() {
todo!("Retain warnings");

Check warning on line 61 in src/document/document.rs

View check run for this annotation

Codecov / codecov/patch

src/document/document.rs#L61

Added line #L61 was not covered by tests
}

let blocks = maw_blocks.item?;

Some(Self {
header,
Expand Down
13 changes: 10 additions & 3 deletions src/tests/asciidoc_lang/blocks/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ mod content_model {
// simple:: a block that's treated as contiguous lines of paragraph text (and
// subject to normal substitutions) (e.g., a paragraph block)

let block = Block::parse(Span::new("abc")).unwrap();
let block = Block::parse(Span::new("abc"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(block.item.content_model(), ContentModel::Simple);
}

Expand Down Expand Up @@ -159,7 +162,9 @@ mod context {
// distinguishes one kind of block from another. You can think of the context as
// the block's type.

let mi = Block::parse(Span::new("== Section Title\n\nContent of section.")).unwrap();
let mi = Block::parse(Span::new("== Section Title\n\nContent of section."))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(mi.item.context().deref(), "section");
}
Expand Down Expand Up @@ -195,7 +200,9 @@ mod context {
// For example, all sections implicitly have the compound content model
// because a section may only contain other blocks.

let mi = Block::parse(Span::new("== Section Title\n\nContent of section.")).unwrap();
let mi = Block::parse(Span::new("== Section Title\n\nContent of section."))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(mi.item.content_model(), ContentModel::Compound);
}
Expand Down
65 changes: 49 additions & 16 deletions src/tests/blocks/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,33 @@ mod simple {
#[test]
fn impl_clone() {
// Silly test to mark the #[derive(...)] line as covered.
let b1 = Block::parse(Span::new("abc")).unwrap();
let b1 = Block::parse(Span::new("abc"))
.unwrap_if_no_warnings()
.unwrap();

let b2 = b1.item.clone();
assert_eq!(b1.item, b2);
}

#[test]
fn err_empty_source() {
assert!(Block::parse(Span::new("")).is_none());
assert!(Block::parse(Span::new(""))
.unwrap_if_no_warnings()
.is_none());
}

#[test]
fn err_only_spaces() {
assert!(Block::parse(Span::new(" ")).is_none());
assert!(Block::parse(Span::new(" "))
.unwrap_if_no_warnings()
.is_none());
}

#[test]
fn single_line() {
let mi = Block::parse(Span::new("abc")).unwrap();
let mi = Block::parse(Span::new("abc"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(
mi.item,
Expand Down Expand Up @@ -72,7 +81,9 @@ mod simple {

#[test]
fn multiple_lines() {
let mi = Block::parse(Span::new("abc\ndef")).unwrap();
let mi = Block::parse(Span::new("abc\ndef"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(
mi.item,
Expand Down Expand Up @@ -123,7 +134,9 @@ mod simple {

#[test]
fn consumes_blank_lines_after() {
let mi = Block::parse(Span::new("abc\n\ndef")).unwrap();
let mi = Block::parse(Span::new("abc\n\ndef"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(
mi.item,
Expand Down Expand Up @@ -178,7 +191,9 @@ mod r#macro {

#[test]
fn err_inline_syntax() {
let mi = Block::parse(Span::new("foo:bar[]")).unwrap();
let mi = Block::parse(Span::new("foo:bar[]"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(
mi.item,
Expand Down Expand Up @@ -228,7 +243,9 @@ mod r#macro {

#[test]
fn err_no_attr_list() {
let mi = Block::parse(Span::new("foo::bar")).unwrap();
let mi = Block::parse(Span::new("foo::bar"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(
mi.item,
Expand Down Expand Up @@ -263,7 +280,9 @@ mod r#macro {

#[test]
fn err_attr_list_not_closed() {
let mi = Block::parse(Span::new("foo::bar[blah")).unwrap();
let mi = Block::parse(Span::new("foo::bar[blah"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(
mi.item,
Expand Down Expand Up @@ -298,7 +317,9 @@ mod r#macro {

#[test]
fn err_unexpected_after_attr_list() {
let mi = Block::parse(Span::new("foo::bar[blah]bonus")).unwrap();
let mi = Block::parse(Span::new("foo::bar[blah]bonus"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(
mi.item,
Expand Down Expand Up @@ -369,7 +390,9 @@ mod r#macro {

#[test]
fn simplest_block_macro() {
let mi = Block::parse(Span::new("foo::[]")).unwrap();
let mi = Block::parse(Span::new("foo::[]"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(
mi.item,
Expand Down Expand Up @@ -426,7 +449,9 @@ mod r#macro {

#[test]
fn has_target() {
let mi = Block::parse(Span::new("foo::bar[]")).unwrap();
let mi = Block::parse(Span::new("foo::bar[]"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(
mi.item,
Expand Down Expand Up @@ -484,7 +509,9 @@ mod r#macro {

#[test]
fn has_target_and_attrlist() {
let mi = Block::parse(Span::new("foo::bar[blah]")).unwrap();
let mi = Block::parse(Span::new("foo::bar[blah]"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(
mi.item,
Expand Down Expand Up @@ -578,7 +605,9 @@ mod section {

#[test]
fn err_missing_space_before_title() {
let mi = Block::parse(Span::new("=blah blah")).unwrap();
let mi = Block::parse(Span::new("=blah blah"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(
mi.item,
Expand Down Expand Up @@ -613,7 +642,9 @@ mod section {

#[test]
fn simplest_section_block() {
let mi = Block::parse(Span::new("== Section Title")).unwrap();
let mi = Block::parse(Span::new("== Section Title"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(mi.item.content_model(), ContentModel::Compound);
assert_eq!(mi.item.context().deref(), "section");
Expand Down Expand Up @@ -653,7 +684,9 @@ mod section {

#[test]
fn has_child_block() {
let mi = Block::parse(Span::new("== Section Title\n\nabc")).unwrap();
let mi = Block::parse(Span::new("== Section Title\n\nabc"))
.unwrap_if_no_warnings()
.unwrap();

assert_eq!(mi.item.content_model(), ContentModel::Compound);
assert_eq!(mi.item.context().deref(), "section");
Expand Down

0 comments on commit fbb65de

Please sign in to comment.