1use std::{mem::transmute, str::FromStr};
2
3use crate::{
4 collections::{
5 handle_table::{Handle, HandleTable},
6 hash_map::CaoHashMap,
7 },
8 compiler::{CardIndex, NameSpace},
9 instruction::Instruction,
10 vm::instr_execution::decode_value,
11 VarName,
12};
13use crate::{version, VariableId};
14
15#[derive(Debug, Default, Clone)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct Labels(pub HandleTable<Label>);
18
19#[derive(Debug, Default, Clone)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21pub struct Variables {
22 pub ids: HandleTable<VariableId>,
23 pub names: HandleTable<VarName>,
24}
25
26#[derive(Debug, Clone, Default)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28pub struct Label {
29 pub pos: u32,
31}
32
33impl Label {
34 pub fn new(pos: u32) -> Self {
35 Self { pos }
36 }
37}
38
39#[derive(Debug, Clone, Default)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41pub struct Trace {
42 pub namespace: NameSpace,
43 pub index: CardIndex,
44}
45
46impl std::fmt::Display for Trace {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 for ns in self.namespace.iter() {
49 write!(f, "{ns}.")?;
50 }
51 write!(f, "{}", self.index)
52 }
53}
54
55#[derive(Debug, Clone)]
56#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
57pub struct CaoCompiledProgram {
58 pub bytecode: Vec<u8>,
60 pub data: Vec<u8>,
62 pub labels: Labels,
63 pub variables: Variables,
64 pub cao_lang_version: String,
65 pub trace: CaoHashMap<u32, Trace>,
66}
67
68impl CaoCompiledProgram {
69 pub fn variable_id(&self, name: &str) -> Option<VariableId> {
70 self.variables
71 .ids
72 .get(Handle::from_str(name).unwrap())
73 .copied()
74 }
75
76 pub fn print_disassembly(&self) {
77 let mut out = std::io::BufWriter::new(std::io::stdout());
78 self.disassemble_writer(&mut out).unwrap();
79 }
80
81 pub fn disassemble_string(&self) -> String {
82 let mut out = Vec::new();
83 self.disassemble_writer(&mut out).unwrap();
84 String::from_utf8(out).unwrap()
85 }
86
87 pub fn disassemble_writer(&self, mut writer: impl std::io::Write) -> std::io::Result<()> {
88 let mut i = 0;
89 while i < self.bytecode.len() {
90 let instr: u8 = self.bytecode[i];
91 let instr: Instruction = unsafe { transmute(instr) };
92 write!(writer, "{i}\t")?;
93 match instr {
95 Instruction::Add => writeln!(writer, "Add")?,
96 Instruction::Sub => writeln!(writer, "Sub")?,
97 Instruction::Mul => writeln!(writer, "Mul")?,
98 Instruction::Div => writeln!(writer, "Div")?,
99 Instruction::CallNative => writeln!(writer, "CallNative")?,
100 Instruction::ScalarInt => writeln!(writer, "ScalarInt")?,
101 Instruction::ScalarFloat => writeln!(writer, "ScalarFloat")?,
102 Instruction::ScalarNil => writeln!(writer, "ScalarNil")?,
103 Instruction::StringLiteral => writeln!(writer, "StringLiteral")?,
104 Instruction::CopyLast => writeln!(writer, "CopyLast")?,
105 Instruction::Exit => writeln!(writer, "Exit")?,
106 Instruction::CallFunction => writeln!(writer, "CallFunction")?,
107 Instruction::Equals => writeln!(writer, "Equals")?,
108 Instruction::NotEquals => writeln!(writer, "NotEquals")?,
109 Instruction::Less => writeln!(writer, "Less")?,
110 Instruction::LessOrEq => writeln!(writer, "LessOrEq")?,
111 Instruction::Pop => writeln!(writer, "Pop")?,
112 Instruction::SetGlobalVar => writeln!(writer, "SetGlobalVar")?,
113 Instruction::ReadGlobalVar => writeln!(writer, "ReadGlobalVar")?,
114 Instruction::SetLocalVar => writeln!(writer, "SetLocalVar")?,
115 Instruction::ReadLocalVar => writeln!(writer, "ReadLocalVar")?,
116 Instruction::ClearStack => writeln!(writer, "ClearStack")?,
117 Instruction::Return => writeln!(writer, "Return")?,
118 Instruction::SwapLast => writeln!(writer, "SwapLast")?,
119 Instruction::And => writeln!(writer, "And")?,
120 Instruction::Or => writeln!(writer, "Or")?,
121 Instruction::Xor => writeln!(writer, "Xor")?,
122 Instruction::Not => writeln!(writer, "Not")?,
123 Instruction::GotoIfTrue | Instruction::GotoIfFalse | Instruction::Goto => {
124 i += 1;
125 let pos: i32 = unsafe { decode_value(&self.bytecode, &mut i) };
126 writeln!(writer, "{instr:?}\t{pos}")?;
127 continue;
128 }
129 Instruction::InitTable => writeln!(writer, "InitTable")?,
130 Instruction::GetProperty => writeln!(writer, "GetProperty")?,
131 Instruction::SetProperty => writeln!(writer, "SetProperty")?,
132 Instruction::Len => writeln!(writer, "Len")?,
133 Instruction::BeginForEach => writeln!(writer, "BeginForEach")?,
134 Instruction::ForEach => writeln!(writer, "ForEach")?,
135 Instruction::FunctionPointer => writeln!(writer, "FunctionPointer")?,
136 Instruction::NativeFunctionPointer => writeln!(writer, "NativeFunctionPointer")?,
137 Instruction::NthRow => writeln!(writer, "NthRow")?,
138 Instruction::AppendTable => writeln!(writer, "AppendTable")?,
139 Instruction::PopTable => writeln!(writer, "PopTable")?,
140 Instruction::Closure => writeln!(writer, "Closure")?,
141 Instruction::SetUpvalue => writeln!(writer, "SetUpvalue")?,
142 Instruction::ReadUpvalue => writeln!(writer, "ReadUpvalue")?,
143 Instruction::RegisterUpvalue => writeln!(writer, "RegisterUpvalue")?,
144 Instruction::CloseUpvalue => writeln!(writer, "CloseUpvalue")?,
145 }
146 i += instr.span();
147 }
148 Ok(())
149 }
150}
151
152impl Default for CaoCompiledProgram {
153 fn default() -> Self {
154 Self {
155 bytecode: Default::default(),
156 data: Default::default(),
157 labels: Default::default(),
158 variables: Default::default(),
159 cao_lang_version: version::VERSION_STR.to_string(),
160 trace: Default::default(),
161 }
162 }
163}