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}