Skip to content

Commit 4498dff

Browse files
committed
the first sketch of parsing a tag with Nom and half-decent errors
1 parent 650f700 commit 4498dff

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

git-object/src/parsed/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::str;
66
mod tag;
77
mod util;
88

9+
use nom::error::ParseError;
910
pub use tag::Tag;
1011

1112
#[cfg(test)]
@@ -21,13 +22,36 @@ quick_error! {
2122
ParseError(msg: &'static str, kind: Vec<u8>) {
2223
display("{}: {:?}", msg, std::str::from_utf8(&kind))
2324
}
25+
Nom(input: bstr::BString, msg: &'static str) {
26+
display("{}: '{}' could not be parsed", msg, input)
27+
}
2428
ObjectKind(err: crate::Error) {
2529
from()
2630
cause(err)
2731
}
2832
}
2933
}
3034

35+
impl Error {
36+
pub fn parse_context(mut self, ctx: &'static str) -> Self{
37+
match self {
38+
Error::Nom(_, ref mut message) => *message = ctx,
39+
_ => {}
40+
};
41+
self
42+
}
43+
}
44+
45+
impl ParseError<&[u8]> for Error {
46+
fn from_error_kind(input: &[u8], kind: nom::error::ErrorKind) -> Self {
47+
Error::Nom(input.into(), "parse error")
48+
}
49+
50+
fn append(_: &[u8], _: nom::error::ErrorKind, other: Self) -> Self {
51+
other
52+
}
53+
}
54+
3155
#[derive(PartialEq, Eq, Debug, Hash)]
3256
pub enum Object<'data> {
3357
Tag(Tag<'data>),

git-object/src/parsed/tag.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ use crate::{parsed::Signature, Time};
66
use bstr::{BStr, ByteSlice};
77
use btoi::btoi;
88
use hex::FromHex;
9+
use nom::{bytes::complete::tag, IResult, };
10+
use nom::sequence::{tuple, preceded, terminated};
11+
use nom::bytes::complete::{take, take_while, take_while_m_n};
12+
use nom::combinator::map;
913

1014
#[derive(PartialEq, Eq, Debug, Hash)]
1115
pub struct Tag<'data> {
@@ -71,6 +75,29 @@ fn parse_signature(d: &[u8]) -> Result<Signature, Error> {
7175
})
7276
}
7377

78+
fn context(msg: &'static str) -> impl Fn(nom::Err<Error>) -> nom::Err<Error> {
79+
move |e: nom::Err<Error>| e.map(|e| e.parse_context(msg))
80+
}
81+
82+
fn is_hex_digit_lc(b: u8) -> bool {
83+
match b {
84+
b'0'..=b'9' => true,
85+
b'a'..=b'f' => true,
86+
_ => false,
87+
}
88+
}
89+
90+
pub(crate) fn parse_tag_nom(i: &[u8]) -> IResult<&[u8], Tag, Error> {
91+
const NL: &[u8] = b"\n";
92+
let (i, _) = terminated(preceded(tag(b"object "), take_while_m_n(40usize, 40, is_hex_digit_lc)), tag(NL))(i).map_err(context("object <40 lowercase hex char>"))?;
93+
unimplemented!("parse message nom")
94+
}
95+
96+
pub(crate) fn parse_message_nom(i: &[u8]) -> IResult<&[u8], (Option<&BStr>, Option<&BStr>), Error> {
97+
let (i, _) = tag(b"\n")(i)?;
98+
unimplemented!("parse message nom")
99+
}
100+
74101
fn parse_message<'data>(
75102
d: &'data [u8],
76103
mut lines: impl Iterator<Item = &'data [u8]>,

git-object/src/parsed/tests/tag.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,20 @@ use crate::{
66
use bstr::ByteSlice;
77
use pretty_assertions::assert_eq;
88

9+
mod message {
10+
use super::fixture_bytes;
11+
use super::parsed::tag::parse_tag_nom;
12+
use crate::parsed::tests::tag::tag_fixture;
13+
14+
#[test]
15+
fn parse() {
16+
let fixture = fixture_bytes("tag.txt");
17+
assert_eq!(parse_tag_nom(&fixture).unwrap().1, tag_fixture(9000));
18+
}
19+
}
20+
921
#[test]
10-
fn tag_parse() {
22+
fn parse() {
1123
let fixture = fixture_bytes("tag.txt");
1224
let actual = parsed::Tag::from_bytes(&fixture).unwrap();
1325
assert_eq!(actual, tag_fixture(9000));

0 commit comments

Comments
 (0)