Skip to main content
edited tags
Link
dfhwze
  • 13.9k
  • 3
  • 38
  • 101
made q2 clearer, typo fix
Source Link
Chetan
  • 133
  • 4
  1. Am I using the "right" type for the Add subnodes (i.e. Rc)?
  2. Is it possible to create eval as a function instead of an AST method instead of a function? I kept fighting the borrow checking if x in eval was self : &AST<T> (within the impl block, of course)
  3. Is there any way to make this program more concise/cleaner? I think I understand why all the additional wrapping and sprinkling of Rc::clone/new and lots of reference taking is needed, but was wondering if I was perhaps missing something that might make this code cleaner to read. Any other feedback/helpfulehelpful pointers would also be appreciated. Thank you!
  1. Am I using the "right" type for the Add subnodes (i.e. Rc)?
  2. Is it possible to create eval as a function instead of an AST method? I kept fighting the borrow checking if x in eval was self : &AST<T> (within the impl block, of course)
  3. Is there any way to make this program more concise/cleaner? I think I understand why all the additional wrapping and sprinkling of Rc::clone/new and lots of reference taking is needed, but was wondering if I was perhaps missing something that might make this code cleaner to read. Any other feedback/helpfule pointers would also be appreciated. Thank you!
  1. Am I using the "right" type for the Add subnodes (i.e. Rc)?
  2. Is it possible to create eval as an AST method instead of a function? I kept fighting the borrow checking if x in eval was self : &AST<T> (within the impl block, of course)
  3. Is there any way to make this program more concise/cleaner? I think I understand why all the additional wrapping and sprinkling of Rc::clone/new and lots of reference taking is needed, but was wondering if I was perhaps missing something that might make this code cleaner to read. Any other feedback/helpful pointers would also be appreciated. Thank you!
Source Link
Chetan
  • 133
  • 4

Toy Expression Interpreter

I've just started learning Rust (coming from Haskell) and decided to test a toy expression interpreter.

Code:

use std::rc::Rc;

pub type RAST<T> = Rc<AST<T>>;

#[derive(Debug)]
pub enum AST<T> {
    ConstInt(isize, Rc<T>),
    Add(RAST<T>, RAST<T>, Rc<T>),
}

pub fn eval<T>(x: &RAST<T>) -> RAST<T> {
    match &**x {
        AST::Add::<T>(l, r, t) => {
            let el = eval(&l);
            let er = eval(&r);
            match (&*el, &*er) {
                (AST::ConstInt::<T>(li,_q),
                 AST::ConstInt::<T>(ri,_r)) =>
                    Rc::new(AST::ConstInt::<T>(li+ri, Rc::clone(t))),
                _ => mk_add(&el, &er, &t),
            }
        },
        _ => Rc::clone(x),
    }
}

pub fn mk_int<T>(i: isize, t: &Rc<T>) -> RAST<T> {
    Rc::new(AST::ConstInt::<T>(i, Rc::clone(t)))
}

pub fn mk_add<T>(l: &RAST<T>, r: &RAST<T>, t: &Rc<T>) -> RAST<T> {
    Rc::new(AST::Add::<T>(Rc::clone(l), Rc::clone(r), Rc::clone(t)))
}

pub fn main() {
    let a = Rc::new(());
    
    let x = mk_int(3, &a);
    let y = mk_int(6, &a);
    let z = mk_add(&x, &y, &a);
    let c = mk_add(&x, &z, &a);
    
    let r = eval(&c);
    println!("Raw: {:?}", c);
    println!("Evaluated: {:?}", r);
}

With this output:

Raw: Add(ConstInt(3, ()), Add(ConstInt(3, ()), ConstInt(6, ()), ()), ())
Evaluated: ConstInt(12, ())

I'd really appreciate any feedback on:

  1. Am I using the "right" type for the Add subnodes (i.e. Rc)?
  2. Is it possible to create eval as a function instead of an AST method? I kept fighting the borrow checking if x in eval was self : &AST<T> (within the impl block, of course)
  3. Is there any way to make this program more concise/cleaner? I think I understand why all the additional wrapping and sprinkling of Rc::clone/new and lots of reference taking is needed, but was wondering if I was perhaps missing something that might make this code cleaner to read. Any other feedback/helpfule pointers would also be appreciated. Thank you!