1use crate::bytecode_encoder::encode_v1::encode_symbol;
6use crate::compiler::instruction::{InstructionDebug, RawAstLocation};
7use crate::compiler::{
8 self, BindRules, Symbol, SymbolTable, SymbolicInstruction, SymbolicInstructionInfo,
9};
10use crate::debugger::device_specification::{DeviceSpecification, Property};
11use crate::errors::UserError;
12use crate::parser::bind_rules::{Condition, ConditionOp, Statement};
13use crate::parser::common::{BindParserError, CompoundIdentifier, Span, Value};
14use std::collections::{HashMap, HashSet};
15use std::fmt;
16use std::str::FromStr;
17use thiserror::Error;
18
19#[derive(Debug, Error, Clone, PartialEq)]
20pub enum DebuggerError {
21 ParserError(BindParserError),
22 CompilerError(compiler::CompilerError),
23 DuplicateKey(CompoundIdentifier),
24 MissingLabel,
25 NoOutcome,
26 IncorrectAstLocation,
27 InvalidAstLocation,
28 UnknownKey(CompoundIdentifier),
29 InvalidValueSymbol(Symbol),
30}
31
32impl fmt::Display for DebuggerError {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 write!(f, "{}", UserError::from(self.clone()))
35 }
36}
37
38type DevicePropertyMap = HashMap<Symbol, DeviceValue>;
39
40#[derive(Debug, PartialEq)]
41struct DeviceValue {
42 symbol: Option<Symbol>,
43 identifier: Option<CompoundIdentifier>,
44}
45
46#[derive(Debug, Clone, PartialEq)]
47pub enum AstLocation<'a> {
48 ConditionStatement(Statement<'a>),
49 AcceptStatementValue { identifier: CompoundIdentifier, value: Value, span: Span<'a> },
50 AcceptStatementFailure { identifier: CompoundIdentifier, symbol: Symbol, span: Span<'a> },
51 IfCondition(Condition<'a>),
52 FalseStatement(Statement<'a>),
53}
54
55impl<'a> AstLocation<'a> {
56 pub fn to_instruction_debug(self) -> InstructionDebug {
57 match self {
58 AstLocation::ConditionStatement(statement) => InstructionDebug {
59 line: statement.get_span().line,
60 ast_location: RawAstLocation::ConditionStatement,
61 extra: 0,
62 },
63 AstLocation::AcceptStatementValue { span, .. } => InstructionDebug {
64 line: span.line,
65 ast_location: RawAstLocation::AcceptStatementValue,
66 extra: 0,
67 },
68 AstLocation::AcceptStatementFailure { span, symbol, .. } => InstructionDebug {
69 line: span.line,
70 ast_location: RawAstLocation::AcceptStatementFailure,
71 extra: encode_symbol(symbol).unwrap_or(0),
72 },
73 AstLocation::IfCondition(condition) => InstructionDebug {
74 line: condition.span.line,
75 ast_location: RawAstLocation::IfCondition,
76 extra: 0,
77 },
78 AstLocation::FalseStatement(statement) => InstructionDebug {
79 line: statement.get_span().line,
80 ast_location: RawAstLocation::FalseStatement,
81 extra: 0,
82 },
83 }
84 }
85}
86
87#[derive(Debug, PartialEq)]
88enum DebuggerOutput<'a> {
89 ConditionStatement {
90 statement: &'a Statement<'a>,
91 success: bool,
92 },
93 FalseStatement {
94 statement: &'a Statement<'a>,
95 },
96 AcceptStatementSuccess {
97 identifier: &'a CompoundIdentifier,
98 value: &'a Value,
99 value_symbol: &'a Symbol,
100 span: &'a Span<'a>,
101 },
102 AcceptStatementFailure {
103 identifier: &'a CompoundIdentifier,
104 span: &'a Span<'a>,
105 },
106 IfCondition {
107 condition: &'a Condition<'a>,
108 success: bool,
109 },
110}
111
112pub fn debug_from_str<'a>(
113 bind_rules: &BindRules,
114 device_file: &str,
115) -> Result<bool, DebuggerError> {
116 let device_specification =
117 DeviceSpecification::from_str(device_file).map_err(DebuggerError::ParserError)?;
118
119 debug_from_device_specification(
120 &bind_rules.symbol_table,
121 &bind_rules.instructions,
122 device_specification,
123 )
124}
125
126pub fn debug_from_device_specification<'a>(
127 symbol_table: &SymbolTable,
128 instructions: &Vec<SymbolicInstructionInfo<'a>>,
129 device_specification: DeviceSpecification,
130) -> Result<bool, DebuggerError> {
131 let mut debugger = Debugger::new(&device_specification.properties, symbol_table, instructions)?;
132 let binds = debugger.evaluate_bind_rules()?;
133 debugger.log_output()?;
134 Ok(binds)
135}
136
137struct Debugger<'a> {
138 device_properties: DevicePropertyMap,
139 symbol_table: &'a SymbolTable,
140 instructions: &'a Vec<SymbolicInstructionInfo<'a>>,
141 output: Vec<DebuggerOutput<'a>>,
142}
143
144impl<'a> Debugger<'a> {
145 fn new(
146 properties: &[Property],
147 symbol_table: &'a SymbolTable,
148 instructions: &'a Vec<SymbolicInstructionInfo<'a>>,
149 ) -> Result<Self, DebuggerError> {
150 let device_properties = Debugger::construct_property_map(properties, &symbol_table)?;
151 let output = Vec::new();
152 Ok(Debugger { device_properties, symbol_table, instructions, output })
153 }
154
155 fn construct_property_map(
164 properties: &[Property],
165 symbol_table: &SymbolTable,
166 ) -> Result<DevicePropertyMap, DebuggerError> {
167 let mut property_map = HashMap::new();
168 let mut keys_seen = HashSet::new();
169
170 for Property { key, value } in properties {
171 if keys_seen.contains(key) {
174 return Err(DebuggerError::DuplicateKey(key.clone()));
175 }
176 keys_seen.insert(key.clone());
177
178 if let Some(key_symbol) = symbol_table.get(key) {
179 let device_value = match value {
180 Value::NumericLiteral(n) => {
181 DeviceValue { symbol: Some(Symbol::NumberValue(*n)), identifier: None }
182 }
183 Value::StringLiteral(s) => DeviceValue {
184 symbol: Some(Symbol::StringValue(s.to_string())),
185 identifier: None,
186 },
187 Value::BoolLiteral(b) => {
188 DeviceValue { symbol: Some(Symbol::BoolValue(*b)), identifier: None }
189 }
190 Value::Identifier(identifier) => match symbol_table.get(identifier) {
191 Some(symbol) => DeviceValue {
192 symbol: Some(symbol.clone()),
193 identifier: Some(identifier.clone()),
194 },
195 None => DeviceValue { symbol: None, identifier: Some(identifier.clone()) },
196 },
197 };
198
199 property_map.insert(key_symbol.clone(), device_value);
200 }
201 }
202
203 Ok(property_map)
204 }
205
206 fn evaluate_bind_rules(&mut self) -> Result<bool, DebuggerError> {
207 let mut instructions = self.instructions.iter();
208
209 while let Some(mut instruction) = instructions.next() {
210 let mut jump_label = None;
211
212 match &instruction.instruction {
213 SymbolicInstruction::AbortIfEqual { lhs, rhs } => {
214 let aborts = self.device_property_matches(lhs, rhs);
215 self.output_abort_if(&instruction.location, aborts)?;
216 if aborts {
217 return Ok(false);
218 }
219 }
220 SymbolicInstruction::AbortIfNotEqual { lhs, rhs } => {
221 let aborts = !self.device_property_matches(lhs, rhs);
222 self.output_abort_if(&instruction.location, aborts)?;
223 if aborts {
224 return Ok(false);
225 }
226 }
227 SymbolicInstruction::Label(_label) => (),
228 SymbolicInstruction::UnconditionalJump { label } => {
229 jump_label = Some(label);
230 }
231 SymbolicInstruction::JumpIfEqual { lhs, rhs, label } => {
232 let jump_succeeds = self.device_property_matches(lhs, rhs);
233 self.output_jump_if_equal(&instruction.location, rhs, jump_succeeds)?;
234 if jump_succeeds {
235 jump_label = Some(label);
236 }
237 }
238 SymbolicInstruction::JumpIfNotEqual { lhs, rhs, label } => {
239 let jump_succeeds = !self.device_property_matches(lhs, rhs);
240 self.output_jump_if_not_equal(&instruction.location, jump_succeeds)?;
241 if jump_succeeds {
242 jump_label = Some(label);
243 }
244 }
245 SymbolicInstruction::UnconditionalAbort => {
246 self.output_unconditional_abort(&instruction.location)?;
247 return Ok(false);
248 }
249 SymbolicInstruction::UnconditionalBind => return Ok(true),
250 }
251
252 if let Some(label) = jump_label {
253 while instruction.instruction != SymbolicInstruction::Label(*label) {
254 instruction = instructions.next().ok_or(DebuggerError::MissingLabel)?;
255 }
256 }
257 }
258
259 Err(DebuggerError::NoOutcome)
260 }
261
262 fn device_property_matches(&self, lhs: &Symbol, rhs: &Symbol) -> bool {
263 if let Some(DeviceValue { symbol: Some(value_symbol), identifier: _ }) =
264 self.device_properties.get(lhs)
265 {
266 value_symbol == rhs
267 } else {
268 false
269 }
270 }
271
272 fn output_abort_if(
273 &mut self,
274 location: &'a Option<AstLocation>,
275 aborts: bool,
276 ) -> Result<(), DebuggerError> {
277 if let Some(AstLocation::ConditionStatement(statement)) = location {
278 self.output.push(DebuggerOutput::ConditionStatement { statement, success: !aborts });
279 Ok(())
280 } else {
281 Err(DebuggerError::IncorrectAstLocation)
282 }
283 }
284
285 fn output_jump_if_equal(
286 &mut self,
287 location: &'a Option<AstLocation>,
288 rhs: &'a Symbol,
289 jump_succeeds: bool,
290 ) -> Result<(), DebuggerError> {
291 match location {
292 Some(AstLocation::AcceptStatementValue { identifier, value, span }) => {
293 if jump_succeeds {
294 self.output.push(DebuggerOutput::AcceptStatementSuccess {
295 identifier,
296 value,
297 value_symbol: rhs,
298 span,
299 });
300 }
301 Ok(())
302 }
303 Some(AstLocation::IfCondition(condition)) => {
304 self.output
305 .push(DebuggerOutput::IfCondition { condition, success: !jump_succeeds });
306 Ok(())
307 }
308 _ => Err(DebuggerError::IncorrectAstLocation),
309 }
310 }
311
312 fn output_jump_if_not_equal(
313 &mut self,
314 location: &'a Option<AstLocation>,
315 jump_succeeds: bool,
316 ) -> Result<(), DebuggerError> {
317 if let Some(AstLocation::IfCondition(condition)) = location {
318 self.output.push(DebuggerOutput::IfCondition { condition, success: !jump_succeeds });
319 Ok(())
320 } else {
321 Err(DebuggerError::IncorrectAstLocation)
322 }
323 }
324
325 fn output_unconditional_abort(
326 &mut self,
327 location: &'a Option<AstLocation>,
328 ) -> Result<(), DebuggerError> {
329 match location {
330 Some(AstLocation::FalseStatement(statement)) => {
331 self.output.push(DebuggerOutput::FalseStatement { statement });
332 Ok(())
333 }
334 Some(AstLocation::AcceptStatementFailure { identifier, span, symbol: _ }) => {
335 self.output.push(DebuggerOutput::AcceptStatementFailure { identifier, span });
336 Ok(())
337 }
338 _ => Err(DebuggerError::IncorrectAstLocation),
339 }
340 }
341
342 fn log_output(&self) -> Result<(), DebuggerError> {
343 for output in &self.output {
344 match output {
345 DebuggerOutput::ConditionStatement { statement, success } => {
346 self.log_condition_statement(statement, *success)?;
347 }
348 DebuggerOutput::FalseStatement { statement } => self.log_abort_statement(statement),
349 DebuggerOutput::AcceptStatementSuccess {
350 identifier,
351 value,
352 value_symbol,
353 span,
354 } => self.log_accept_statement_success(identifier, value, value_symbol, span)?,
355 DebuggerOutput::AcceptStatementFailure { identifier, span } => {
356 self.log_accept_statement_failure(identifier, span)?;
357 }
358 DebuggerOutput::IfCondition { condition, success } => {
359 self.log_if_condition(condition, *success)?;
360 }
361 }
362 }
363 Ok(())
364 }
365
366 fn log_condition_statement(
367 &self,
368 statement: &Statement,
369 success: bool,
370 ) -> Result<(), DebuggerError> {
371 if let Statement::ConditionStatement { span, condition: Condition { lhs, op, .. } } =
372 statement
373 {
374 let outcome_string = if success { "succeeded" } else { "failed" };
375 println!(
376 "Line {}: Condition statement {}: {}",
377 span.line, outcome_string, span.fragment
378 );
379
380 if condition_needs_actual_value(success, op) {
381 println!("\t{}", self.actual_value_string(lhs)?)
382 }
383
384 Ok(())
385 } else {
386 Err(DebuggerError::InvalidAstLocation)
387 }
388 }
389
390 fn log_abort_statement(&self, statement: &Statement) {
391 if let Statement::False { span } = statement {
392 println!("Line {}: Abort statement reached.", span.line);
393 }
394 }
395
396 fn log_accept_statement_success(
397 &self,
398 identifier: &CompoundIdentifier,
399 value: &Value,
400 value_symbol: &Symbol,
401 span: &Span,
402 ) -> Result<(), DebuggerError> {
403 let value_identifier_prog =
405 if let Value::Identifier(identifier) = value { Some(identifier) } else { None };
406
407 let key_symbol = self
409 .symbol_table
410 .get(identifier)
411 .ok_or_else(|| DebuggerError::UnknownKey(identifier.clone()))?;
412 let DeviceValue { symbol: _, identifier: value_identifier_device } = self
413 .device_properties
414 .get(key_symbol)
415 .expect("Accept statement succeeded so device must have this key.");
416
417 let value_literal = value_symbol_string(value_symbol)?;
418
419 let value_string = match (value_identifier_prog, value_identifier_device) {
420 (Some(identifier_prog), Some(identifier_value)) => {
421 if identifier_prog == identifier_value {
422 format!("`{}` [{}]", identifier_prog, value_literal)
423 } else {
424 format!("`{}` (`{}`) [{}]", identifier_prog, identifier_value, value_literal)
425 }
426 }
427 (Some(identifier_prog), None) => format!("`{}` [{}]", identifier_prog, value_literal),
428 (None, Some(identifier_value)) => format!("`{}` [{}]", identifier_value, value_literal),
429 (None, None) => format!("{}", value_literal),
430 };
431
432 println!(
433 "Line {}: Accept statement succeeded.\n\tValue of `{}` was {}.",
434 span.line, identifier, value_string
435 );
436
437 Ok(())
438 }
439
440 fn log_accept_statement_failure(
441 &self,
442 identifier: &CompoundIdentifier,
443 span: &Span,
444 ) -> Result<(), DebuggerError> {
445 println!(
446 "Line {}: Accept statement failed.\n\t{}",
447 span.line,
448 self.actual_value_string(identifier)?
449 );
450
451 Ok(())
452 }
453
454 fn log_if_condition(&self, condition: &Condition, success: bool) -> Result<(), DebuggerError> {
455 let Condition { span, lhs, op, rhs: _ } = condition;
456
457 let outcome_string = if success { "succeeded" } else { "failed" };
458 println!(
459 "Line {}: If statement condition {}: {}",
460 span.line, outcome_string, span.fragment
461 );
462
463 if condition_needs_actual_value(success, op) {
464 println!("\t{}", self.actual_value_string(lhs)?)
465 }
466
467 Ok(())
468 }
469
470 fn actual_value_string(
471 &self,
472 key_identifier: &CompoundIdentifier,
473 ) -> Result<String, DebuggerError> {
474 let key_symbol = self
475 .symbol_table
476 .get(key_identifier)
477 .ok_or_else(|| DebuggerError::UnknownKey(key_identifier.clone()))?;
478 let DeviceValue { symbol: value_symbol, identifier: value_identifier } = self
479 .device_properties
480 .get(key_symbol)
481 .unwrap_or(&DeviceValue { symbol: None, identifier: None });
482
483 Ok(match (value_symbol, value_identifier) {
484 (Some(symbol), Some(identifier)) => format!(
485 "Actual value of `{}` was `{}` [{}].",
486 key_identifier,
487 identifier,
488 value_symbol_string(symbol)?
489 ),
490 (Some(symbol), None) => format!(
491 "Actual value of `{}` was literal {}.",
492 key_identifier,
493 value_symbol_string(symbol)?
494 ),
495 (None, Some(identifier)) => {
496 format!("Actual value of `{}` was `{}`.", key_identifier, identifier)
497 }
498 (None, None) => format!("Device had no value for `{}`.", key_identifier),
499 })
500 }
501}
502
503fn condition_needs_actual_value(success: bool, op: &ConditionOp) -> bool {
504 match op {
505 ConditionOp::Equals => !success,
506 ConditionOp::NotEquals => success,
507 }
508}
509
510fn value_symbol_string(symbol: &Symbol) -> Result<String, DebuggerError> {
511 match symbol {
512 Symbol::DeprecatedKey(..) => Err(DebuggerError::InvalidValueSymbol(symbol.clone())),
513 Symbol::Key(..) => Err(DebuggerError::InvalidValueSymbol(symbol.clone())),
514 Symbol::NumberValue(n) => Ok(format!("0x{:x}", n)),
515 Symbol::StringValue(s) => Ok(format!("\"{}\"", s)),
516 Symbol::BoolValue(b) => Ok(b.to_string()),
517 Symbol::EnumValue(s) => Ok(format!("\"{}\"", s)),
518 }
519}
520
521#[cfg(test)]
522mod test {
523 use super::*;
524 use crate::make_identifier;
525 use crate::parser::bind_library;
526
527 #[test]
528 fn duplicate_key() {
529 let symbol_table = HashMap::new();
530 let properties = vec![
531 Property { key: make_identifier!("abc"), value: Value::NumericLiteral(42) },
532 Property { key: make_identifier!("abc"), value: Value::NumericLiteral(5) },
533 ];
534 assert_eq!(
535 Debugger::construct_property_map(&properties, &symbol_table),
536 Err(DebuggerError::DuplicateKey(make_identifier!("abc")))
537 );
538 }
539
540 #[test]
541 fn condition_equals() {
542 let statement = Statement::ConditionStatement {
543 span: Span::new(),
544 condition: Condition {
545 span: Span::new(),
546 lhs: make_identifier!("abc"),
547 op: ConditionOp::Equals,
548 rhs: Value::NumericLiteral(42),
549 },
550 };
551 let statements = vec![statement.clone()];
552 let mut symbol_table = HashMap::new();
553 symbol_table.insert(
554 make_identifier!("abc"),
555 Symbol::Key("abc".to_string(), bind_library::ValueType::Number),
556 );
557
558 let instructions = compiler::compile_statements(statements, &symbol_table, false).unwrap();
559
560 let properties =
562 vec![Property { key: make_identifier!("abc"), value: Value::NumericLiteral(42) }];
563 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
564 assert!(debugger.evaluate_bind_rules().unwrap());
565 assert_eq!(
566 debugger.output,
567 vec![DebuggerOutput::ConditionStatement { statement: &statement, success: true }]
568 );
569
570 let properties = vec![
572 Property { key: make_identifier!("abc"), value: Value::NumericLiteral(42) },
573 Property { key: make_identifier!("xyz"), value: Value::BoolLiteral(true) },
574 ];
575 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
576 assert!(debugger.evaluate_bind_rules().unwrap());
577 assert_eq!(
578 debugger.output,
579 vec![DebuggerOutput::ConditionStatement { statement: &statement, success: true }]
580 );
581
582 let properties =
584 vec![Property { key: make_identifier!("abc"), value: Value::NumericLiteral(5) }];
585 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
586 assert!(!debugger.evaluate_bind_rules().unwrap());
587 assert_eq!(
588 debugger.output,
589 vec![DebuggerOutput::ConditionStatement { statement: &statement, success: false }]
590 );
591
592 let properties = Vec::new();
594 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
595 assert!(!debugger.evaluate_bind_rules().unwrap());
596 assert_eq!(
597 debugger.output,
598 vec![DebuggerOutput::ConditionStatement { statement: &statement, success: false }]
599 );
600 }
601
602 #[test]
603 fn condition_not_equals() {
604 let statement = Statement::ConditionStatement {
605 span: Span::new(),
606 condition: Condition {
607 span: Span::new(),
608 lhs: make_identifier!("abc"),
609 op: ConditionOp::NotEquals,
610 rhs: Value::NumericLiteral(42),
611 },
612 };
613 let statements = vec![statement.clone()];
614 let mut symbol_table = HashMap::new();
615 symbol_table.insert(
616 make_identifier!("abc"),
617 Symbol::Key("abc".to_string(), bind_library::ValueType::Number),
618 );
619 let instructions = compiler::compile_statements(statements, &symbol_table, false).unwrap();
620
621 let properties =
623 vec![Property { key: make_identifier!("abc"), value: Value::NumericLiteral(5) }];
624 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
625 assert!(debugger.evaluate_bind_rules().unwrap());
626 assert_eq!(
627 debugger.output,
628 vec![DebuggerOutput::ConditionStatement { statement: &statement, success: true }]
629 );
630
631 let properties = Vec::new();
633 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
634 assert!(debugger.evaluate_bind_rules().unwrap());
635 assert_eq!(
636 debugger.output,
637 vec![DebuggerOutput::ConditionStatement { statement: &statement, success: true }]
638 );
639
640 let properties =
642 vec![Property { key: make_identifier!("abc"), value: Value::NumericLiteral(42) }];
643 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
644 assert!(!debugger.evaluate_bind_rules().unwrap());
645 assert_eq!(
646 debugger.output,
647 vec![DebuggerOutput::ConditionStatement { statement: &statement, success: false }]
648 );
649 }
650
651 #[test]
652 fn accept() {
653 let statements = vec![Statement::Accept {
654 span: Span::new(),
655 identifier: make_identifier!("abc"),
656 values: vec![Value::NumericLiteral(42), Value::NumericLiteral(314)],
657 }];
658 let mut symbol_table = HashMap::new();
659 symbol_table.insert(
660 make_identifier!("abc"),
661 Symbol::Key("abc".to_string(), bind_library::ValueType::Number),
662 );
663
664 let instructions = compiler::compile_statements(statements, &symbol_table, false).unwrap();
665
666 let properties =
668 vec![Property { key: make_identifier!("abc"), value: Value::NumericLiteral(42) }];
669 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
670 assert!(debugger.evaluate_bind_rules().unwrap());
671 assert_eq!(
672 debugger.output,
673 vec![DebuggerOutput::AcceptStatementSuccess {
674 identifier: &make_identifier!("abc"),
675 value: &Value::NumericLiteral(42),
676 value_symbol: &Symbol::NumberValue(42),
677 span: &Span::new(),
678 }]
679 );
680
681 let properties =
683 vec![Property { key: make_identifier!("abc"), value: Value::NumericLiteral(5) }];
684 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
685 assert!(!debugger.evaluate_bind_rules().unwrap());
686 assert_eq!(
687 debugger.output,
688 vec![DebuggerOutput::AcceptStatementFailure {
689 identifier: &make_identifier!("abc"),
690 span: &Span::new(),
691 }]
692 );
693
694 let properties = Vec::new();
696 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
697 assert!(!debugger.evaluate_bind_rules().unwrap());
698 assert_eq!(
699 debugger.output,
700 vec![DebuggerOutput::AcceptStatementFailure {
701 identifier: &make_identifier!("abc"),
702 span: &Span::new(),
703 }]
704 );
705 }
706
707 #[test]
708 fn if_else() {
709 let condition1 = Condition {
720 span: Span::new(),
721 lhs: make_identifier!("abc"),
722 op: ConditionOp::Equals,
723 rhs: Value::NumericLiteral(1),
724 };
725 let condition2 = Condition {
726 span: Span::new(),
727 lhs: make_identifier!("abc"),
728 op: ConditionOp::Equals,
729 rhs: Value::NumericLiteral(2),
730 };
731 let statement1 = Statement::ConditionStatement {
732 span: Span::new(),
733 condition: Condition {
734 span: Span::new(),
735 lhs: make_identifier!("xyz"),
736 op: ConditionOp::Equals,
737 rhs: Value::NumericLiteral(1),
738 },
739 };
740 let statement2 = Statement::ConditionStatement {
741 span: Span::new(),
742 condition: Condition {
743 span: Span::new(),
744 lhs: make_identifier!("xyz"),
745 op: ConditionOp::Equals,
746 rhs: Value::NumericLiteral(2),
747 },
748 };
749 let statement3 = Statement::ConditionStatement {
750 span: Span::new(),
751 condition: Condition {
752 span: Span::new(),
753 lhs: make_identifier!("xyz"),
754 op: ConditionOp::Equals,
755 rhs: Value::NumericLiteral(3),
756 },
757 };
758
759 let statements = vec![Statement::If {
760 span: Span::new(),
761 blocks: vec![
762 (condition1.clone(), vec![statement1.clone()]),
763 (condition2.clone(), vec![statement2.clone()]),
764 ],
765 else_block: vec![statement3.clone()],
766 }];
767 let mut symbol_table = HashMap::new();
768 symbol_table.insert(
769 make_identifier!("abc"),
770 Symbol::Key("abc".to_string(), bind_library::ValueType::Number),
771 );
772 symbol_table.insert(
773 make_identifier!("xyz"),
774 Symbol::Key("xyz".to_string(), bind_library::ValueType::Number),
775 );
776
777 let instructions = compiler::compile_statements(statements, &symbol_table, false).unwrap();
778
779 let properties = vec![
781 Property { key: make_identifier!("abc"), value: Value::NumericLiteral(1) },
782 Property { key: make_identifier!("xyz"), value: Value::NumericLiteral(1) },
783 ];
784 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
785 assert!(debugger.evaluate_bind_rules().unwrap());
786 assert_eq!(
787 debugger.output,
788 vec![
789 DebuggerOutput::IfCondition { condition: &condition1, success: true },
790 DebuggerOutput::ConditionStatement { statement: &statement1, success: true }
791 ]
792 );
793
794 let properties = vec![
796 Property { key: make_identifier!("abc"), value: Value::NumericLiteral(2) },
797 Property { key: make_identifier!("xyz"), value: Value::NumericLiteral(2) },
798 ];
799 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
800 assert!(debugger.evaluate_bind_rules().unwrap());
801 assert_eq!(
802 debugger.output,
803 vec![
804 DebuggerOutput::IfCondition { condition: &condition1, success: false },
805 DebuggerOutput::IfCondition { condition: &condition2, success: true },
806 DebuggerOutput::ConditionStatement { statement: &statement2, success: true }
807 ]
808 );
809
810 let properties =
812 vec![Property { key: make_identifier!("xyz"), value: Value::NumericLiteral(3) }];
813 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
814 assert!(debugger.evaluate_bind_rules().unwrap());
815 assert_eq!(
816 debugger.output,
817 vec![
818 DebuggerOutput::IfCondition { condition: &condition1, success: false },
819 DebuggerOutput::IfCondition { condition: &condition2, success: false },
820 DebuggerOutput::ConditionStatement { statement: &statement3, success: true }
821 ]
822 );
823
824 let properties = vec![
826 Property { key: make_identifier!("abc"), value: Value::NumericLiteral(42) },
827 Property { key: make_identifier!("xyz"), value: Value::NumericLiteral(42) },
828 ];
829 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
830 assert!(!debugger.evaluate_bind_rules().unwrap());
831 assert_eq!(
832 debugger.output,
833 vec![
834 DebuggerOutput::IfCondition { condition: &condition1, success: false },
835 DebuggerOutput::IfCondition { condition: &condition2, success: false },
836 DebuggerOutput::ConditionStatement { statement: &statement3, success: false }
837 ]
838 );
839
840 let properties = Vec::new();
842 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
843 assert!(!debugger.evaluate_bind_rules().unwrap());
844 assert_eq!(
845 debugger.output,
846 vec![
847 DebuggerOutput::IfCondition { condition: &condition1, success: false },
848 DebuggerOutput::IfCondition { condition: &condition2, success: false },
849 DebuggerOutput::ConditionStatement { statement: &statement3, success: false }
850 ]
851 );
852 }
853
854 #[test]
855 fn abort() {
856 let abort_statement = Statement::False { span: Span::new() };
857 let statements = vec![abort_statement.clone()];
858 let mut symbol_table = HashMap::new();
859 symbol_table.insert(
860 make_identifier!("abc"),
861 Symbol::Key("abc".to_string(), bind_library::ValueType::Number),
862 );
863
864 let instructions = compiler::compile_statements(statements, &symbol_table, false).unwrap();
865
866 let properties =
868 vec![Property { key: make_identifier!("abc"), value: Value::NumericLiteral(42) }];
869 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
870 assert!(!debugger.evaluate_bind_rules().unwrap());
871 assert_eq!(
872 debugger.output,
873 vec![DebuggerOutput::FalseStatement { statement: &abort_statement }]
874 );
875 }
876
877 #[test]
878 fn supports_all_value_types() {
879 let statements = vec![
880 Statement::ConditionStatement {
881 span: Span::new(),
882 condition: Condition {
883 span: Span::new(),
884 lhs: make_identifier!("a"),
885 op: ConditionOp::Equals,
886 rhs: Value::NumericLiteral(42),
887 },
888 },
889 Statement::ConditionStatement {
890 span: Span::new(),
891 condition: Condition {
892 span: Span::new(),
893 lhs: make_identifier!("b"),
894 op: ConditionOp::Equals,
895 rhs: Value::BoolLiteral(false),
896 },
897 },
898 Statement::ConditionStatement {
899 span: Span::new(),
900 condition: Condition {
901 span: Span::new(),
902 lhs: make_identifier!("c"),
903 op: ConditionOp::Equals,
904 rhs: Value::StringLiteral("string".to_string()),
905 },
906 },
907 Statement::ConditionStatement {
908 span: Span::new(),
909 condition: Condition {
910 span: Span::new(),
911 lhs: make_identifier!("d"),
912 op: ConditionOp::Equals,
913 rhs: Value::Identifier(make_identifier!("VALUE")),
914 },
915 },
916 ];
917 let mut symbol_table = HashMap::new();
918 symbol_table.insert(
919 make_identifier!("a"),
920 Symbol::Key("a".to_string(), bind_library::ValueType::Number),
921 );
922 symbol_table.insert(
923 make_identifier!("b"),
924 Symbol::Key("b".to_string(), bind_library::ValueType::Number),
925 );
926 symbol_table.insert(
927 make_identifier!("c"),
928 Symbol::Key("c".to_string(), bind_library::ValueType::Number),
929 );
930 symbol_table.insert(
931 make_identifier!("d"),
932 Symbol::Key("d".to_string(), bind_library::ValueType::Number),
933 );
934 symbol_table.insert(
935 make_identifier!("VALUE"),
936 Symbol::Key("VALUE".to_string(), bind_library::ValueType::Number),
937 );
938
939 let instructions = compiler::compile_statements(statements, &symbol_table, false).unwrap();
940
941 let properties = vec![
943 Property { key: make_identifier!("a"), value: Value::NumericLiteral(42) },
944 Property { key: make_identifier!("b"), value: Value::BoolLiteral(false) },
945 Property {
946 key: make_identifier!("c"),
947 value: Value::StringLiteral("string".to_string()),
948 },
949 Property {
950 key: make_identifier!("d"),
951 value: Value::Identifier(make_identifier!("VALUE")),
952 },
953 ];
954 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
955 assert!(debugger.evaluate_bind_rules().unwrap());
956 }
957
958 #[test]
959 fn full_rules() {
960 let condition = Condition {
970 span: Span::new(),
971 lhs: make_identifier!("abc"),
972 op: ConditionOp::Equals,
973 rhs: Value::NumericLiteral(42),
974 };
975 let abort_statement = Statement::False { span: Span::new() };
976 let condition_statement = Statement::ConditionStatement {
977 span: Span::new(),
978 condition: Condition {
979 span: Span::new(),
980 lhs: make_identifier!("pqr"),
981 op: ConditionOp::NotEquals,
982 rhs: Value::BoolLiteral(true),
983 },
984 };
985
986 let statements = vec![Statement::If {
987 span: Span::new(),
988 blocks: vec![(condition.clone(), vec![abort_statement.clone()])],
989 else_block: vec![
990 Statement::Accept {
991 span: Span::new(),
992 identifier: make_identifier!("xyz"),
993 values: vec![Value::NumericLiteral(1), Value::NumericLiteral(2)],
994 },
995 condition_statement.clone(),
996 ],
997 }];
998 let mut symbol_table = HashMap::new();
999 symbol_table.insert(
1000 make_identifier!("abc"),
1001 Symbol::Key("abc".to_string(), bind_library::ValueType::Number),
1002 );
1003 symbol_table.insert(
1004 make_identifier!("xyz"),
1005 Symbol::Key("xyz".to_string(), bind_library::ValueType::Number),
1006 );
1007 symbol_table.insert(
1008 make_identifier!("pqr"),
1009 Symbol::Key("pqr".to_string(), bind_library::ValueType::Number),
1010 );
1011 let instructions = compiler::compile_statements(statements, &symbol_table, false).unwrap();
1012
1013 let properties =
1015 vec![Property { key: make_identifier!("abc"), value: Value::NumericLiteral(42) }];
1016 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
1017 assert!(!debugger.evaluate_bind_rules().unwrap());
1018 assert_eq!(
1019 debugger.output,
1020 vec![
1021 DebuggerOutput::IfCondition { condition: &condition, success: true },
1022 DebuggerOutput::FalseStatement { statement: &abort_statement }
1023 ]
1024 );
1025
1026 let properties = vec![
1028 Property { key: make_identifier!("abc"), value: Value::NumericLiteral(43) },
1029 Property { key: make_identifier!("xyz"), value: Value::NumericLiteral(1) },
1030 ];
1031 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
1032 assert!(debugger.evaluate_bind_rules().unwrap());
1033 assert_eq!(
1034 debugger.output,
1035 vec![
1036 DebuggerOutput::IfCondition { condition: &condition, success: false },
1037 DebuggerOutput::AcceptStatementSuccess {
1038 identifier: &make_identifier!("xyz"),
1039 value: &Value::NumericLiteral(1),
1040 value_symbol: &Symbol::NumberValue(1),
1041 span: &Span::new(),
1042 },
1043 DebuggerOutput::ConditionStatement {
1044 statement: &condition_statement,
1045 success: true
1046 }
1047 ]
1048 );
1049
1050 let properties = vec![
1052 Property { key: make_identifier!("abc"), value: Value::NumericLiteral(43) },
1053 Property { key: make_identifier!("xyz"), value: Value::NumericLiteral(3) },
1054 ];
1055 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
1056 assert!(!debugger.evaluate_bind_rules().unwrap());
1057 assert_eq!(
1058 debugger.output,
1059 vec![
1060 DebuggerOutput::IfCondition { condition: &condition, success: false },
1061 DebuggerOutput::AcceptStatementFailure {
1062 identifier: &make_identifier!("xyz"),
1063 span: &Span::new(),
1064 },
1065 ]
1066 );
1067
1068 let properties = vec![
1070 Property { key: make_identifier!("abc"), value: Value::NumericLiteral(43) },
1071 Property { key: make_identifier!("xyz"), value: Value::NumericLiteral(1) },
1072 Property { key: make_identifier!("pqr"), value: Value::BoolLiteral(true) },
1073 ];
1074 let mut debugger = Debugger::new(&properties, &symbol_table, &instructions).unwrap();
1075 assert!(!debugger.evaluate_bind_rules().unwrap());
1076 assert_eq!(
1077 debugger.output,
1078 vec![
1079 DebuggerOutput::IfCondition { condition: &condition, success: false },
1080 DebuggerOutput::AcceptStatementSuccess {
1081 identifier: &make_identifier!("xyz"),
1082 value: &Value::NumericLiteral(1),
1083 value_symbol: &Symbol::NumberValue(1),
1084 span: &Span::new(),
1085 },
1086 DebuggerOutput::ConditionStatement {
1087 statement: &condition_statement,
1088 success: false
1089 }
1090 ]
1091 );
1092 }
1093}