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