Skip to content

Commit a46a7fe

Browse files
committed
parser: new more flexible parsing mechanism
1 parent 321d1ee commit a46a7fe

File tree

3 files changed

+201
-92
lines changed

3 files changed

+201
-92
lines changed

src/bin/example.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,48 @@ mod day1 {
2727
}
2828
}
2929

30-
aoc_main::main! {
30+
mod day2 {
31+
pub fn part_1_option(input: &str) -> Option<usize> {
32+
Some(input.len())
33+
}
34+
35+
pub fn part_1_result(input: &str) -> Result<usize, &str> {
36+
Ok(input.len())
37+
}
38+
39+
pub fn part_2_option(_: &str) -> Option<usize> {
40+
None
41+
}
42+
43+
pub fn part_2_result(_: &str) -> Result<usize, &str> {
44+
Err("some error")
45+
}
46+
}
47+
48+
mod day3 {
49+
pub fn generator(_: &str) -> Option<&str> {
50+
None
51+
}
52+
53+
pub fn part_1(input: &str) -> usize {
54+
input.len()
55+
}
56+
}
57+
58+
mod day4 {
59+
pub fn generator(_: &str) -> Result<i64, impl std::fmt::Display + std::fmt::Debug> {
60+
"five".parse()
61+
}
62+
63+
pub fn part_1(input: &i64) -> i64 {
64+
*input
65+
}
66+
}
67+
68+
aoc::main! {
3169
year 2019;
32-
day1 : generator => part_1, part_2
70+
day1 : generator => part_1, part_2;
71+
day2 => part_1_option?, part_1_result?, part_2_option?, part_2_result?;
72+
day3 : generator? => part_1;
73+
day4 : generator? => part_1;
3374
}

src/lib.rs

Lines changed: 98 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod input;
2+
pub mod parse;
23

34
use std::cmp::min;
45
use std::iter;
@@ -63,34 +64,79 @@ pub struct Opt {
6364
}
6465

6566
#[macro_export]
66-
macro_rules! main {
67+
macro_rules! run_day {
6768
(
68-
year $year: expr;
69-
$( $day: ident $( : $generator: ident )? => $( $solution: ident ),+ );+
70-
$( ; )?
71-
) => {
69+
{ $i: expr, $curr_day: expr, $year: expr, $opt: expr },
70+
{ day $day: ident { gen $generator: ident { $( { sol $solution: ident } )* } } }
71+
) => {{
72+
if stringify!($day) == $curr_day {
73+
if $i != 0 { println!() }
74+
let day = $curr_day[3..].parse().expect("days must be integers");
75+
println!("Day {}", day);
76+
77+
let data = {
78+
if $opt.stdin {
79+
let mut data = String::new();
80+
std::io::stdin().read_to_string(&mut data)
81+
.expect("failed to read from stdin");
82+
data
83+
} else if let Some(path) = $opt.file.as_ref() {
84+
read_to_string(path)
85+
.expect("failed to read specified file")
86+
} else {
87+
$crate::input::get_input($year, day).expect("could not fetch input")
88+
}
89+
};
90+
91+
let input = data.as_str();
92+
93+
// $(
94+
let start = Instant::now();
95+
let input = $day::$generator(&data);
96+
let elapsed = start.elapsed();
97+
$crate::print_with_duration("generator", None, elapsed);
98+
// )?
99+
100+
$({
101+
let start = Instant::now();
102+
let response = $day::$solution(&input);
103+
let elapsed = start.elapsed();
104+
105+
$crate::print_with_duration(
106+
stringify!($solution),
107+
Some(&format!("{}", response)),
108+
elapsed,
109+
);
110+
})+
111+
}
112+
}}
113+
}
114+
115+
#[macro_export]
116+
macro_rules! main {
117+
( year $year: expr; $( $tail: tt )* ) => {
72118
use std::fs::read_to_string;
73119
use std::io::Read;
74120
use std::time::Instant;
75121

76-
use $crate::clap::Clap;
122+
use $crate::{clap::Clap, parse, run_day};
77123

78124
const YEAR: u16 = $year;
79-
const DAYS: &[&str] = &[$(stringify!($day)),*];
80125

81126
fn main() {
82127
let mut opt = $crate::Opt::parse();
128+
let days = parse! { extract_day {}; $( $tail )* };
83129

84-
if opt.bench {
85-
bench::run_benchs();
86-
}
130+
// if opt.bench {
131+
// bench::run_benchs();
132+
// }
87133

88134
if opt.days.is_empty() {
89-
opt.days = DAYS.iter().map(|s| s[3..].to_string()).collect();
135+
opt.days = days.iter().map(|s| s[3..].to_string()).collect();
90136
} else {
91137
let ignored_days: Vec<_> = opt.days
92138
.iter()
93-
.filter(|day| !DAYS.contains(&format!("day{}", day).as_str()))
139+
.filter(|day| !days.contains(&format!("day{}", day).as_str()))
94140
.map(String::as_str)
95141
.collect();
96142

@@ -100,7 +146,7 @@ macro_rules! main {
100146

101147
opt.days = opt.days
102148
.into_iter()
103-
.filter(|day| DAYS.contains(&format!("day{}", day).as_str()))
149+
.filter(|day| days.contains(&format!("day{}", day).as_str()))
104150
.collect();
105151
}
106152

@@ -112,93 +158,55 @@ macro_rules! main {
112158

113159
for (i, day) in opt.days.iter().enumerate() {
114160
let module_name = format!("day{}", day);
115-
let day = day.parse().expect("days must be integers");
116161

117-
if !DAYS.contains(&module_name.as_str()) {
162+
if !days.contains(&module_name.as_str()) {
118163
eprintln!(
119164
"Module `{}` was not registered, available are: {}",
120165
module_name,
121-
DAYS.join(", "),
166+
days.join(", "),
122167
);
123168
}
124169

125-
$(
126-
if stringify!($day) == module_name {
127-
if i != 0 { println!() }
128-
println!("Day {}", day);
129-
130-
let data = {
131-
if opt.stdin {
132-
let mut data = String::new();
133-
std::io::stdin().read_to_string(&mut data)
134-
.expect("failed to read from stdin");
135-
data
136-
} else if let Some(path) = opt.file.as_ref() {
137-
read_to_string(path)
138-
.expect("failed to read specified file")
139-
} else {
140-
$crate::input::get_input(YEAR, day).expect("could not fetch input")
141-
}
142-
};
143-
144-
let input = data.as_str();
145-
146-
$(
147-
let start = Instant::now();
148-
let input = $day::$generator(&data);
149-
let elapsed = start.elapsed();
150-
$crate::print_with_duration("generator", None, elapsed);
151-
)?
152-
153-
$({
154-
let start = Instant::now();
155-
let response = $day::$solution(&input);
156-
let elapsed = start.elapsed();
157-
158-
$crate::print_with_duration(
159-
stringify!($solution),
160-
Some(&format!("{}", response)),
161-
elapsed,
162-
);
163-
})+
164-
}
165-
)+
170+
parse! {
171+
run_day { i, module_name, YEAR, opt };
172+
$( $tail )*
173+
};
166174
}
167175
}
168176

169177

170-
mod bench {
171-
use $crate::criterion::*;
172-
173-
pub fn run_benchs() {
174-
main();
175-
}
176-
177-
$(
178-
fn $day(c: &mut Criterion) {
179-
let mut group = c.benchmark_group(stringify!($day));
180-
let day = stringify!($day)[3..].parse().expect("dayX expected for module");
181-
182-
let data = $crate::input::get_input(crate::YEAR, day)
183-
.expect("could not fetch input");
184-
185-
let input = data.as_str();
186-
$( let input = crate::$day::$generator(&data); )?
187-
188-
189-
$(
190-
group.bench_function(
191-
stringify!($solution),
192-
|b| b.iter(|| crate::$day::$solution(&input)),
193-
);
194-
)+
195-
196-
group.finish();
197-
}
198-
)+
199-
200-
criterion_group!(benches, $($day),+);
201-
criterion_main!(benches);
202-
}
178+
// mod bench {
179+
// use $crate::criterion::*;
180+
//
181+
// pub fn run_benchs() {
182+
// main();
183+
// }
184+
//
185+
// $(
186+
// fn $day(c: &mut Criterion) {
187+
// let mut group = c.benchmark_group(stringify!($day));
188+
// let day = stringify!($day)[3..].parse().expect("dayX expected for module");
189+
//
190+
// let data = $crate::input::get_input(crate::YEAR, day)
191+
// .expect("could not fetch input");
192+
//
193+
// let input = data.as_str();
194+
// $( let input = crate::$day::$generator(&data); )?
195+
//
196+
//
197+
// $(
198+
// group.bench_function(
199+
// stringify!($solution),
200+
// |b| b.iter(|| crate::$day::$solution(&input)),
201+
// );
202+
// )+
203+
//
204+
// group.finish();
205+
// }
206+
// )+
207+
//
208+
// criterion_group!(benches, $($day),+);
209+
// criterion_main!(benches);
210+
// }
203211
};
204212
}

src/parse.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Call `apply` macro on this generated form of token tree;
2+
// $ctx, { day DAY { gen GENERATOR { { sol SOLUTION } { sol SOLUTION } } } }
3+
#[macro_export]
4+
macro_rules! parse {
5+
// Read day
6+
(
7+
day $apply: ident, $ctx: tt, $val: expr;
8+
$day: ident : $generator: ident => $( $tail: tt )*
9+
) => {
10+
$crate::parse!( sol $apply, $ctx, $val; { day $day { gen $generator { } } }; $( $tail )* )
11+
};
12+
13+
// Empty rules
14+
( day $apply: ident, $ctx: tt, $val: expr; ) => {};
15+
16+
// Read solution
17+
(
18+
sol $apply: ident, $ctx: tt, $val: expr;
19+
{ day $day: tt { gen $generator: tt { $( $acc: tt )* } } } ;
20+
$sol: ident $( $tail: tt )*
21+
) => {
22+
$crate::parse!(
23+
post_sol $apply, $ctx, $val;
24+
{ day $day { gen $generator { $( $acc )* { sol $sol } } } };
25+
$( $tail )*
26+
)
27+
};
28+
29+
// After solution: there is new solutions
30+
(
31+
post_sol $apply: ident, $ctx: tt, $val: expr;
32+
$curr: tt ; , $( $tail: tt )*
33+
) => {
34+
$crate::parse!( sol $apply, $ctx, $val; $curr; $( $tail )* )
35+
};
36+
37+
// After solution: end of day
38+
(
39+
post_sol $apply: ident, $ctx: tt, $val: expr;
40+
$curr: tt ; ; $( $tail: tt )*
41+
) => {{
42+
$val.push($apply!{ $ctx, $curr });
43+
$crate::parse!( day $apply, $ctx, $val; $( $tail )* );
44+
}};
45+
46+
// Initialization
47+
( $apply: ident $ctx: tt; $( $tt: tt )* ) => {{
48+
let mut val = Vec::new();
49+
$crate::parse!( day $apply, $ctx, val; $( $tt )* );
50+
val
51+
}};
52+
}
53+
54+
// Extract day names from a parsed token tree
55+
#[macro_export]
56+
macro_rules! extract_day {
57+
({}, { day $day: ident $other: tt }) => {
58+
stringify!($day)
59+
};
60+
}

0 commit comments

Comments
 (0)