Last active
August 29, 2015 14:22
-
-
Save rfielding/da6d3c72da3aa5251501 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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