reqlang_expr/
disassembler.rs1use crate::{
4 compiler::{CompileTimeEnv, ExprByteCode, opcode},
5 prelude::lookup,
6};
7
8pub struct Disassembler<'bytecode, 'env> {
9 bytecode: &'bytecode ExprByteCode,
10 env: &'env CompileTimeEnv,
11}
12
13impl<'bytecode, 'env> Disassembler<'bytecode, 'env> {
14 pub fn new(bytecode: &'bytecode ExprByteCode, env: &'env CompileTimeEnv) -> Self {
15 Self { bytecode, env }
16 }
17
18 pub fn disassemble(&self) -> String {
20 let mut out = String::new();
21
22 let mut op_idx = 0;
23
24 while op_idx < self.bytecode.codes().len() {
25 let (op_byte_size, disassembled_byte_idx, disassembled_op) =
26 self.disassemble_op(op_idx);
27
28 let op_string = &format!("{disassembled_byte_idx} {disassembled_op}");
29 out.push_str(op_string);
30
31 op_idx += op_byte_size;
32 }
33
34 out
35 }
36
37 pub fn disassemble_op(&self, op_idx: usize) -> (usize, String, String) {
38 let op_idx_str = format!("{op_idx:04}");
39
40 let (op_idx_inc, op_str): (usize, String) = match self.bytecode.codes()[op_idx] {
41 opcode::GET => self.disassemble_op_get(op_idx),
42 opcode::CALL => self.disassemble_op_call("CALL", op_idx),
43 opcode::CONSTANT => self.disassemble_op_constant("CONSTANT", op_idx),
44 opcode::TRUE => self.disassemble_op_true("TRUE", op_idx),
45 opcode::FALSE => self.disassemble_op_false("FALSE", op_idx),
46 _ => (1, "".to_string()),
47 };
48
49 (op_idx_inc, op_idx_str, op_str)
50 }
51
52 fn disassemble_op_true(&self, name: &str, op_idx: usize) -> (usize, String) {
53 let constant_op = self.bytecode.codes()[op_idx];
54 assert_eq!(constant_op, opcode::TRUE);
55
56 let string = format!("{name}\n");
57
58 (1, string)
59 }
60
61 fn disassemble_op_false(&self, name: &str, op_idx: usize) -> (usize, String) {
62 let constant_op = self.bytecode.codes()[op_idx];
63 assert_eq!(constant_op, opcode::FALSE);
64
65 let string = format!("{name}\n");
66
67 (1, string)
68 }
69
70 fn disassemble_op_constant(&self, name: &str, op_idx: usize) -> (usize, String) {
71 let constant_op = self.bytecode.codes()[op_idx];
72 assert_eq!(constant_op, opcode::CONSTANT);
73
74 let constant_idx = self.bytecode.codes()[op_idx + 1] as usize;
75
76 let value = self
77 .bytecode
78 .strings()
79 .get(constant_idx)
80 .expect("should have string at index");
81
82 let string = format!("{name:16} {constant_idx:>4} == '{value}'\n");
83
84 (2, string)
85 }
86
87 fn disassemble_op_get(&self, op_idx: usize) -> (usize, String) {
88 let call_op = self.bytecode.codes()[op_idx];
89 assert_eq!(call_op, opcode::GET);
90
91 let lookup_type = self.bytecode.codes()[op_idx + 1];
92 let constant_idx = self.bytecode.codes()[op_idx + 2] as usize;
93
94 let value = match lookup_type {
95 lookup::BUILTIN => {
96 let value = self.env.get_builtin(constant_idx).unwrap();
97 &value.name
98 }
99 lookup::USER_BUILTIN => {
100 let value = self.env.get_user_builtin(constant_idx).unwrap();
101 &value.name
102 }
103 lookup::VAR => {
104 let value = self.env.get_var(constant_idx).unwrap();
105
106 value
107 }
108 lookup::PROMPT => {
109 let value = self.env.get_prompt(constant_idx).unwrap();
110
111 value
112 }
113 lookup::SECRET => {
114 let value = self.env.get_secret(constant_idx).unwrap();
115
116 value
117 }
118 lookup::CLIENT_CTX => {
119 let value = self.env.get_client_context(constant_idx).unwrap();
120
121 value
122 }
123 _ => panic!("invalid get lookup code: {}", lookup_type),
124 };
125
126 let lookup_type_string = match lookup_type {
127 lookup::BUILTIN => "BUILTIN",
128 lookup::USER_BUILTIN => "USER_BUILTIN",
129 lookup::VAR => "VAR",
130 lookup::PROMPT => "PROMPT",
131 lookup::SECRET => "SECRET",
132 lookup::CLIENT_CTX => "CLIENT_CTX",
133 _ => panic!("invalid get lookup code: {}", lookup_type),
134 };
135
136 let name = "GET";
137
138 let string = format!("{name} {lookup_type_string:12} {constant_idx:>4} == '{value}'\n");
139
140 (3, string)
141 }
142
143 fn disassemble_op_call(&self, name: &str, op_idx: usize) -> (usize, String) {
144 let call_op = self.bytecode.codes()[op_idx];
145 assert_eq!(call_op, opcode::CALL);
146
147 let arg_count = self.bytecode.codes()[op_idx + 1];
148
149 let string = format!("{name:16} ({arg_count} args)\n",);
150
151 (2, string)
152 }
153}