1use std::{fs, path::Path};
2
3use crate::{cache::NessaCache, compilation::{CompiledNessaExpr, NessaError, NessaInstruction}, config::{ImportMap, InnerDepGraph, NessaModule}, context::{standard_ctx, NessaContext, NUM_STD_BINOPS, NUM_STD_FNS, NUM_STD_INTS, NUM_STD_INT_IMPL, NUM_STD_MACROS, NUM_STD_NARYOPS, NUM_STD_TYPES, NUM_STD_UNOPS}, execution::ExecutionInfo, functions::Function, interfaces::{Interface, InterfaceImpl}, macros::NessaMacro, operations::Operator, parser::NessaExpr, types::TypeTemplate};
4
5use serde::{Serialize, Deserialize};
6use bitcode;
7
8#[derive(Clone, Serialize, Deserialize)]
9pub struct ReducedNessaModule {
10 pub name: String,
11 pub hash: String,
12
13 pub code: Vec<NessaExpr>,
14 pub source: Vec<String>,
15 pub imports: ImportMap,
16 pub inner_dependencies: InnerDepGraph,
17
18 pub type_templates: Vec<TypeTemplate>,
19 pub interfaces: Vec<Interface>,
20 pub interface_impls: Vec<InterfaceImpl>,
21
22 pub unary_ops: Vec<Operator>,
23 pub binary_ops: Vec<Operator>,
24 pub nary_ops: Vec<Operator>,
25
26 pub functions: Vec<Function>,
27
28 pub macros: Vec<NessaMacro>,
29
30 pub cache: NessaCache
31}
32
33impl NessaModule {
34 pub fn get_reduced_module(&self) -> ReducedNessaModule {
35 let reduced_types = self.ctx.type_templates[*NUM_STD_TYPES.lock().unwrap().borrow()..].to_vec();
36 let reduced_ints = self.ctx.interfaces[*NUM_STD_INTS.lock().unwrap().borrow()..].to_vec();
37 let reduced_int_impls = self.ctx.interface_impls[*NUM_STD_INT_IMPL.lock().unwrap().borrow()..].to_vec();
38 let reduced_macros = self.ctx.macros[*NUM_STD_MACROS.lock().unwrap().borrow()..].to_vec();
39
40 let func_map = NUM_STD_FNS.lock().unwrap();
41 let unop_map = NUM_STD_UNOPS.lock().unwrap();
42 let binop_map = NUM_STD_BINOPS.lock().unwrap();
43 let naryop_map = NUM_STD_NARYOPS.lock().unwrap();
44
45 let reduced_functions = self.ctx.functions.iter().map(|f| {
46 let mut f_cpy = f.clone();
47
48 if let Some(inner) = func_map.borrow().get(&f_cpy.id) {
49 f_cpy.overloads = f_cpy.overloads[*inner..].to_vec();
50 }
51
52 f_cpy
53 })
54 .collect();
55
56 let reduced_unops = self.ctx.unary_ops.iter().filter_map(|o| {
57 let mut o_cpy = o.clone();
58
59 if let Operator::Unary { id, operations, .. } = &mut o_cpy {
60 if let Some(inner) = unop_map.borrow().get(id) {
61 *operations = operations[*inner..].to_vec();
62 }
63
64 return Some(o_cpy);
65 }
66
67 unreachable!();
68 }).collect();
69
70 let reduced_binops = self.ctx.binary_ops.iter().filter_map(|o| {
71 let mut o_cpy = o.clone();
72
73 if let Operator::Binary { id, operations, .. } = &mut o_cpy {
74 if let Some(inner) = binop_map.borrow().get(id) {
75 *operations = operations[*inner..].to_vec();
76 }
77
78 return Some(o_cpy);
79 }
80
81 unreachable!();
82 }).collect();
83
84 let reduced_naryops = self.ctx.nary_ops.iter().filter_map(|o| {
85 let mut o_cpy = o.clone();
86
87 if let Operator::Nary { id, operations, .. } = &mut o_cpy {
88 if let Some(inner) = naryop_map.borrow().get(id) {
89 *operations = operations[*inner..].to_vec();
90 }
91
92 return Some(o_cpy);
93 }
94
95 unreachable!();
96 }).collect();
97
98 ReducedNessaModule {
99 name: self.name.clone(),
100 hash: self.hash.clone(),
101 code: self.code.clone(),
102 source: self.source.clone(),
103 imports: self.imports.clone(),
104 inner_dependencies: self.inner_dependencies.clone(),
105 type_templates: reduced_types,
106 interfaces: reduced_ints,
107 interface_impls: reduced_int_impls,
108 unary_ops: reduced_unops,
109 binary_ops: reduced_binops,
110 nary_ops: reduced_naryops,
111 functions: reduced_functions,
112 macros: reduced_macros,
113 cache: self.ctx.cache.clone(),
114 }
115 }
116}
117
118impl ReducedNessaModule {
119 pub fn recover_module(mut self) -> NessaModule {
120 let mut std_ctx = standard_ctx();
121
122 std_ctx.cache = self.cache;
124
125 std_ctx.type_templates.append(&mut self.type_templates);
126 std_ctx.interfaces.append(&mut self.interfaces);
127 std_ctx.interface_impls.append(&mut self.interface_impls);
128 std_ctx.macros.append(&mut self.macros);
129
130 for mut f in self.functions {
131 if f.id < std_ctx.functions.len() {
132 std_ctx.functions[f.id].overloads.append(&mut f.overloads);
133
134 } else {
135 std_ctx.functions.push(f);
136 }
137 }
138
139 for mut o in self.unary_ops {
140 if let Operator::Unary { id, operations, .. } = &mut o {
141 if *id < std_ctx.unary_ops.len() {
142 if let Operator::Unary { operations: operations_std, .. } = &mut std_ctx.unary_ops[*id] {
143 operations_std.append(operations);
144 }
145
146 } else {
147 std_ctx.unary_ops.push(o);
148 }
149
150 } else {
151 unreachable!();
152 }
153 }
154
155 for mut o in self.binary_ops {
156 if let Operator::Binary { id, operations, .. } = &mut o {
157 if *id < std_ctx.binary_ops.len() {
158 if let Operator::Binary { operations: operations_std, .. } = &mut std_ctx.binary_ops[*id] {
159 operations_std.append(operations);
160 }
161
162 } else {
163 std_ctx.binary_ops.push(o);
164 }
165
166 } else {
167 unreachable!();
168 }
169 }
170
171 for mut o in self.nary_ops {
172 if let Operator::Nary { id, operations, .. } = &mut o {
173 if *id < std_ctx.nary_ops.len() {
174 if let Operator::Nary { operations: operations_std, .. } = &mut std_ctx.nary_ops[*id] {
175 operations_std.append(operations);
176 }
177
178 } else {
179 std_ctx.nary_ops.push(o);
180 }
181
182 } else {
183 unreachable!();
184 }
185 }
186
187 NessaModule {
188 name: self.name.clone(),
189 hash: self.hash.clone(),
190 ctx: std_ctx,
191 code: self.code,
192 source: self.source,
193 imports: self.imports,
194 inner_dependencies: self.inner_dependencies,
195 }
196 }
197
198 pub fn deserialize(data: &[u8]) -> Self {
199 bitcode::deserialize(data).expect("Unable to deserialize module")
200 }
201
202 pub fn serialize(&self) -> Vec<u8> {
203 bitcode::serialize(self).expect("Unable to serialize module")
204 }
205
206 pub fn from_file(path: &Path) -> Self {
207 let data = fs::read(path).expect("Unable to read serialized module from file");
208 ReducedNessaModule::deserialize(&data)
209 }
210
211 pub fn write_to_file(&self, path: &Path) {
212 fs::write(path, self.serialize()).expect("Unable to write serialized module to file");
213 }
214}
215
216#[derive(Clone, Serialize, Deserialize)]
217pub struct CompiledNessaModule {
218 pub hash: String,
219 type_templates: Vec<TypeTemplate>,
220 interface_impls: Vec<InterfaceImpl>,
221 instructions: Vec<CompiledNessaExpr>
222}
223
224impl NessaContext {
225 pub fn get_serializable_module(&self, hash: String, instructions: &[NessaInstruction]) -> CompiledNessaModule {
226 return CompiledNessaModule {
227 hash,
228 type_templates: self.type_templates[*NUM_STD_TYPES.lock().unwrap().borrow()..].to_vec(),
229 interface_impls: self.interface_impls[*NUM_STD_INT_IMPL.lock().unwrap().borrow()..].to_vec(),
230 instructions: instructions.iter().map(|i| i.instruction.clone()).collect()
231 };
232 }
233}
234
235impl CompiledNessaModule {
236 pub fn deserialize(data: &[u8]) -> Self {
237 bitcode::deserialize(data).expect("Unable to deserialize code")
238 }
239
240 pub fn serialize(&self) -> Vec<u8> {
241 bitcode::serialize(self).expect("Unable to serialize code")
242 }
243
244 pub fn from_file(path: &Path) -> Self {
245 let data = fs::read(path).expect("Unable to read serialized code from file");
246 CompiledNessaModule::deserialize(&data)
247 }
248
249 pub fn write_to_file(&self, path: &Path) {
250 fs::write(path, self.serialize()).expect("Unable to write serialized code to file");
251 }
252
253 pub fn execute<const DEBUG: bool>(&mut self, program_input: &[String]) -> Result<ExecutionInfo, NessaError> {
254 let mut ctx = standard_ctx();
255
256 ctx.type_templates.append(&mut self.type_templates);
257 ctx.interface_impls.append(&mut self.interface_impls);
258
259 ctx.program_input = program_input.to_vec();
260
261 ctx.execute_compiled_code::<DEBUG>(&self.instructions, &[])
262 }
263}