Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split preamble parsing into its own crate #89

Merged
merged 1 commit into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = [ "eipw-lint", "eipw-lint-js" ]
members = [ "eipw-preamble", "eipw-lint", "eipw-lint-js" ]

[package]
name = "eipw"
Expand Down
1 change: 1 addition & 0 deletions eipw-lint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ description = "library of lints for eipw, the Ethereum Improvement Proposal vali
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
eipw-preamble = { version = "0.1.0", path = "../eipw-preamble" }
comrak = { version = "0.18.0", default-features = false }
annotate-snippets = "0.9.1"
snafu = "0.7.4"
Expand Down
9 changes: 4 additions & 5 deletions eipw-lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
pub mod fetch;
pub mod lints;
pub mod modifiers;
pub mod preamble;
pub mod reporters;
pub mod tree;

Expand All @@ -19,11 +18,12 @@ use comrak::{Arena, ComrakExtensionOptions, ComrakOptions};

use crate::lints::{Context, DefaultLint, Error as LintError, FetchContext, InnerContext, Lint};
use crate::modifiers::{DefaultModifier, Modifier};
use crate::preamble::Preamble;
use crate::reporters::Reporter;

use educe::Educe;

use eipw_preamble::{Preamble, SplitError};

use serde::{Deserialize, Serialize};

use snafu::{ensure, ResultExt, Snafu};
Expand Down Expand Up @@ -871,8 +871,7 @@ fn process<'a>(
) -> Result<Option<InnerContext<'a>>, Error> {
let (preamble_source, body_source) = match Preamble::split(source) {
Ok(v) => v,
Err(preamble::SplitError::MissingStart { .. })
| Err(preamble::SplitError::LeadingGarbage { .. }) => {
Err(SplitError::MissingStart { .. }) | Err(SplitError::LeadingGarbage { .. }) => {
let mut footer = Vec::new();
if source.as_bytes().get(3) == Some(&b'\r') {
footer.push(Annotation {
Expand Down Expand Up @@ -906,7 +905,7 @@ fn process<'a>(
})?;
return Ok(None);
}
Err(preamble::SplitError::MissingEnd { .. }) => {
Err(SplitError::MissingEnd { .. }) => {
reporter
.report(Snippet {
title: Some(Annotation {
Expand Down
3 changes: 2 additions & 1 deletion eipw-lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ use annotate_snippets::snippet::{AnnotationType, Snippet};

use comrak::nodes::AstNode;

use crate::preamble::Preamble;
use crate::reporters::{self, Reporter};

use educe::Educe;

use eipw_preamble::Preamble;

pub use self::known_lints::DefaultLint;

use snafu::Snafu;
Expand Down
16 changes: 16 additions & 0 deletions eipw-preamble/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "eipw-preamble"
version = "0.1.0"
edition = "2021"
license = "MPL-2.0"
rust-version = "1.69"
repository = "https://github.com/ethereum/eipw"
description = "preamble parser for eipw, the Ethereum Improvement Proposal validator"

[dependencies]
annotate-snippets = "0.9.1"
regex = "1.8.4"
snafu = "0.7.4"

[dev-dependencies]
assert_matches = "1.5.0"
1 change: 1 addition & 0 deletions eipw-preamble/LICENSE.md
1 change: 1 addition & 0 deletions eipw-preamble/README.md
34 changes: 29 additions & 5 deletions eipw-lint/src/preamble.rs → eipw-preamble/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
//! This crate comprises the preamble parsing logic for `eipw`, the EIP
//! validator.
//!
//! See [`Preamble`] for more details.
#![warn(missing_docs)]

use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet};

Expand All @@ -12,26 +17,32 @@ use snafu::{ensure, Backtrace, OptionExt, Snafu};

use std::collections::HashMap;

/// Errors that can arise while parsing a preamble. See [`Preamble::parse'].
#[derive(Debug, Snafu)]
pub(crate) struct ParseErrors<'a> {
pub struct ParseErrors<'a> {
backtrace: Backtrace,
errors: Vec<Snippet<'a>>,
}

impl<'a> ParseErrors<'a> {
/// Consumes the error and returns the diagnostic messages (annotations)
/// that caused it.
pub fn into_errors(self) -> Vec<Snippet<'a>> {
self.errors
}
}

/// Errors that can arise from [`Preamble::split`].
#[derive(Debug, Snafu)]
#[snafu(module)]
#[non_exhaustive]
pub(crate) enum SplitError {
pub enum SplitError {
/// Bytes appeared before the first delimiter.
#[snafu(context(suffix(false)))]
LeadingGarbage,
/// The first delimiter was not found.
#[snafu(context(suffix(false)))]
MissingStart,
/// The second delimiter was not found.
#[snafu(context(suffix(false)))]
MissingEnd,
}
Expand Down Expand Up @@ -63,13 +74,15 @@ impl<'a> Fields<'a> {
}
}

/// An ordered list of fields from a preamble.
#[derive(Debug, Default, Clone)]
pub struct Preamble<'a> {
fields: Fields<'a>,
}

impl<'a> Preamble<'a> {
pub(crate) fn split(text: &'a str) -> Result<(&'a str, &'a str), SplitError> {
/// Divides the given text into a preamble portion and a body portion.
pub fn split(text: &'a str) -> Result<(&'a str, &'a str), SplitError> {
let re_marker = Regex::new(r"(^|\n)---(\n|$)").unwrap();

let mut iter = re_marker.find_iter(text);
Expand All @@ -85,7 +98,9 @@ impl<'a> Preamble<'a> {
Ok((preamble, body))
}

pub(crate) fn parse(origin: Option<&'a str>, text: &'a str) -> Result<Self, ParseErrors<'a>> {
/// Parse some preamble text (usually extracted with [`Preamble::split`])
/// for easy access.
pub fn parse(origin: Option<&'a str>, text: &'a str) -> Result<Self, ParseErrors<'a>> {
let lines = text.split('\n');
let mut result: Result<Fields<'a>, Vec<Snippet<'a>>> = Ok(Default::default());

Expand Down Expand Up @@ -156,19 +171,24 @@ impl<'a> Preamble<'a> {
})
}

/// Provides an iterator over the fields from the preamble, in the order
/// they appeared in the source text.
pub fn fields(&self) -> impl '_ + Iterator<Item = Field<'a>> {
self.fields.iter()
}

/// Get a field by its name, or `None` if it isn't present.
pub fn by_name(&self, name: &str) -> Option<Field<'a>> {
self.fields.by_name(name)
}

/// Get a field by its position in the source file (zero-indexed.)
pub fn by_index(&self, index: usize) -> Option<Field<'a>> {
self.fields.by_index(index)
}
}

/// A field from a [`Preamble`] that includes its position in a source file.
#[derive(Debug, Clone, Copy)]
pub struct Field<'a> {
line_start: usize,
Expand All @@ -178,18 +198,22 @@ pub struct Field<'a> {
}

impl<'a> Field<'a> {
/// Line the field was defined on.
pub fn line_start(&self) -> usize {
self.line_start
}

/// Key (before the colon) of this preamble field.
pub fn name(&self) -> &'a str {
self.name
}

/// Value (after the colon) of this preamble field.
pub fn value(&self) -> &'a str {
self.value
}

/// File where this field is defined.
pub fn source(&self) -> &'a str {
self.source
}
Expand Down
Loading