1use crate::interpreter::InterpErr;
20use alloc::vec::Vec;
21
22#[cfg(feature = "compiler")]
23pub use compiler::*;
24
25const OP_TYPE_MASK: u8 = 0b0010_0000;
27const OP_INVERT_MASK: u8 = 0b0001_0000;
28const OP_LOAD_MASK: u8 = 0b0000_1000;
29const OP_CONJ_MASK: u8 = 0b0000_1111;
30const OP_COMP_MASK: u8 = 0b0000_0111;
31
32const INDEX_LHS_MASK: u8 = 0b1111_0000;
33const INDEX_RHS_MASK: u8 = 0b0000_1111;
34
35const INDEX_LHS_SHIFT: usize = 4;
36const INDEX_RHS_SHIFT: usize = 0;
37
38#[derive(Clone, Copy, PartialEq)]
41pub enum LoadSource {
42 Input,
43 DataTable,
44}
45
46pub struct SubjectSource {
48 pub load_source: LoadSource,
49 pub index: u8,
50}
51
52#[cfg_attr(feature = "std", derive(Debug))]
54#[derive(Clone, Copy, PartialEq)]
55pub enum OpCode {
56 COMP(Comparator),
57 CONJ(Conjunction),
58}
59
60#[cfg_attr(feature = "std", derive(Debug))]
62#[derive(Clone, Copy, PartialEq)]
63pub struct Comparator {
64 pub load: OpLoad,
65 pub op: OpComp,
66 pub indices: OpIndices,
67 pub invert: bool,
68}
69
70#[cfg_attr(feature = "std", derive(Debug))]
72#[derive(Clone, Copy, PartialEq)]
73pub struct Conjunction {
74 pub op: OpConj,
75 pub invert: bool,
76}
77
78#[cfg_attr(feature = "std", derive(Debug))]
80#[derive(Clone, Copy, PartialEq)]
81pub struct OpIndices {
82 pub lhs: u8,
83 pub rhs: u8,
84}
85
86#[allow(non_camel_case_types)]
89#[cfg_attr(feature = "std", derive(Debug))]
90#[derive(Clone, Copy, PartialEq)]
91pub enum OpLoad {
92 INPUT_VS_USER,
93 INPUT_VS_INPUT,
94}
95
96impl From<u8> for OpLoad {
97 fn from(value: u8) -> Self {
98 match value {
99 0 => Self::INPUT_VS_USER,
100 1 => Self::INPUT_VS_INPUT,
101 _ => Self::INPUT_VS_USER,
102 }
103 }
104}
105
106#[allow(non_camel_case_types)]
108#[cfg_attr(feature = "std", derive(Debug))]
109#[derive(Clone, Copy, PartialEq)]
110pub enum OpComp {
111 EQ,
112 GT,
113 GTE,
114 IN,
115}
116
117impl From<u8> for OpComp {
118 fn from(value: u8) -> Self {
119 match value {
120 0 => Self::EQ,
121 1 => Self::GT,
122 2 => Self::GTE,
123 3 => Self::IN,
124 _ => Self::EQ,
125 }
126 }
127}
128
129#[allow(non_camel_case_types)]
131#[cfg_attr(feature = "std", derive(Debug))]
132#[derive(Clone, Copy, PartialEq)]
133pub enum OpConj {
134 AND,
135 OR,
136 XOR,
137}
138
139impl From<u8> for OpConj {
140 fn from(value: u8) -> Self {
141 match value {
142 0 => Self::AND,
143 1 => Self::OR,
144 2 => Self::XOR,
145 _ => Self::AND,
146 }
147 }
148}
149
150impl OpCode {
151 pub fn compile(self, stream: &mut Vec<u8>) {
153 stream.push(self.into());
154 match self {
155 OpCode::COMP(comparator) => stream.push(comparator.indices.into()),
156 _ => {}
157 };
158 }
159
160 pub fn parse(stream: &mut dyn Iterator<Item = &u8>) -> Result<Option<Self>, InterpErr> {
162 let op_index = stream.next();
163 if op_index.is_none() {
164 return Ok(None);
166 }
167
168 let index = op_index.unwrap();
169
170 let invert = (index & OP_INVERT_MASK) == OP_INVERT_MASK;
172
173 match index & OP_TYPE_MASK {
175 0 => {
176 let load = match index & OP_LOAD_MASK {
179 0 => OpLoad::INPUT_VS_USER,
180 _ => OpLoad::INPUT_VS_INPUT,
181 };
182 let op = match index & OP_COMP_MASK {
184 0 => OpComp::EQ,
185 1 => OpComp::GT,
186 2 => OpComp::GTE,
187 3 => OpComp::IN,
188 _ => return Err(InterpErr::InvalidOpCode(*index)),
189 };
190 let indices = if let Some(i) = stream.next() {
192 Ok(*i)
193 } else {
194 Err(InterpErr::UnexpectedEOI("expected index"))
195 }?;
196
197 Ok(Some(OpCode::COMP(Comparator {
199 load: load,
200 op: op,
201 indices: OpIndices {
202 lhs: (indices & INDEX_LHS_MASK) >> INDEX_LHS_SHIFT,
203 rhs: (indices & INDEX_RHS_MASK) >> INDEX_RHS_SHIFT,
204 },
205 invert: invert,
206 })))
207 }
208 _ => {
209 let op = match index & OP_CONJ_MASK {
211 0 => OpConj::AND,
212 1 => OpConj::OR,
213 2 => OpConj::XOR,
214 _ => return Err(InterpErr::InvalidOpCode(*index)),
215 };
216 Ok(Some(OpCode::CONJ(Conjunction {
218 op: op,
219 invert: invert,
220 })))
221 }
222 }
223 }
224}
225
226impl Comparator {
227 pub fn new(op: OpComp) -> Self {
229 Comparator {
230 load: OpLoad::INPUT_VS_USER,
231 op: op,
232 indices: OpIndices { lhs: 0, rhs: 0 },
233 invert: false,
234 }
235 }
236
237 pub fn load(mut self, load: OpLoad) -> Self {
239 self.load = load;
240 self
241 }
242
243 pub fn indices(mut self, lhs: u8, rhs: u8) -> Self {
245 self.indices.lhs = lhs;
246 self.indices.rhs = rhs;
247 self
248 }
249
250 pub fn invert(mut self) -> Self {
252 self.invert = true;
253 self
254 }
255
256 pub fn loads_from_subjects(mut self, lhs: SubjectSource, rhs: SubjectSource) -> Self {
260 let (load, flip) = match (lhs.load_source, rhs.load_source) {
262 (LoadSource::Input, LoadSource::Input) => (OpLoad::INPUT_VS_INPUT, false),
263 (LoadSource::Input, LoadSource::DataTable) => (OpLoad::INPUT_VS_USER, false),
264 (LoadSource::DataTable, LoadSource::Input) => (OpLoad::INPUT_VS_USER, true),
265 (_, _) => (OpLoad::INPUT_VS_USER, true), };
267
268 self = self.load(load).indices(lhs.index, rhs.index);
270
271 if flip {
273 self.flip_indices()
274 } else {
275 self
276 }
277 }
278
279 pub fn flip_indices(mut self) -> Self {
282 self.indices = OpIndices {
283 lhs: self.indices.rhs,
284 rhs: self.indices.lhs,
285 };
286 let (op, invert) = match self.op {
287 OpComp::EQ => (self.op, self.invert),
288 OpComp::IN => (self.op, self.invert),
289 OpComp::GT => (OpComp::GTE, !self.invert),
290 OpComp::GTE => (OpComp::GT, !self.invert),
291 };
292 self.op = op;
293 self.invert = invert;
294 self
295 }
296}
297
298impl Conjunction {
299 pub fn new(op: OpConj) -> Self {
301 Conjunction {
302 op: op,
303 invert: false,
304 }
305 }
306
307 pub fn invert(mut self) -> Self {
309 self.invert = true;
310 self
311 }
312}
313
314#[cfg(feature = "compiler")]
316mod compiler {
317 use super::*;
318 use crate::parser::ast;
319 use core::convert::From;
320
321 impl Comparator {
322 pub fn apply_imperative(mut self, imperative: &ast::Imperative) -> Self {
324 match imperative {
325 ast::Imperative::MustBe => {}
326 ast::Imperative::MustNotBe => self.invert = !self.invert,
327 };
328 self
329 }
330 }
331
332 impl From<&ast::Comparator> for Comparator {
333 fn from(comparator: &ast::Comparator) -> Self {
335 match comparator {
336 ast::Comparator::Equal => Comparator::new(OpComp::EQ),
337 ast::Comparator::GreaterThan => Comparator::new(OpComp::GT),
338 ast::Comparator::GreaterThanOrEqual => Comparator::new(OpComp::GTE),
339 ast::Comparator::LessThan => Comparator::new(OpComp::GTE).invert(),
340 ast::Comparator::LessThanOrEqual => Comparator::new(OpComp::GT).invert(),
341 ast::Comparator::OneOf => Comparator::new(OpComp::IN),
342 }
343 }
344 }
345
346 impl From<&ast::Conjunctive> for Conjunction {
347 fn from(conjunctive: &ast::Conjunctive) -> Self {
349 match conjunctive {
350 ast::Conjunctive::And => Conjunction::new(OpConj::AND),
351 ast::Conjunctive::Or => Conjunction::new(OpConj::OR),
352 }
353 }
354 }
355}
356
357impl Into<u8> for OpLoad {
358 fn into(self) -> u8 {
359 match self {
360 OpLoad::INPUT_VS_USER => 0,
361 OpLoad::INPUT_VS_INPUT => OP_LOAD_MASK,
362 }
363 }
364}
365
366impl Into<u8> for OpComp {
367 fn into(self) -> u8 {
368 match self {
369 OpComp::EQ => 0,
370 OpComp::GT => 1,
371 OpComp::GTE => 2,
372 OpComp::IN => 3,
373 }
374 }
375}
376
377impl Into<u8> for OpConj {
378 fn into(self) -> u8 {
379 match self {
380 OpConj::AND => 0,
381 OpConj::OR => 1,
382 OpConj::XOR => 2,
383 }
384 }
385}
386
387impl Into<u8> for OpIndices {
388 fn into(self) -> u8 {
389 (self.lhs << INDEX_LHS_SHIFT) & INDEX_LHS_MASK
390 | (self.rhs << INDEX_RHS_SHIFT) & INDEX_RHS_MASK
391 }
392}
393
394impl Into<u8> for OpCode {
396 fn into(self) -> u8 {
397 match self {
398 OpCode::COMP(comp) => {
399 let invert_u8: u8 = if comp.invert { OP_INVERT_MASK } else { 0 };
400 let load_u8: u8 = comp.load.into();
401 let comp_u8: u8 = comp.op.into();
402 invert_u8 | load_u8 | comp_u8
403 }
404 OpCode::CONJ(conj) => {
405 let invert_u8: u8 = if conj.invert { OP_INVERT_MASK } else { 0 };
406 let conj_u8: u8 = conj.op.into();
407 OP_TYPE_MASK | invert_u8 | conj_u8
408 }
409 }
410 }
411}
412
413#[cfg(test)]
414mod test {
415 use super::*;
416
417 #[test]
418 fn compile_comparators_basic() {
419 let mut bytes = Vec::<u8>::default();
420 OpCode::COMP(Comparator::new(OpComp::EQ)).compile(&mut bytes);
421 OpCode::COMP(Comparator::new(OpComp::GT)).compile(&mut bytes);
422 OpCode::COMP(Comparator::new(OpComp::GTE)).compile(&mut bytes);
423 OpCode::COMP(Comparator::new(OpComp::IN)).compile(&mut bytes);
424 assert_eq!(bytes, vec![0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00,]);
425 }
426
427 #[test]
428 fn compile_conjunctions_basic() {
429 let mut bytes = Vec::<u8>::default();
430 OpCode::CONJ(Conjunction::new(OpConj::AND)).compile(&mut bytes);
431 OpCode::CONJ(Conjunction::new(OpConj::OR)).compile(&mut bytes);
432 OpCode::CONJ(Conjunction::new(OpConj::XOR)).compile(&mut bytes);
433 assert_eq!(bytes, vec![0x20, 0x21, 0x22,]);
434 }
435
436 #[test]
437 fn compile_comparator_advanced() {
438 let mut bytes = Vec::<u8>::default();
439 OpCode::COMP(
440 Comparator::new(OpComp::EQ)
441 .load(OpLoad::INPUT_VS_INPUT)
442 .invert()
443 .indices(11, 3),
444 )
445 .compile(&mut bytes);
446 assert_eq!(bytes, vec![0x18, 0xb3]);
447 }
448
449 #[test]
450 fn compile_conjunction_advanced() {
451 let mut bytes = Vec::<u8>::default();
452 OpCode::CONJ(Conjunction::new(OpConj::OR).invert()).compile(&mut bytes);
453 assert_eq!(bytes, vec![0x31]);
454 }
455
456 #[test]
457 fn parse_comparator_basic() {
458 let mut stream = [0x00_u8, 0x00_u8].iter();
459 let op_code = OpCode::parse(&mut stream).unwrap();
460 assert_eq!(op_code, Some(OpCode::COMP(Comparator::new(OpComp::EQ))));
461 }
462
463 #[test]
464 fn parse_comparator_gt() {
465 let mut stream = [0x01_u8, 0x00_u8].iter();
466 let op_code = OpCode::parse(&mut stream).unwrap();
467 assert_eq!(op_code, Some(OpCode::COMP(Comparator::new(OpComp::GT))));
468 }
469
470 #[test]
471 fn parse_comparator_indicies() {
472 let mut stream = [0x00_u8, 0x5c_u8].iter();
473 let op_code = OpCode::parse(&mut stream).unwrap();
474 assert_eq!(
475 op_code,
476 Some(OpCode::COMP(Comparator::new(OpComp::EQ).indices(5, 12)))
477 );
478 }
479
480 #[test]
481 fn parse_comparator_advanced() {
482 let mut stream = [0x18_u8, 0x27_u8].iter();
483 let op_code = OpCode::parse(&mut stream).unwrap();
484 assert_eq!(
485 op_code,
486 Some(OpCode::COMP(
487 Comparator::new(OpComp::EQ)
488 .invert()
489 .load(OpLoad::INPUT_VS_INPUT)
490 .indices(2, 7)
491 ))
492 );
493 }
494
495 #[test]
496 fn parse_comparator_invalid() {
497 let mut stream = [0x07_u8, 0x00_u8].iter();
498 assert_eq!(
499 OpCode::parse(&mut stream),
500 Err(InterpErr::InvalidOpCode(0x07))
501 );
502 }
503
504 #[test]
505 fn parse_comparator_missing_indices() {
506 let mut stream = [0x00_u8].iter();
507 assert_eq!(
508 OpCode::parse(&mut stream),
509 Err(InterpErr::UnexpectedEOI("expected index"))
510 );
511 }
512
513 #[test]
514 fn parse_conjunction_basic() {
515 let mut stream = [0x20_u8].iter();
516 let op_code = OpCode::parse(&mut stream).unwrap();
517 assert_eq!(op_code, Some(OpCode::CONJ(Conjunction::new(OpConj::AND))));
518 }
519
520 #[test]
521 fn parse_conjunction_xor() {
522 let mut stream = [0x22_u8].iter();
523 let op_code = OpCode::parse(&mut stream).unwrap();
524 assert_eq!(op_code, Some(OpCode::CONJ(Conjunction::new(OpConj::XOR))));
525 }
526
527 #[test]
528 fn parse_conjunction_advanced() {
529 let mut stream = [0x31_u8].iter();
530 assert_eq!(
531 OpCode::parse(&mut stream).unwrap(),
532 Some(OpCode::CONJ(Conjunction::new(OpConj::OR).invert()))
533 );
534 }
535
536 #[test]
537 fn parse_conjunction_invalid() {
538 let mut stream = [0x2f_u8].iter();
539 assert_eq!(
540 OpCode::parse(&mut stream),
541 Err(InterpErr::InvalidOpCode(0x2f))
542 );
543 }
544}