Skip to content

Instantly share code, notes, and snippets.

@rfielding
Last active August 29, 2015 14:22
Show Gist options
  • Save rfielding/da6d3c72da3aa5251501 to your computer and use it in GitHub Desktop.
Save rfielding/da6d3c72da3aa5251501 to your computer and use it in GitHub Desktop.
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Error;
//#[allow(dead_code)]
#[derive(Copy,Clone)]
enum Opb {
PAIR,
ADD,
SUB,
MUL,
DIV,
TYP,
EQ
}
impl Display for Opb {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
match *self {
Opb::PAIR => write!(f, ","),
Opb::ADD => write!(f, "+"),
Opb::SUB => write!(f, "-"),
Opb::MUL => write!(f, "*"),
Opb::DIV => write!(f, "/"),
Opb::TYP => write!(f, ":"),
Opb::EQ => write!(f, "=")
}
}
}
#[derive(Copy,Clone)]
enum Opu {
NOP,
COMMUTE,
RDIST
}
impl Display for Opu {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
match *self {
Opu::COMMUTE => write!(f, "commute"),
Opu::NOP => write!(f, "nop"),
Opu::RDIST => write!(f, "rdist")
}
}
}
#[derive(Clone)]
enum Expr {
Name(&'static str),
Int(i32),
BinOp(Box<Expr>, Opb, Box<Expr>),
UOp(Box<Expr>,Opu)
}
impl Display for Expr {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
match *self {
Expr::Name(ref s) => write!(f, "{}", s),
Expr::Int(ref i) => write!(f, "{}", i),
Expr::BinOp(ref l,ref op,ref r) => write!(f, "({} {} {})", l, op, r),
Expr::UOp(ref l,ref op) => write!(f, "({} {})", l, op)
}
}
}
////Relatively straightforward because nothing is copied
// (a op b) -> (b op a)
fn commute(expr: Expr) -> Expr {
match expr {
Expr::BinOp(l, op, r) => Expr::BinOp(r, op, l),
_ => expr
}
}
////This was rather tricky because of the boxes, and copying and cloning
// ( (ll opl rl) op r) -> ( (ll op r) opl (rl op r) )
fn rdistrib(expr: Expr) -> Expr {
match expr.clone() {
Expr::BinOp(l, op, r) =>
match (*l).clone() {
Expr::BinOp(ll, opl, rl) =>
Expr::BinOp(
Box::new(
Expr::BinOp(
Box::new((*ll).clone()),
op,
Box::new((*r).clone()),
)
),
opl,
Box::new(
Expr::BinOp(
Box::new((*rl).clone()),
op,
Box::new((*r).clone()),
)
),
),
_ => expr
},
_ => expr
}
}
////Remove the tedium of constructing binops
fn do_opb(expr1: Expr, op: Opb, expr2: Expr) -> Expr {
let x = Expr::BinOp(Box::new(expr1.clone()), op, Box::new(expr2.clone()));
println!("{}", x);
x
}
fn do_reduce(expr1: Expr) -> Expr {
match expr1.clone() {
Expr::UOp(x, uo) => {
match uo {
Opu::COMMUTE => commute(*x),
Opu::RDIST => rdistrib(*x),
Opu::NOP => *x
}
},
_ => expr1
}
}
fn do_opu(expr1: Expr, op: Opu) -> Expr {
let mut x = Expr::UOp(Box::new(expr1.clone()), op);
x = do_reduce(x);
println!("{}", x);
x
}
////Simple test of garbage collection free symbolic manipulation
fn main() {
let mut x0 : Expr = Expr::Name("a");
x0 = do_opb(x0, Opb::TYP, Expr::Name("t"));
x0 = do_opb(x0, Opb::PAIR, Expr::Name("z"));
x0 = do_opb(x0, Opb::ADD, Expr::Int(1));
x0 = do_opu(x0, Opu::COMMUTE);
x0 = do_opb(x0, Opb::MUL, Expr::Name("b"));
x0 = do_opu(x0, Opu::RDIST);
x0 = do_opb(x0, Opb::EQ, Expr::Name("c"));
x0 = do_opb(x0, Opb::ADD, Expr::Int(42));
x0 = do_opu(x0, Opu::RDIST);
x0 = do_opb(x0, Opb::DIV, Expr::Int(2));
x0 = do_opu(x0, Opu::RDIST);
do_opu(x0, Opu::NOP);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment