1use crate::compiler::symbol_table::{get_deprecated_key_identifiers, Symbol};
6use crate::interpreter::common::BytecodeError;
7use crate::interpreter::decode_bind_rules::{DecodedCompositeBindRules, DecodedRules, Node};
8use crate::interpreter::instruction_decoder::{DecodedCondition, DecodedInstruction};
9use crate::parser::common::NodeType;
10
11fn dump_node(
12 node: &Node,
13 node_type: NodeType,
14 decoded_rules: &DecodedCompositeBindRules,
15) -> String {
16 let node_name = decoded_rules
17 .symbol_table
18 .get(&node.name_id)
19 .map_or_else(|| "N/A".to_string(), |name| name.clone());
20 let mut node_dump = match node_type {
21 NodeType::Primary => format!("Node (primary): {}", node_name),
22 NodeType::Additional => format!("Node: {}", node_name),
23 NodeType::Optional => format!("Node (optional): {}", node_name),
24 };
25 node_dump.push_str(&dump_instructions(node.decoded_instructions.clone()));
26 node_dump.push_str("\n");
27 node_dump
28}
29
30pub fn dump_bind_rules(bytecode: Vec<u8>) -> Result<String, BytecodeError> {
31 match DecodedRules::new(bytecode)? {
32 DecodedRules::Normal(decoded_rules) => {
33 Ok(dump_instructions(decoded_rules.decoded_instructions))
34 }
35 DecodedRules::Composite(rules) => {
36 let mut node_dump = dump_node(&rules.primary_node, NodeType::Primary, &rules);
37
38 if !rules.additional_nodes.is_empty() {
39 let additional_nodes_dump = rules
40 .additional_nodes
41 .iter()
42 .map(|node| dump_node(node, NodeType::Additional, &rules))
43 .collect::<Vec<String>>()
44 .concat();
45 node_dump.push_str(&additional_nodes_dump);
46 }
47
48 if !rules.optional_nodes.is_empty() {
49 let optional_nodes_dump = rules
50 .optional_nodes
51 .iter()
52 .map(|node| dump_node(&node, NodeType::Optional, &rules))
53 .collect::<Vec<String>>()
54 .concat();
55 node_dump.push_str(&optional_nodes_dump);
56 }
57 Ok(node_dump)
58 }
59 }
60}
61
62fn dump_condition(cond: DecodedCondition) -> String {
63 let op = if cond.is_equal { "==" } else { "!=" };
64 let lhs_dump = match cond.lhs {
65 Symbol::NumberValue(value) => {
66 let deprecated_keys = get_deprecated_key_identifiers();
67 match deprecated_keys.get(&(value as u32)) {
68 Some(value) => value.clone(),
69 None => value.to_string(),
70 }
71 }
72 _ => cond.lhs.to_string(),
73 };
74 format!("{} {} {}", lhs_dump, op, cond.rhs)
75}
76
77fn dump_instructions(instructions: Vec<DecodedInstruction>) -> String {
79 let mut bind_rules_dump = String::new();
80 for inst in instructions {
81 let inst_dump = match inst {
82 DecodedInstruction::UnconditionalAbort => " Abort".to_string(),
83 DecodedInstruction::Condition(cond) => format!(" {}", dump_condition(cond)),
84 DecodedInstruction::Jump(cond) => match cond {
85 Some(condition) => format!(" Jump if {} to ??", dump_condition(condition)),
86 None => " Jump to ??".to_string(),
87 },
88 DecodedInstruction::Label => " Label ??".to_string(),
89 };
90
91 bind_rules_dump.push_str("\n");
92 bind_rules_dump.push_str(&inst_dump);
93 }
94
95 bind_rules_dump
96}
97
98#[cfg(test)]
99mod test {
100 use super::*;
101 use crate::bytecode_constants::*;
102
103 const BIND_HEADER: [u8; 8] = [0x42, 0x49, 0x4E, 0x44, 0x02, 0, 0, 0];
104
105 fn append_section_header(bytecode: &mut Vec<u8>, magic_num: u32, sz: u32) {
106 bytecode.extend_from_slice(&magic_num.to_be_bytes());
107 bytecode.extend_from_slice(&sz.to_le_bytes());
108 }
109
110 #[test]
111 fn test_bytecode_print() {
112 let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
113 bytecode.push(BYTECODE_DISABLE_DEBUG);
114 append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 18);
115
116 let str_1: [u8; 5] = [0x57, 0x52, 0x45, 0x4E, 0]; bytecode.extend_from_slice(&[1, 0, 0, 0]);
118 bytecode.extend_from_slice(&str_1);
119
120 let str_2: [u8; 5] = [0x44, 0x55, 0x43, 0x4B, 0]; bytecode.extend_from_slice(&[2, 0, 0, 0]);
122 bytecode.extend_from_slice(&str_2);
123
124 append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 28);
125
126 let instructions = [
127 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0, 0x10, 0x11, 0x01, 0, 0, 0, 0x00, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0, 0x30, 0x20, ];
133 bytecode.extend_from_slice(&instructions);
134
135 let expected_dump =
136 "\n 83886080 == 268435472\n Jump if Key(WREN) == \"DUCK\" to ??\n Abort\n Label ??";
137 assert_eq!(expected_dump.to_string(), dump_bind_rules(bytecode).unwrap());
138 }
139
140 #[test]
141 fn test_composite_bytecode_print() {
142 let bytecode = vec![
143 0x42, 0x49, 0x4e, 0x44, 0x02, 0x00, 0x00, 0x00, 0x00, 0x53, 0x59, 0x4e, 0x42, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x77, 0x61, 0x6c, 0x6c, 0x63, 0x72, 0x65, 0x65, 0x70, 0x65, 0x72, 0x00, 0x02, 0x00, 0x00, 0x00, 0x77, 0x61, 0x67, 0x74, 0x61, 0x69, 0x6c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x72, 0x65, 0x64, 0x70, 0x6f, 0x6c, 0x6c, 0x00, 0x43, 0x4f, 0x4d, 0x50, 0x2d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x51, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x30, ];
163
164 let expected_dump = "Node (primary): wagtail\n \
165 fuchsia.BIND_PROTOCOL == 1\n\
166 Node: redpoll\n \
167 fuchsia.BIND_PROTOCOL != 2\n \
168 Abort\n";
169 assert_eq!(expected_dump.to_string(), dump_bind_rules(bytecode).unwrap());
170 }
171}