cao_lang/
compiled_program.rs

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    /// Position of this card in the bytecode of the program
30    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    /// Instructions
59    pub bytecode: Vec<u8>,
60    /// Data used by instuctions with variable length inputs
61    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            // TODO: also print the arguments of the instructions
94            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}