value_expr/
valuer.rs

1use super::data::*;
2
3pub trait Valued<T: ?Sized> {
4    fn to_i32(&self, ctx: &mut T) -> i32;
5}
6pub trait Context {
7    fn call(&mut self, func: &str, values: &Vec<Value>) -> i32;
8    fn ident_get(&self, ident: &str) -> i32;
9    fn ident_set(&mut self, ident: &str, value: i32);
10    fn call_native(&mut self, _func: &str) -> i32 {
11        unreachable!()
12    }
13}
14macro_rules! i2b {
15    ($expr:expr) => {
16        $expr > 0
17    };
18}
19macro_rules! b2i {
20    ($expr:expr) => {
21        if $expr {
22            1
23        } else {
24            0
25        }
26    };
27}
28impl UnOp {
29    pub fn to_i32<T: Context, V: Valued<T>>(&self, ctx: &mut T, value: V) -> i32 {
30        match self {
31            UnOp::Not => b2i!(!i2b!(value.to_i32(ctx))),
32            UnOp::Neg => -value.to_i32(ctx),
33        }
34    }
35}
36
37impl BinOp {
38    pub fn to_i32<T: Context, V: Valued<T>>(&self, ctx: &mut T, left: V, right: V) -> i32 {
39        match self {
40            BinOp::Add => left.to_i32(ctx) + right.to_i32(ctx),
41            BinOp::Sub => left.to_i32(ctx) - right.to_i32(ctx),
42            BinOp::Mul => left.to_i32(ctx) * right.to_i32(ctx),
43            BinOp::Div => left.to_i32(ctx) / right.to_i32(ctx),
44            BinOp::Rem => left.to_i32(ctx) % right.to_i32(ctx),
45            BinOp::BitXor => left.to_i32(ctx) ^ right.to_i32(ctx),
46            BinOp::BitAnd => left.to_i32(ctx) & right.to_i32(ctx),
47            BinOp::BitOr => left.to_i32(ctx) | right.to_i32(ctx),
48            BinOp::Shl => left.to_i32(ctx) << right.to_i32(ctx),
49            BinOp::Shr => left.to_i32(ctx) >> right.to_i32(ctx),
50            BinOp::And => b2i!(i2b!(left.to_i32(ctx)) && i2b!(right.to_i32(ctx))),
51            BinOp::Or => b2i!(i2b!(left.to_i32(ctx)) || i2b!(right.to_i32(ctx))),
52            BinOp::Eq => b2i!(left.to_i32(ctx) == right.to_i32(ctx)),
53            BinOp::Lt => b2i!(left.to_i32(ctx) < right.to_i32(ctx)),
54            BinOp::Le => b2i!(left.to_i32(ctx) <= right.to_i32(ctx)),
55            BinOp::Ne => b2i!(left.to_i32(ctx) != right.to_i32(ctx)),
56            BinOp::Ge => b2i!(left.to_i32(ctx) >= right.to_i32(ctx)),
57            BinOp::Gt => b2i!(left.to_i32(ctx) > right.to_i32(ctx)),
58        }
59    }
60}
61
62impl AssignOp {
63    pub fn to_i32<T: Context, V: Valued<T>>(&self, ctx: &mut T, ident: &str, value: V) -> i32 {
64        let v = match self {
65            AssignOp::Assign => value.to_i32(ctx),
66            AssignOp::AddAssign => ctx.ident_get(ident) + value.to_i32(ctx),
67            AssignOp::SubAssign => ctx.ident_get(ident) - value.to_i32(ctx),
68            AssignOp::MulAssign => ctx.ident_get(ident) * value.to_i32(ctx),
69            AssignOp::DivAssign => ctx.ident_get(ident) / value.to_i32(ctx),
70            AssignOp::RemAssign => ctx.ident_get(ident) % value.to_i32(ctx),
71            AssignOp::BitXorAssign => ctx.ident_get(ident) ^ value.to_i32(ctx),
72            AssignOp::BitAndAssign => ctx.ident_get(ident) & value.to_i32(ctx),
73            AssignOp::BitOrAssign => ctx.ident_get(ident) | value.to_i32(ctx),
74            AssignOp::ShlAssign => ctx.ident_get(ident) << value.to_i32(ctx),
75            AssignOp::ShrAssign => ctx.ident_get(ident) >> value.to_i32(ctx),
76        };
77        ctx.ident_set(ident, v);
78        v
79    }
80}
81
82impl<T: Context, V: Valued<T>> Valued<T> for [V] {
83    fn to_i32(&self, ctx: &mut T) -> i32 {
84        let mut last = 0;
85        for value in self.iter() {
86            last = value.to_i32(ctx);
87        }
88        last
89    }
90}
91
92impl<T: Context> Valued<T> for Value {
93    fn to_i32(&self, ctx: &mut T) -> i32 {
94        match self {
95            Value::Integer(v) => *v,
96            Value::Unary(op, v) => op.to_i32(ctx, v),
97            Value::Binary(op, l, r) => op.to_i32(ctx, l, r),
98            Value::Paren(v) => v.to_i32(ctx),
99            Value::FuncLike(v, args) => ctx.call(v, args),
100            Value::Ident(ident) => ctx.ident_get(ident),
101            Value::Assign(op, ident, v) => op.to_i32(ctx, ident, v),
102            Value::Native(v) => ctx.call_native(v),
103        }
104    }
105}
106
107impl<T: Context> Valued<T> for &Box<Value> {
108    fn to_i32(&self, ctx: &mut T) -> i32 {
109        self.as_ref().to_i32(ctx)
110    }
111}
112
113pub(crate) use {b2i, i2b};
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test() {
120        struct C;
121        impl Context for C {
122            fn call(&mut self, func: &str, values: &Vec<Value>) -> i32 {
123                match func {
124                    "add" => {
125                        let args: Vec<_> = values.iter().map(|e| e.to_i32(self)).collect();
126                        args[0] + args[1]
127                    }
128                    &_ => {
129                        unreachable!()
130                    }
131                }
132            }
133
134            fn ident_get(&self, _ident: &str) -> i32 {
135                unreachable!()
136            }
137
138            fn ident_set(&mut self, _ident: &str, _value: i32) {
139                unreachable!()
140            }
141        }
142        impl C {
143            fn test(&mut self, str: &str) -> i32 {
144                Value::parse_str(str).unwrap().to_i32(self)
145            }
146        }
147        let mut c = C {};
148        let ctx = &mut c;
149        assert_eq!(ctx.test("1+1"), 2);
150        assert_eq!(ctx.test("add(1,2*5)"), 11);
151    }
152}