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

Fix nom_json and enable benchmarks for nom and pom parsers #1003

Merged
merged 3 commits into from
Feb 28, 2025
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 parser/benches/bench_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@

use criterion::*;

use crate::nom_json::nom_parse_json;
use crate::oni_comb_json::oni_comb_parse_json;
use crate::pom_json::pom_parse_json;
// use pprof::criterion::{Output, PProfProfiler};

mod nom_json;
mod oni_comb_json;
mod pom_json;

/// 異なる複雑さのJSONデータを用意
fn get_test_data() -> Vec<(&'static str, &'static str)> {
Expand Down Expand Up @@ -63,9 +67,16 @@ fn criterion_benchmark(criterion: &mut Criterion) {

// 各テストデータに対してベンチマークを実行
for (name, data) in get_test_data() {
// oni-comb-rsパーサーのベンチマーク
group.bench_with_input(BenchmarkId::new("oni-comb-rs", name), data, |b, i| {
b.iter(|| oni_comb_parse_json(i))
});

// nomパーサーのベンチマーク
group.bench_with_input(BenchmarkId::new("nom", name), data, |b, i| b.iter(|| nom_parse_json(i)));

// pomパーサーのベンチマーク
group.bench_with_input(BenchmarkId::new("pom", name), data, |b, i| b.iter(|| pom_parse_json(i)));
}

group.finish();
Expand Down
59 changes: 32 additions & 27 deletions parser/benches/nom_json.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
// #![cfg(feature = "alloc")]

use nom::{
branch::alt,
bytes::complete::{escaped, tag, take_while},
character::complete::{char, one_of},
character::complete::{alphanumeric1 as alphanumeric, char, one_of},
combinator::{cut, map, opt, value},
error::{context, ContextError, ErrorKind, ParseError},
multi::separated_list0,
number::complete::double,
sequence::{delimited, preceded, separated_pair, terminated},
IResult,
Err, IResult, Parser,
};
use std::collections::HashMap;
use std::str;
Expand Down Expand Up @@ -73,11 +71,11 @@ fn boolean<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, bool,

// `alt` combines the two parsers. It returns the result of the first
// successful parser, or an error
alt((parse_true, parse_false))(input)
alt((parse_true, parse_false)).parse(input)
}

fn null<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, (), E> {
value((), tag("null"))(input)
value((), tag("null")).parse(input)
}

/// this parser combines the previous `parse_str` parser, that recognizes the
Expand All @@ -92,7 +90,7 @@ fn null<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, (), E> {
/// - `context` lets you add a static string to provide more information in the
/// error chain (to indicate which parser had an error)
fn string<'a, E: ParseError<&'a str> + ContextError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
context("string", preceded(char('\"'), cut(terminated(parse_str, char('\"')))))(i)
context("string", preceded(char('\"'), cut(terminated(parse_str, char('\"'))))).parse(i)
}

/// some combinators, like `separated_list0` or `many0`, will call a parser repeatedly,
Expand All @@ -109,13 +107,14 @@ fn array<'a, E: ParseError<&'a str> + ContextError<&'a str>>(i: &'a str) -> IRes
preceded(sp, char(']')),
)),
),
)(i)
)
.parse(i)
}

fn key_value<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
i: &'a str,
) -> IResult<&'a str, (&'a str, JsonValue), E> {
separated_pair(preceded(sp, string), cut(preceded(sp, char(':'))), json_value)(i)
separated_pair(preceded(sp, string), cut(preceded(sp, char(':'))), json_value).parse(i)
}

fn hash<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
Expand All @@ -132,7 +131,8 @@ fn hash<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
preceded(sp, char('}')),
)),
),
)(i)
)
.parse(i)
}

/// here, we apply the space parser before trying to parse a value
Expand All @@ -147,26 +147,31 @@ fn json_value<'a, E: ParseError<&'a str> + ContextError<&'a str>>(i: &'a str) ->
map(boolean, JsonValue::Boolean),
map(null, |_| JsonValue::Null),
)),
)(i)
)
.parse(i)
}

/// the root element of a JSON parser is either an object or an array
/// Note: This function is currently not used in the benchmarks
/// but kept for reference.
// fn root<'a, E: ParseError<&'a str> + ContextError<&'a str>>(i: &'a str) -> IResult<&'a str, JsonValue, E> {
// delimited(
// sp,
// alt((
// map(hash, JsonValue::Object),
// map(array, JsonValue::Array),
// map(null, |_| JsonValue::Null),
// )),
// opt(sp),
// )(i)
// }
fn root<'a, E: ParseError<&'a str> + ContextError<&'a str>>(i: &'a str) -> IResult<&'a str, JsonValue, E> {
delimited(
sp,
alt((
map(hash, JsonValue::Object),
map(array, JsonValue::Array),
map(null, |_| JsonValue::Null),
)),
opt(sp),
)
.parse(i)
}

pub fn nom_parse_json(s: &str) {
let ir = json_value::<(&str, ErrorKind)>(s);
let _ = ir.unwrap().1;
// println!("{:?}", r);
match json_value::<(&str, ErrorKind)>(s) {
Ok((_, _)) => {
// パース成功
}
Err(_) => {
// パース失敗(ベンチマークでは無視)
}
}
}
2 changes: 1 addition & 1 deletion parser/src/core/committed_status.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// A structure representing the commit status of the parser.<br/>
/// パーサのコミット状態を表す構造体。
#[derive(Debug, Clone, PartialOrd, PartialEq)]
#[derive(Debug, Clone, Copy, PartialOrd, PartialEq)]
pub enum CommittedStatus {
Committed,
Uncommitted,
Expand Down
2 changes: 1 addition & 1 deletion parser/src/core/parse_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl<'a, I, A> ParseResult<'a, I, A> {
ParseResult::Failure {
committed_status: is_committed,
..
} => Some(is_committed.clone()),
} => Some(*is_committed),
_ => None,
}
}
Expand Down
Loading