Skip to content

Instantly share code, notes, and snippets.

@christophebiocca
Created December 9, 2017 20:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save christophebiocca/142d009fd7ffb9601107881ad4ef7cf4 to your computer and use it in GitHub Desktop.
Save christophebiocca/142d009fd7ffb9601107881ad4ef7cf4 to your computer and use it in GitHub Desktop.
Advent of code 2017-08 macrop-less chomp parser example.
//! Only does the parsing. Macro-less chomp is verbose but rather clear to use
extern crate chomp;
use chomp::prelude::*;
use std::io::{self, Read};
fn skip_whitespace(i : &str) -> SimpleResult<&str, ()> {
// skip_while1 is what I wanted to use, but it doesn't exist in the latest release?
take_while1(i, char::is_whitespace).map(|_|{()})
}
fn parse_constant(i : &str) -> SimpleResult<&str, isize> {
option(
i,
|i|{token(i, '-')}.map(|_|{-1}),
1,
).bind(|i, m|{
take_while1(
i,
|c|{c.is_digit(10)},
).map(|s|{
s.parse::<isize>().expect("Already should be a valid number") * m
})
})
}
fn parse_register(i : &str) -> SimpleResult<&str, String> {
take_while1(
i,
char::is_alphabetic,
).map(String::from)
}
#[derive(Debug)]
enum Operation {
Increment(String, isize),
Decrement(String, isize),
}
fn parse_operation(i : &str) -> SimpleResult<&str, Operation> {
// It's not possible to return the constructors and unify them, so the alternative is to
// pass them forward into a shared function
fn with_constant<F>(i : &str, r : String, constructor : F) -> SimpleResult<&str, Operation> where F : Fn(String, isize) -> Operation {
skip_whitespace(i).then(|i|{
parse_constant(i).map(|v|{
constructor(r, v)
})
})
}
parse_register(i).bind(|i, r|{
skip_whitespace(i).then(|i|{
let r1 = r.clone();
or(
i,
|i|{
string(i, &['i', 'n', 'c']).then(|i|{with_constant(i, r, Operation::Increment)})
},
|i|{
string(i, &['d', 'e', 'c']).then(|i|{with_constant(i, r1, Operation::Decrement)})
},
)
})
})
}
#[derive(Debug)]
enum Condition {
Eq(String, isize),
Neq(String, isize),
Lt(String, isize),
Leq(String, isize),
Gt(String, isize),
Geq(String, isize),
}
fn parse_condition(i : &str) -> SimpleResult<&str, Condition> {
// It's not possible to return the constructors and unify them, so the alternative is to
// pass them forward into a shared function.
fn with_constant<F>(i : &str, r : String, constructor : F) -> SimpleResult<&str, Condition> where F : Fn(String, isize) -> Condition {
skip_whitespace(i).then(|i|{
parse_constant(i).map(|v|{
constructor(r, v)
})
})
}
parse_register(i).bind(|i, r|{
skip_whitespace(i).then(|i|{
// Could be much shorter if I used `choice` but would require boxing.
let r1 = r.clone();
or(
i,
|i|{
string(i, &['=', '=']).then(move |i|{with_constant(i, r1, Condition::Eq)})
},
|i|{
let r1 = r.clone();
or(
i,
|i|{
string(i, &['!', '=']).then(move |i|{with_constant(i, r1, Condition::Neq)})
},
|i|{
let r1 = r.clone();
or(
i,
|i|{
token(i, '<').then(move |i|{with_constant(i, r1, Condition::Lt)})
},
|i|{
let r1 = r.clone();
or(
i,
|i|{
string(i, &['<', '=']).then(move |i|{with_constant(i, r1, Condition::Leq)})
},
|i|{
let r1 = r.clone();
or(
i,
|i|{
token(i, '>').then(move |i|{with_constant(i, r1, Condition::Gt)})
},
|i|{
string(i, &['>', '=']).then(move |i|{with_constant(i, r, Condition::Geq)})
},
)
},
)
},
)
},
)
},
)
})
})
}
#[derive(Debug)]
struct Instruction {
condition : Condition,
operation : Operation,
}
fn parse_instruction(i : &str) -> SimpleResult<&str, Instruction> {
parse_operation(i).bind(|i, o|{
skip_whitespace(i).then(|i|{
string(i, &['i', 'f'])
}).then(
skip_whitespace
).then(
parse_condition
).map(|c|{
Instruction {
condition : c,
operation : o,
}
})
})
}
fn parse_instruction_stream(i : &str) -> SimpleResult<&str, Vec<Instruction>> {
sep_by1(
i,
parse_instruction,
|i|{token(i, '\n')},
)
}
fn main() {
let mut input = String::new();
io::stdin().read_to_string(&mut input).expect("Couldn't read stdin");
let instruction_stream = parse_only_str(
parse_instruction_stream,
input.trim(),
).expect("Couldn't parse instruction stream");
println!("{:?}", instruction_stream);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment