Skip to content

Instantly share code, notes, and snippets.

@panicbit
Created January 9, 2016 01:05
Show Gist options
  • Save panicbit/86f115a75221299500d6 to your computer and use it in GitHub Desktop.
Save panicbit/86f115a75221299500d6 to your computer and use it in GitHub Desktop.
// cargo-deps: nom="~1.0.0"
#[macro_use]
extern crate nom;
use nom::*;
use nom::IResult::*;
use std::str::{self, FromStr};
use std::iter::FromIterator;
use std::collections::HashMap;
fn is_variable(input: u8) -> bool {
is_alphabetic(input) && (input as char).is_lowercase()
}
#[derive(Debug)]
enum Value {
Variable(String),
Integer(i32)
}
impl Value {
fn evaluate(&self, hm: &mut HashMap<String, Op>) -> i32 {
match *self {
Value::Variable(ref var) => evaluate(var, hm),
Value::Integer(int) => int
}
}
}
#[derive(Debug)]
enum Op {
Noop(Value),
Not(Value),
And(Value, Value),
Or(Value, Value),
Lshift(Value, Value),
Rshift(Value, Value)
}
impl Op {
fn from_bytes(bytes: &[u8], lhs: Value, rhs: Value) -> Op {
match bytes {
b"AND" => Op::And(lhs, rhs),
b"OR" => Op::Or(lhs, rhs),
b"LSHIFT" => Op::Lshift(lhs, rhs),
b"RSHIFT" => Op::Rshift(lhs, rhs),
_ => unreachable!()
}
}
fn evaluate(&self, hm: &mut HashMap<String, Op>) -> i32 {
match *self {
Op::Noop(ref value) => value.evaluate(hm),
Op::Not(ref value) => !value.evaluate(hm),
Op::And(ref lhs, ref rhs) => lhs.evaluate(hm) & rhs.evaluate(hm),
Op::Or(ref lhs, ref rhs) => lhs.evaluate(hm) | rhs.evaluate(hm),
Op::Lshift(ref lhs, ref rhs) => lhs.evaluate(hm) << rhs.evaluate(hm),
Op::Rshift(ref lhs, ref rhs) => lhs.evaluate(hm) >> rhs.evaluate(hm)
}
}
}
fn to_string(input: &[u8]) -> Result<String, str::Utf8Error> {
str::from_utf8(input).map(str::to_string)
}
named!(variable<String>,
map_res!(
take_while1!(is_variable),
to_string
)
);
named!(integer<i32>,
map_res!(
map_res!(
take_while1!(is_digit),
str::from_utf8
),
FromStr::from_str
)
);
named!(value<Value>, alt!(
variable => {Value::Variable} |
integer => {Value::Integer}
));
named!(nullary<Op>, chain!(
value: value,
|| Op::Noop(value)
));
named!(unary<Op>, chain!(
tag!("NOT") ~
space ~
value: value,
|| Op::Not(value)
));
named!(binary<Op>, chain!(
lhs: value ~
space ~
op: alt!(
tag!("AND") |
tag!("OR") |
tag!("LSHIFT") |
tag!("RSHIFT")
) ~
space ~
rhs: value,
|| Op::from_bytes(op, lhs, rhs)
));
named!(term<Op>, alt!(binary | unary | nullary));
named!(assignment<(String, Op)>, chain!(
term: term ~
tag!(" -> ") ~
variable: variable,
|| (variable, term)
));
named!(root<Vec<(String, Op)> >,
separated_list!(newline, assignment)
);
fn evaluate(var: &str, hm: &mut HashMap<String, Op>) -> i32 {
let op = hm.remove(var).expect("definition");
let result = op.evaluate(hm);
hm.insert(var.to_string(), Op::Noop(Value::Integer(result)));
result
}
fn main() {
let input = include_bytes!("../input.txt");
if let Done(_, output) = root(input) {
let mut hm: HashMap<String, Op> = HashMap::from_iter(output);
let result = evaluate("a", &mut hm);
println!("{}", result);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment