type Name = String; #[derive(Debug, Clone)] pub enum Stmt { Puts(Expr), Fix(Name), Assn(Name, Expr), LitAssn(Name, Vec), } #[derive(Debug, Clone)] pub enum Expr { Var(Name), Cat(Vec), Chc(Vec), Rep(i64, Box), Lit(Literal), Ap(Box, Box), Tup(Vec), Let(Name, Box, Box), Fun(Vec), Case(Box, Vec), } #[derive(Debug, Clone)] pub struct Case { pub pat: Pat, pub expr: Expr, } #[derive(Debug, Clone)] pub enum Pat { Var(Name), Lit(Literal), Tup(Vec), } #[derive(Debug, Clone)] pub struct Choice { pub weight: Option, pub value: Expr, } impl Choice { pub fn weight(&self) -> i64 { self.weight.unwrap_or(1) } } #[derive(Debug, Clone)] pub enum Literal { Str(String), Atom(String), Num(i64), } impl Literal { pub fn from_str_literal(s: &str) -> Literal { // strip the outer pieces from the string let mut buf = String::new(); let mut src = s[1..s.len() - 1].chars().into_iter(); while let Some(c) = src.next() { if c == '\\' { match src.next() { Some('n') => buf.push('\n'), Some('t') => buf.push('\t'), Some('r') => buf.push('\r'), Some(c) => buf.push(c), None => panic!("bad escape"), } } else { buf.push(c); } } Literal::Str(buf) } }