1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
use uuid::Uuid;

#[derive(Debug, PartialEq, Clone)]
pub struct Expr<'c> {
    pub line: usize,
    pub value: ExprValue<'c>,
}

impl<'c> Expr<'c> {
    pub fn new_at<'r>(value: ExprValue<'r>, line: usize) -> Expr<'r> {
        Expr {
            line: line,
            value: value
        }
    }

    pub fn new_array<'r>(value: Vec<Expr<'r>>, line: usize) -> Expr<'r> {
        Expr::new_at(ExprValue::Array(value), line)
    }

    pub fn new_hash<'r>(value: Vec<(Expr<'r>, Expr<'r>)>, line: usize) -> Expr<'r> {
        Expr::new_at(ExprValue::Hash(value), line)
    }

    pub fn new_str_constant<'r>(value: &'r str, line: usize) -> Expr<'r> {
        Expr::new_at(ExprValue::Constant(ExprConstant::Str(value)), line)
    }

    pub fn new_int_constant<'r>(value: i64, line: usize) -> Expr<'r> {
        Expr::new_at(ExprValue::Constant(ExprConstant::Int(value)), line)
    }

    pub fn new_bool<'r>(value: bool, line: usize) -> Expr<'r> {
        Expr::new_at(ExprValue::Constant(ExprConstant::Bool(value)), line)
    }

    pub fn new_null<'r>(line: usize) -> Expr<'r> {
        Expr::new_at(ExprValue::Constant(ExprConstant::Null), line)
    }

    pub fn new_name<'r>(name: &'r str, line: usize) -> Expr<'r> {
        Expr::new_at(ExprValue::Name(name), line)
    }

    pub fn is_constant(&self) -> bool {
        match self.value {
            ExprValue::Array(ref items) => items.iter().all(|i| i.is_constant()),
            ExprValue::AssignName(_) => false,
            ExprValue::BinaryOperator { .. } => false,
            ExprValue::Concat { .. } => false,
            ExprValue::Conditional { .. } => false,
            ExprValue::Constant(_) => true,
            ExprValue::Name(_) => false,
            ExprValue::UnaryOperator { value: "-", ref expr } => expr.is_constant(),
            ExprValue::UnaryOperator { value: "+", ref expr } => expr.is_constant(),
            ExprValue::UnaryOperator { .. } => false,
            ExprValue::Hash(ref items) => items.iter().all(|&(ref k, ref v)| k.is_constant() && v.is_constant()),
            ExprValue::GetAttr { .. } => false,
            ExprValue::ImportedFunctionCall { .. } => false,
            ExprValue::FunctionCall { .. } => false,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum ExprConstant<'c> {
    Str(&'c str),
    Bool(bool),
    Int(i64),
    Float(f64),
    Big(&'c str),
    Null,
}

#[derive(Debug, PartialEq, Clone)]
pub enum ExprValue<'c> {
    Constant(ExprConstant<'c>),
    Name(&'c str),
    AssignName(&'c str),
    Array(Vec<Expr<'c>>),
    Hash(Vec<(Expr<'c>, Expr<'c>)>),
    UnaryOperator { value: &'c str, expr: Box<Expr<'c>> },
    BinaryOperator { value: &'c str, left: Box<Expr<'c>>, right: Box<Expr<'c>> },
    Concat { left: Box<Expr<'c>>, right: Box<Expr<'c>> },
    Conditional { expr: Box<Expr<'c>>, yay: Box<Expr<'c>>, nay: Box<Expr<'c>> },
    GetAttr {
        node: Box<Expr<'c>>,
        arg: Box<Expr<'c>>,
        arguments: Vec<Expr<'c>>,
        call_type: ExprCallType
    },
    ImportedFunctionCall { uuid: Uuid, alias: &'c str, arguments: Vec<Expr<'c>> },
    FunctionCall { name: &'c str, arguments: Vec<(Option<&'c str>, Expr<'c>)> }
}

#[derive(Debug, PartialEq, Clone)]
pub enum ExprCallType {
    Any,
    Method,
    Array,
}