1use std::fmt;
2
3use crate::common::{
4 opcode::Opcode,
5 data::Data,
6 number::build_number,
7 span::Span,
8};
9
10use crate::core::ffi::FFIFunction;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum Captured {
15 Local(usize),
17 Nonlocal(usize),
19}
20
21#[derive(Debug, Clone, PartialEq)]
24pub struct Lambda {
25 pub decls: usize,
29 pub code: Vec<u8>,
31 pub spans: Vec<(usize, Span)>,
33 pub constants: Vec<Data>,
35 pub captures: Vec<Captured>,
38 pub ffi: Vec<FFIFunction>,
41}
42
43impl Lambda {
44 pub fn empty() -> Lambda {
46 Lambda {
47 decls: 0,
48 code: vec![],
49 spans: vec![],
50 constants: vec![],
51 captures: vec![],
52 ffi: vec![],
53 }
54 }
55
56 pub fn emit(&mut self, op: Opcode) {
58 self.code.push(op as u8)
59 }
60
61 pub fn emit_bytes(&mut self, bytes: &mut Vec<u8>) {
63 self.code.append(bytes)
64 }
65
66 pub fn emit_span(&mut self, span: &Span) {
70 self.spans.push((self.code.len(), span.clone()))
71 }
72
73 pub fn demit(&mut self) {
75 self.code.pop();
76 }
77
78 pub fn index_data(&mut self, data: Data) -> usize {
84 match self.constants.iter().position(|d| d == &data) {
85 Some(d) => d,
86 None => {
87 self.constants.push(data);
88 self.constants.len() - 1
89 },
90 }
91 }
92
93 pub fn index_span(&self, index: usize) -> Span {
95 let mut best = &Span::empty();
96
97 for (i, span) in self.spans.iter() {
98 if i > &index { break; }
99 best = span;
100 }
101
102 best.clone()
103 }
104
105 pub fn add_ffi(&mut self, function: FFIFunction) -> usize {
110 self.ffi.push(function);
111 self.ffi.len() - 1
112 }
113}
114
115impl fmt::Display for Lambda {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
119 writeln!(f, "-- Dumping Constants:")?;
120 for constant in self.constants.iter() {
121 writeln!(f, "{:?}", constant)?;
122 }
123
124 writeln!(f, "-- Dumping Captures:")?;
130 for capture in self.captures.iter() {
131 writeln!(f, "{:?}", capture)?;
132 }
133
134 writeln!(f, "-- Dumping Variables: {}", self.decls)?;
135
136 writeln!(f, "-- Dumping Bytecode:")?;
137 writeln!(f, "Inst. \tArgs\tValue?")?;
138 let mut index = 0;
139
140 while index < self.code.len() {
141 index += 1;
142 match Opcode::from_byte(self.code[index - 1]) {
143 Opcode::Con => {
144 let (constant_index, consumed) = build_number(&self.code[index..]);
145 index += consumed;
146 writeln!(f, "Load Con\t{}\t{:?}", constant_index, self.constants[constant_index])?;
147 },
148 Opcode::NotInit => { writeln!(f, "NotInit \t\tDeclare variable")?; }
149 Opcode::Del => { writeln!(f, "Delete \t\t--")?; },
150 Opcode::Capture => {
151 let (local_index, consumed) = build_number(&self.code[index..]);
152 index += consumed;
153 writeln!(f, "Capture \t{}\tIndexed local moved to heap", local_index)?;
154 },
155 Opcode::Save => {
156 let (local_index, consumed) = build_number(&self.code[index..]);
157 index += consumed;
158 writeln!(f, "Save \t{}\tIndexed local", local_index)?;
159 },
160 Opcode::SaveCap => {
161 let (upvalue_index, consumed) = build_number(&self.code[index..]);
162 index += consumed;
163 writeln!(f, "Save Cap\t{}\tIndexed upvalue on heap", upvalue_index)?;
164 },
165 Opcode::Load => {
166 let (local_index, consumed) = build_number(&self.code[index..]);
167 index += consumed;
168 writeln!(f, "Load \t{}\tIndexed local", local_index)?;
169 },
170 Opcode::LoadCap => {
171 let (upvalue_index, consumed) = build_number(&self.code[index..]);
172 index += consumed;
173 writeln!(f, "Load Cap\t{}\tIndexed upvalue on heap", upvalue_index)?;
174 },
175 Opcode::Call => { writeln!(f, "Call \t\tRun top function using next stack value")?; }
176 Opcode::Return => {
177 let (num_locals, consumed) = build_number(&self.code[index..]);
178 index += consumed;
179 writeln!(f, "Return \t{}\tLocals on stack deleted", num_locals)?;
180 },
181 Opcode::Closure => {
182 let (todo_index, consumed) = build_number(&self.code[index..]);
183 index += consumed;
184 writeln!(f, "Closure \t{}\tIndex of lambda to be wrapped", todo_index)?;
185 },
186 Opcode::Print => { writeln!(f, "Print \t\t--")?; },
187 Opcode::Label => { writeln!(f, "Label \t\t--")?; },
188 Opcode::Tuple => {
189 let (length, consumed) = build_number(&self.code[index..]);
190 index += consumed;
191 writeln!(f, "Tuple \t{}\tValues tupled together", length)?;
192 },
193 Opcode::UnLabel => { writeln!(f, "UnLabel \t\t--")?; },
194 Opcode::UnData => { writeln!(f, "UnData \t\t--")?; },
195 Opcode::UnTuple => {
196 let (item_index, consumed) = build_number(&self.code[index..]);
197 index += consumed;
198 writeln!(f, "UnTuple \t{}\tItem accessed", item_index)?;
199 },
200 Opcode::Copy => { writeln!(f, "Copy \t\t--")?; },
201 Opcode::FFICall => {
202 let (ffi_index, consumed) = build_number(&self.code[index..]);
203 index += consumed;
204 writeln!(f, "Return \t{}\tIndexed FFI function called", ffi_index)?;
205 },
206 }
207 }
208
209 Ok(())
210 }
211}