fn derive_type(&self, expr: &Expression) -> Result<Type, String> {
        match *expr {
            // Trivial cases
            Expression::Int(_) => Ok(Type::Int),
            Expression::Char(_) => Ok(Type::Char),
            Expression::Bool(_) => Ok(Type::Bool),
            Expression::Str(_) => Ok(Type::Str),

            // A variable identifier
            Expression::Identifier(ref ident) => {
                // If we have an identifier, we need to look it up in the context
                match self.variables[self.depth - 1].get(ident) {
                    Some(ref t) => Ok((*t).clone()),
                    None => Err(format!("use of undeclared variable '{}'", ident))
                }
            },

            // A function call
            Expression::FunctionCall(_) => {
                // Lookup function
                // Get return type
                Err(format!("cannot derive type of function call - unimplemented"))
            }

            // An array literal
            Expression::ArrayLiteral(ref v) => {
                let first_type = try!(self.derive_type(&v[0]));
                for e in v.iter() {
                    let et = try!(self.derive_type(e));
                    if first_type != et {
                        return Err(format!("array literal has mixed types"));
                    }
                }
                Ok(Type::Array(Box::new(first_type)))
            }

            // A unary expression (such as -x or !x)
            Expression::Unary(ref op, ref expr) => {
                let expr_type = try!(self.derive_type(expr));
                match *op {
                    UnaryOp::Neg => {
                        match expr_type {
                            Type::Int => Ok(expr_type),
                            _ => Err(format!("invalid type in unary operator '{:?}' (expected: int, actual: {:?})", op, expr_type))
                        }
                    }
                }
            },

            // A binary expression (such as +, *, /, etc)
            Expression::Binary(ref op, ref lhs, ref rhs) => {
                let t1 = try!(self.derive_type(lhs));
                let t2 = try!(self.derive_type(rhs));
                
                // If the types of the lhs and the rhs match, then check to ensure the types make
                // sense for the respective operators
                if t1 == t2 {
                    match *op {
                        // Arithmetic operators require an int type
                        BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div | BinaryOp::Mod => {
                            match t1 {
                                Type::Int => Ok(t1),
                                _ => Err(format!("invalid type on left of operator '{:?}' (expected: int, actual: {:?})", op, t1))
                            }
                        }
                    }
                } else {
                    Err(format!("invalid type on right of operator '{:?}' (expected: {:?}, actual: {:?})", op, t1, t2))
                }
            }
        }
    }
/// Given an expression, derive it's final type. If there is a problem, then display an error
/// message and return the 'ERROR' type, so semantic checking can continue.
Given an expression, derive it's final type. If there is a problem, then display an error
message and return the 'ERROR' type, so semantic checking can continue.
Given an expression derive it ' s final type . If there is a problem then display an error message and return the ' ERROR ' type so semantic checking can continue .
fn derive_type(&self, expr: &Expression) -> Result<Type, String> {
        match *expr {
            // Trivial cases
            Expression::Int(_) => Ok(Type::Int),
            Expression::Char(_) => Ok(Type::Char),
            Expression::Bool(_) => Ok(Type::Bool),
            Expression::Str(_) => Ok(Type::Str),
            // A variable identifier
            Expression::Identifier(ref ident) => {
                // If we have an identifier, we need to look it up in the context
                match self.variables[self.depth - 1].get(ident) {
                    Some(ref t) => Ok((*t).clone()),
                    None => Err(format!("use of undeclared variable '{}'", ident))
                }
            },
            // A function call
            Expression::FunctionCall(_) => {
                // Lookup function
                // Get return type
                Err(format!("cannot derive type of function call - unimplemented"))
            }
            // An array literal
            Expression::ArrayLiteral(ref v) => {
                let first_type = try!(self.derive_type(&v[0]));
                for e in v.iter() {
                    let et = try!(self.derive_type(e));
                    if first_type != et {
                        return Err(format!("array literal has mixed types"));
                    }
                }
                Ok(Type::Array(Box::new(first_type)))
            }
            // A unary expression (such as -x or !x)
            Expression::Unary(ref op, ref expr) => {
                let expr_type = try!(self.derive_type(expr));
                match *op {
                    UnaryOp::Neg => {
                        match expr_type {
                            Type::Int => Ok(expr_type),
                            _ => Err(format!("invalid type in unary operator '{:?}' (expected: int, actual: {:?})", op, expr_type))
                        }
                    }
                }
            },
            // A binary expression (such as +, *, /, etc)
            Expression::Binary(ref op, ref lhs, ref rhs) => {
                let t1 = try!(self.derive_type(lhs));
                let t2 = try!(self.derive_type(rhs));
                // If the types of the lhs and the rhs match, then check to ensure the types make
                // sense for the respective operators
                if t1 == t2 {
                    match *op {
                        // Arithmetic operators require an int type
                        BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div | BinaryOp::Mod => {
                            match t1 {
                                Type::Int => Ok(t1),
                                _ => Err(format!("invalid type on left of operator '{:?}' (expected: int, actual: {:?})", op, t1))
                            }
                        }
                    }
                } else {
                    Err(format!("invalid type on right of operator '{:?}' (expected: {:?}, actual: {:?})", op, t1, t2))
                }
            }
        }
    }
fn derive_type ( & self , expr : & Expression ) -> Result < Type , String > { match * expr { // Trivial cases Expression :: Int ( _ ) => Ok ( Type :: Int ) , Expression :: Char ( _ ) => Ok ( Type :: Char ) , Expression :: Bool ( _ ) => Ok ( Type :: Bool ) , Expression :: Str ( _ ) => Ok ( Type :: Str ) , // A variable identifier Expression :: Identifier ( ref ident ) => { // If we have an identifier, we need to look it up in the context match self . variables [ self . depth - 1 ] . get ( ident ) { Some ( ref t ) => Ok ( ( * t ) . clone ( ) ) , None => Err ( format ! ( " " ident ) ) } } , // A function call Expression :: FunctionCall ( _ ) => { // Lookup function // Get return type Err ( format ! ( " " ) ) } // An array literal Expression :: ArrayLiteral ( ref v ) => { let first_type = try ! ( self derive_type ( v [ 0 ] ) ) ; for e in v . iter ( ) { let et = try ! ( self derive_type ( e ) ) ; if first_type != et { return Err ( format ! ( " " ) ) ; } } Ok ( Type :: Array ( Box :: new ( first_type ) ) ) } // A unary expression (such as -x or !x) Expression :: Unary ( ref op , ref expr ) => { let expr_type = try ! ( self derive_type ( expr ) ) ; match * op { UnaryOp :: Neg => { match expr_type { Type :: Int => Ok ( expr_type ) , _ => Err ( format ! ( " " op expr_type ) ) } } } } , // A binary expression (such as +, *, /, etc) Expression :: Binary ( ref op , ref lhs , ref rhs ) => { let t1 = try ! ( self derive_type ( lhs ) ) ; let t2 = try ! ( self derive_type ( rhs ) ) ; // If the types of the lhs and the rhs match, then check to ensure the types make // sense for the respective operators if t1 == t2 { match * op { // Arithmetic operators require an int type BinaryOp :: Add | BinaryOp :: Sub | BinaryOp :: Mul | BinaryOp :: Div | BinaryOp :: Mod => { match t1 { Type :: Int => Ok ( t1 ) , _ => Err ( format ! ( " " op t1 ) ) } } } } else { Err ( format ! ( " " op t1 t2 ) ) } } } }
Given an expression, derive it's final type.
Given an expression derive it ' s final type .
&self
expr
&Expression
&self
expr
&Expression