Skip to content
Open
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
116 changes: 93 additions & 23 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::error::Error;

use chrono::DateTime;
use nom::combinator::verify;
use nom::complete::take;
use nom::*;
use nom::{
branch::alt,
Expand Down Expand Up @@ -263,32 +264,21 @@ fn is_next_header(input: Input<'_>) -> bool {
///FIXME: Use the ranges in the chunk header to figure out how many chunk lines to parse. Will need
/// to figure out how to count in nom more robustly than many1!(). Maybe using switch!()?
///FIXME: The test_parse_triple_plus_minus_hack test will no longer panic when this is fixed.
fn chunk(input: Input) -> IResult<Input, Hunk> {
fn chunk(input: Input) -> IResult<Input, Hunk> {
// First, parse the chunk header to get range information
let (input, ranges) = chunk_header(input)?;
let (old_range, new_range, range_hint) = ranges;

// Parse chunk lines, using the range information to guide parsing
let (input, lines) = many0(verify(
alt((
// Detect added lines
map(
preceded(tuple((char('+'), not(tag("++ ")))), consume_content_line),
Line::Add,
),
// Detect removed lines
map(
preceded(tuple((char('-'), not(tag("-- ")))), consume_content_line),
Line::Remove,
),
// Detect context lines
map(preceded(char(' '), consume_content_line), Line::Context),
// Handle empty lines within the chunk
map(tag("\n"), |_| Line::Context("")),
)),
// Stop parsing when we detect the next header or have parsed the expected number of lines
|_| !is_next_header(input),
))(input)?;
// Calculate total expected lines
let total_context = old_range.count;
let total_added = new_range.count;

let (input, lines) = parse_hunk_lines(
input,
old_range.count as usize,
new_range.count as usize,
)?;

let (old_range, new_range, range_hint) = ranges;
Ok((
input,
Hunk {
Expand All @@ -300,6 +290,86 @@ fn chunk(input: Input) -> IResult<Input, Hunk> {
))
}

fn parse_hunk_lines<'a>(
mut input: Input<'a>,
old_count: usize,
new_count: usize,
) -> IResult<Input<'a>, Vec<Line<'a>>> {
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::{char, line_ending, not_line_ending},
combinator::{map, opt},
sequence::preceded,
IResult,
};

enum LineKind<'b> {
Add(&'b str),
Remove(&'b str),
Context(&'b str),
EmptyContext,
}

let mut lines = Vec::new();
let mut context = 0;
let mut added = 0;
let mut removed = 0;

while context + removed < old_count || context + added < new_count {
let (rest, kind) = alt((
// +added line
map(preceded(char('+'), not_line_ending), |s: Input<'a>| LineKind::Add(*s.fragment())),
// -removed line
map(preceded(char('-'), not_line_ending), |s: Input<'a>| LineKind::Remove(*s.fragment())),
// ' ' context line (possibly empty after the space)
map(preceded(char(' '), opt(not_line_ending)), |opt_s: Option<Input<'a>>| {
LineKind::Context(opt_s.map(|s| *s.fragment()).unwrap_or(""))
}),
// bare newline (no prefix at all) = empty context line
map(line_ending, |_| LineKind::EmptyContext),
))(input)?;

// For all but EmptyContext, consume the line ending

let (rest, _) = match &kind {
LineKind::EmptyContext => (rest, ()), // already consumed
_ => {
let (rest, _) = line_ending(rest)?;
(rest, ())
}
};
// Update counters and build Line
let line = match kind {
LineKind::Add(s) => {
added += 1;
Line::Add(s)
}
LineKind::Remove(s) => {
removed += 1;
Line::Remove(s)
}
LineKind::Context(s) => {
context += 1;
Line::Context(s)
}
LineKind::EmptyContext => {
context += 1;
Line::Context("")
}
};

lines.push(line);
input = rest;

if context + removed == old_count && context + added == new_count {
break;
}
}

Ok((input, lines))
}

fn chunk_header(input: Input<'_>) -> IResult<Input<'_>, (Range, Range, &'_ str)> {
let (input, _) = tag("@@ -")(input)?;
let (input, old_range) = range(input)?;
Expand Down
1 change: 0 additions & 1 deletion tests/parse_patch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ fn test_parse_triple_plus_minus() -> Result<(), ParseError<'static>> {
// actually takes the hunk ranges into account, the #[should_panic] annotation should be removed.
// See the FIXME comment on top of the chunk_line parser.
#[test]
#[should_panic]
fn test_parse_triple_plus_minus_hack() {
// Our parser has some hacky rules to make sure that lines starting with +++ or --- aren't
// interpreted as regular addition/removal lines that could be part of a hunk. This test
Expand Down
5 changes: 3 additions & 2 deletions tests/parse_samples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ fn parse_wild_samples() {
}

let data = fs::read_to_string(dbg!(&path)).unwrap();
let patches = Patch::from_multiple(&data)
.unwrap_or_else(|err| panic!("failed to parse {:?}, error: {}", path, err));
let patches = Patch::from_multiple(&data);

println!("Patches: {:?}", patches);
let patches = patches.unwrap_or_else(|err| panic!("failed to parse {:?}, error: {}", path, err));
// Make sure that the patch file we produce parses to the same information as the original
// patch file.
#[allow(clippy::format_collect)] // Display::fmt is the only way to resolve Patch->str
Expand Down
53 changes: 53 additions & 0 deletions tests/wild-samples/sample2.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# HG changeset patch
# Parent 13ba6cbdb304cd251fbc22466cadb21019ee817f
# User Bill McCloskey <wmccloskey@mozilla.com>

diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -6369,17 +6369,17 @@ public:
nsCycleCollectionParticipant* helper)
{
}

NS_IMETHOD_(void) NoteNextEdgeName(const char* name)
{
}

- NS_IMETHOD_(void) NoteWeakMapping(void* map, void* key, void* val)
+ NS_IMETHOD_(void) NoteWeakMapping(void* map, void* key, void* kdelegate, void* val)
{
}

bool mFound;

private:
void* mWrapper;
};
diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -527,16 +527,24 @@ js::VisitGrayWrapperTargets(JSCompartmen
{
for (WrapperMap::Enum e(comp->crossCompartmentWrappers); !e.empty(); e.popFront()) {
gc::Cell *thing = e.front().key.wrapped;
if (thing->isMarked(gc::GRAY))
callback(closure, thing);
}
}

+JS_FRIEND_API(JSObject *)
+js::GetWeakmapKeyDelegate(JSObject *key)
+{
+ if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp)
+ return op(key);
+ return NULL;
+}
+
JS_FRIEND_API(void)
JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback)
{
rt->telemetryCallback = callback;
}

JS_FRIEND_API(JSObject *)
Loading