Skip to content

Instantly share code, notes, and snippets.

@jcavat
Created October 12, 2019 09:14
Show Gist options
  • Save jcavat/33341cccc77c42e5fe6e715b3248e8d8 to your computer and use it in GitHub Desktop.
Save jcavat/33341cccc77c42e5fe6e715b3248e8d8 to your computer and use it in GitHub Desktop.
ast with pattern match through visitor pattern in Rust for polymorphic return type
struct Cons {
value: i32,
}
struct AddExpr<T> {
lhs: Box<dyn Accept<T>>,
rhs: Box<dyn Accept<T>>
}
trait Accept<T> {
fn accept(&self, v: &dyn Visitor<Result = T>) -> T;
}
impl <T>Accept<T> for Cons {
fn accept(&self, v: &dyn Visitor<Result = T>) -> T { v.visit_cons(&self) }
}
impl <T>Accept<T> for AddExpr<T> {
fn accept(&self, v: &dyn Visitor<Result = T>) -> T { v.visit_expr(&self) }
}
trait Visitor {
type Result;
fn visit_cons(&self, cons: &Cons) -> Self::Result;
fn visit_expr(&self, expr: &AddExpr<Self::Result>) -> Self::Result;
}
struct StringVisitor {}
impl Visitor for StringVisitor {
type Result = String;
fn visit_cons(&self, cons: &Cons) -> String {
format!("Cons({:})", cons.value)
}
fn visit_expr(&self, expr: &AddExpr<String>) -> String {
format!("AddExpr({:},{:})", expr.lhs.accept(self), expr.rhs.accept(self))
}
}
struct XmlVisitor {}
impl Visitor for XmlVisitor {
type Result = String;
fn visit_cons(&self, cons: &Cons) -> String {
format!("<value> {:} </value>", cons.value)
}
fn visit_expr(&self, expr: &AddExpr<String>) -> String {
format!("<add><lhs> {:} </lhs>,<rhs> {:} </rhs></add>", expr.lhs.accept(self), expr.rhs.accept(self))
}
}
fn test<T: 'static>(v: bool) -> Box<dyn Accept<T>> {
if v {
Box::new(Cons{value: 5})
} else {
Box::new( AddExpr {
lhs: Box::new( Cons{ value: 3 } ),
rhs: Box::new(
AddExpr {
lhs: Box::new( Cons{ value: 12 } ),
rhs: Box::new( Cons{ value: 1 } )
}
)}
)
}
}
fn main() {
println!("coucou");
let u = test(false);
println!("{:}", u.accept( &XmlVisitor{} ));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment