1use std::{cell::RefCell, fs::File, path::PathBuf};
2
3use crate::{compilation::message_and_exit, context::NessaContext, mut_cell::MutCell, types::{Type, ARR_ID, ARR_IT_ID, BOOL, BOOL_ID, FILE, FILE_ID, FLOAT, FLOAT_ID, INT, INT_ID, STR, STR_ID}, ARR_IT_OF, ARR_OF};
4use malachite::Integer;
5use rclite::Rc;
6use serde::{Deserialize, Serialize};
7
8type DataBlock = Rc<MutCell<ObjectBlock>>;
9
10#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
17pub struct NessaArray {
18 pub elements: Vec<Object>,
19 pub elem_type: Box<Type>
20}
21
22#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
23pub struct NessaTuple {
24 pub elements: Vec<Object>,
25 pub elem_types: Vec<Type>
26}
27
28#[derive(Clone, PartialEq, Debug)]
29pub struct NessaArrayIt {
30 pub pos: usize,
31 pub block: DataBlock,
32 pub it_type: Box<Type>
33}
34
35#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
36pub struct NessaLambda {
37 pub loc: usize,
38 pub captures: Vec<Object>,
39 pub args_type: Box<Type>,
40 pub ret_type: Box<Type>
41}
42
43#[derive(Clone, Debug)]
44pub struct NessaFile {
45 pub path: PathBuf,
46 pub file: Option<Rc<RefCell<File>>>
47}
48
49impl PartialEq for NessaFile {
50 fn eq(&self, other: &Self) -> bool {
51 match (&self.file, &other.file) {
52 (None, None) => self.path == other.path,
53 (Some(a), Some(b)) => self.path == other.path && Rc::ptr_eq(a, b),
54
55 _ => false
56 }
57 }
58}
59
60impl NessaFile {
61 pub fn is_open(&self) -> bool {
62 self.file.is_some()
63 }
64
65 pub fn close(&mut self) -> Result<(), String> {
66 if !self.is_open() {
67 return Err(format!("File at {} is already closed", self.path.to_str().unwrap()));
68 }
69
70 self.file = None;
71
72 Ok(())
73 }
74
75 pub fn open(&mut self, read: bool, write: bool, append: bool) -> Result<(), String> {
76 if self.is_open() {
77 return Err(format!("File at {} is already open", self.path.to_str().unwrap()));
78 }
79
80 let file = std::fs::OpenOptions::new()
81 .create(write || append)
82 .read(read)
83 .write(write)
84 .append(append)
85 .open(&self.path);
86
87 match file {
88 Ok(inner) => {
89 self.file = Some(Rc::new(RefCell::new(inner)));
90 Ok(())
91 },
92
93 Err(_) => Err(format!("Unable to open file file at {}", self.path.to_str().unwrap()))
94 }
95 }
96
97 pub fn exists(&self) -> Result<bool, String> {
98 Ok(self.path.is_file())
99 }
100
101 pub fn delete(&mut self) -> Result<bool, String> {
102 if !self.is_open() {
103 return Err(format!("File at {} is closed", self.path.to_str().unwrap()));
104 }
105
106 if std::fs::remove_file(&self.path).is_ok() {
107 self.file = None;
108 Ok(true)
109
110 } else {
111 Ok(false)
112 }
113 }
114}
115
116#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
117pub struct TypeInstance {
118 pub id: usize,
119 pub params: Vec<Type>,
120 pub attributes: Vec<Object>
121}
122
123#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
124pub enum ObjectBlock {
125 #[default]
126 NoValue, Empty,
129 Int(malachite::Integer),
130 Float(f64),
131 Str(String),
132 Bool(bool),
133
134 Tuple(NessaTuple),
135 Array(NessaArray),
136
137 #[serde(skip)]
138 ArrayIter(NessaArrayIt),
139
140 Lambda(NessaLambda),
141
142 #[serde(skip)]
143 File(NessaFile),
144
145 Instance(TypeInstance),
146
147 #[serde(skip)]
148 Ref(DataBlock),
149 #[serde(skip)]
150 Mut(DataBlock),
151}
152
153impl Eq for ObjectBlock {}
154
155impl ObjectBlock {
156 #[inline(always)]
157 pub fn to_obj(self) -> Object {
158 Object { inner: Rc::new(MutCell::new(self)) }
159 }
160
161 pub fn get_type_id(&self) -> usize {
162 match self {
163 ObjectBlock::NoValue => message_and_exit("Accessing moved object".into()),
164 ObjectBlock::Empty => 0,
165 ObjectBlock::Int(_) => INT_ID,
166 ObjectBlock::Float(_) => FLOAT_ID,
167 ObjectBlock::Str(_) => STR_ID,
168 ObjectBlock::Bool(_) => BOOL_ID,
169 ObjectBlock::Tuple(_) => 0,
170 ObjectBlock::Array(_) => ARR_ID,
171 ObjectBlock::ArrayIter(_) => ARR_IT_ID,
172 ObjectBlock::Lambda(_) => 0,
173 ObjectBlock::File(_) => FILE_ID,
174 ObjectBlock::Instance(i) => i.id,
175 ObjectBlock::Ref(_) => 0,
176 ObjectBlock::Mut(_) => 0,
177 }
178 }
179
180 pub fn get_type(&self) -> Type {
181 return match self {
182 ObjectBlock::NoValue => message_and_exit("Accessing moved object".into()),
183 ObjectBlock::Empty => Type::Empty,
184 ObjectBlock::Int(_) => INT,
185 ObjectBlock::Float(_) => FLOAT,
186 ObjectBlock::Str(_) => STR,
187 ObjectBlock::Bool(_) => BOOL,
188 ObjectBlock::Tuple(t) => Type::And(t.elem_types.clone()),
189 ObjectBlock::Array(a) => ARR_OF!(*a.elem_type.clone()),
190 ObjectBlock::ArrayIter(i) => ARR_IT_OF!(*i.it_type.clone()),
191 ObjectBlock::Lambda(l) => Type::Function(l.args_type.clone(), l.ret_type.clone()),
192 ObjectBlock::File(_) => FILE,
193 ObjectBlock::Instance(i) => if i.params.is_empty() { Type::Basic(i.id) } else { Type::Template(i.id, i.params.clone()) },
194 ObjectBlock::Ref(r) => Type::Ref(Box::new(r.borrow().get_type())),
195 ObjectBlock::Mut(r) => Type::MutRef(Box::new(r.borrow().get_type())),
196 };
197 }
198
199 pub fn is_moved(&self) -> bool {
200 matches!(self, ObjectBlock::NoValue)
201 }
202
203 pub fn get_inner<T>(&self) -> &T where ObjectBlock: Get<T> {
204 return Get::<T>::get(self);
205 }
206
207 pub fn mut_inner<T>(&mut self) -> &mut T where ObjectBlock: GetMut<T> {
208 return GetMut::<T>::get(self);
209 }
210
211 pub fn dereference(&self) -> &DataBlock {
212 if let ObjectBlock::Ref(n) | ObjectBlock::Mut(n) = self {
213 return n;
214 }
215
216 unreachable!();
217 }
218
219 pub fn assign_ref(&mut self, other: ObjectBlock, ctx: &NessaContext) -> Result<(), String> {
220 self.dereference().borrow_mut().assign(other, ctx)
221 }
222
223 pub fn assign(&mut self, other: ObjectBlock, ctx: &NessaContext) -> Result<(), String> {
224 use ObjectBlock::*;
225
226 match (self, other) {
227 (Int(a), Int(b)) => *a = b,
228 (Float(a), Float(b)) => *a = b,
229 (Str(a), Str(b)) => *a = b,
230 (Bool(a), Bool(b)) => *a = b,
231 (Array(a), Array(b)) if a.elem_type == b.elem_type => *a = b,
232 (ArrayIter(a), ArrayIter(b)) if a.it_type == b.it_type => *a = b,
233 (Lambda(a), Lambda(b)) if a.args_type == b.args_type && a.ret_type == b.ret_type => *a = b,
234 (Instance(a), Instance(b)) if a.id == b.id && a.params == b.params => *a = b,
235 (Tuple(a), Tuple(b)) if a.elem_types == b.elem_types => *a = b,
236
237 (a, b) => return Err(format!(
238 "Unable to assign value of type {} to block of type {}",
239 b.get_type().get_name(ctx),
240 a.get_type().get_name(ctx)
241 ))
242 };
243
244 Ok(())
245 }
246
247 pub fn deep_clone(&self) -> Self {
248 return match self {
249 ObjectBlock::NoValue => message_and_exit("Accessing moved object".into()),
250
251 ObjectBlock::Empty => ObjectBlock::Empty,
252 ObjectBlock::Int(n) => ObjectBlock::Int(n.clone()),
253 ObjectBlock::Float(n) => ObjectBlock::Float(*n),
254 ObjectBlock::Str(s) => ObjectBlock::Str(s.clone()),
255 ObjectBlock::Bool(b) => ObjectBlock::Bool(*b),
256 ObjectBlock::Tuple(t) => ObjectBlock::Tuple(NessaTuple {
257 elements: t.elements.iter().map(Object::deep_clone).collect(),
258 elem_types: t.elem_types.clone()
259 }),
260 ObjectBlock::Array(a) => ObjectBlock::Array(NessaArray {
261 elements: a.elements.iter().map(Object::deep_clone).collect(),
262 elem_type: a.elem_type.clone()
263 }),
264 ObjectBlock::ArrayIter(i) => ObjectBlock::ArrayIter(NessaArrayIt {
265 pos: i.pos,
266 block: i.block.clone(),
267 it_type: i.it_type.clone()
268 }),
269 ObjectBlock::Lambda(l) => ObjectBlock::Lambda(NessaLambda {
270 loc: l.loc,
271 captures: l.captures.iter().map(Object::deep_clone).collect(),
272 args_type: l.args_type.clone(),
273 ret_type: l.ret_type.clone()
274 }),
275 ObjectBlock::File(f) => ObjectBlock::File(f.clone()),
276 ObjectBlock::Instance(i) => ObjectBlock::Instance(TypeInstance {
277 id: i.id,
278 params: i.params.clone(),
279 attributes: i.attributes.iter().map(Object::deep_clone).collect()
280 }),
281 ObjectBlock::Ref(r) => ObjectBlock::Ref(r.clone()),
282 ObjectBlock::Mut(r) => ObjectBlock::Mut(r.clone()),
283 }
284 }
285}
286
287#[derive(Clone, PartialEq, Eq, Debug)]
288pub struct Object {
289 pub inner: DataBlock
290}
291
292impl Serialize for Object {
293 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
294 where
295 S: serde::Serializer {
296 self.inner.borrow().serialize(serializer)
297 }
298}
299
300impl<'de> Deserialize<'de> for Object {
301 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
302 where
303 D: serde::Deserializer<'de> {
304 let inner = ObjectBlock::deserialize(deserializer)?;
305 Ok(inner.to_obj())
306 }
307}
308
309impl Object {
310 pub fn new<T: NessaData>(data: T) -> Self {
311 data.data().to_obj()
312 }
313
314 pub fn get_ptr(&self) -> *mut ObjectBlock {
315 (*self.inner).as_ptr()
316 }
317
318 pub fn arr(elements: Vec<Object>, elem_type: Type) -> Self {
319 ObjectBlock::Array(NessaArray { elements, elem_type: Box::new(elem_type) }).to_obj()
320 }
321
322 pub fn arr_it(it_type: Type, block: DataBlock, pos: usize) -> Self {
323 ObjectBlock::ArrayIter(NessaArrayIt { pos, block, it_type: Box::new(it_type) }).to_obj()
324 }
325
326 pub fn lambda(loc: usize, captures: Vec<Object>, args_type: Type, ret_type: Type) -> Self {
327 ObjectBlock::Lambda(NessaLambda { loc, captures, args_type: Box::new(args_type), ret_type: Box::new(ret_type) }).to_obj()
328 }
329
330 pub fn tuple(elements: Vec<Object>, elem_types: Vec<Type>) -> Self {
331 ObjectBlock::Tuple(NessaTuple { elements, elem_types }).to_obj()
332 }
333
334 pub fn file(path: PathBuf) -> Self {
335 ObjectBlock::File(NessaFile { path, file: None }).to_obj()
336 }
337
338 pub fn instance(attributes: Vec<Object>, params: Vec<Type>, id: usize) -> Self {
339 ObjectBlock::Instance(TypeInstance { params, attributes, id }).to_obj()
340 }
341
342 pub fn get<T>(&self) -> &T where ObjectBlock: Get<T> {
343 Get::<T>::get(self.inner.borrow())
344 }
345
346 #[allow(clippy::should_implement_trait)]
347 pub fn deref<T>(&self) -> &mut T where ObjectBlock: Deref<T> + GetMut<T> {
348 Deref::<T>::deref(self.inner.borrow())
349 }
350
351 pub fn ref_count(&self) -> usize {
352 Rc::strong_count(&self.inner)
353 }
354
355 pub fn is_moved(&self) -> bool {
356 return self.inner.borrow().is_moved();
357 }
358
359 pub fn move_contents(&self) -> Object {
363 let res = ObjectBlock::default().to_obj();
364
365 match &mut *self.inner.borrow_mut() {
366 ObjectBlock::Mut(i) => std::mem::swap(&mut *i.borrow_mut(), &mut *res.inner.borrow_mut()),
367 _ => unreachable!()
368 };
369
370 res
371 }
372
373 pub fn move_contents_if_ref(&self) -> Object {
374 let res = ObjectBlock::default().to_obj();
375
376 match &mut *self.inner.borrow_mut() {
377 ObjectBlock::Mut(i) => std::mem::swap(&mut *i.borrow_mut(), &mut *res.inner.borrow_mut()),
378 i => std::mem::swap(i, &mut *res.inner.borrow_mut())
379 };
380
381 res
382 }
383
384 pub fn swap_contents(&self, other: &Object) {
385 match (&mut *self.inner.borrow_mut(), &mut *other.inner.borrow_mut()) {
386 (ObjectBlock::Mut(a), ObjectBlock::Mut(b)) => std::mem::swap(&mut *a.borrow_mut(), &mut *b.borrow_mut()),
387 _ => unreachable!()
388 };
389 }
390
391 pub fn drop_contents(&self) {
392 match &mut *self.inner.borrow_mut() {
393 ObjectBlock::Mut(i) => std::mem::take(&mut *i.borrow_mut()),
394 _ => unreachable!()
395 };
396 }
397
398 pub fn assign(&self, other_obj: Object, ctx: &NessaContext) -> Result<(), String> {
399 match Rc::try_unwrap(other_obj.inner) {
400 Ok(inner) => self.inner.borrow_mut().assign_ref(inner.take(), ctx),
401 Err(inner) => self.inner.borrow_mut().assign_ref(inner.borrow().clone(), ctx)
402 }
403 }
404
405 pub fn assign_direct(&self, other_obj: Object, ctx: &NessaContext) -> Result<(), String> {
406 match Rc::try_unwrap(other_obj.inner) {
407 Ok(inner) => self.inner.borrow_mut().assign(inner.take(), ctx),
408 Err(inner) => self.inner.borrow_mut().assign(inner.borrow().clone(), ctx)
409 }
410 }
411
412 pub fn from_inner(inner: DataBlock) -> Self {
413 Object { inner }
414 }
415
416 pub fn no_value() -> Object {
417 ObjectBlock::NoValue.to_obj()
418 }
419
420 pub fn empty() -> Object {
421 ObjectBlock::Empty.to_obj()
422 }
423
424 pub fn get_ref(&self) -> Object {
425 return match self.inner.borrow() {
426 ObjectBlock::Ref(i) |
427 ObjectBlock::Mut(i) => ObjectBlock::Ref(i.clone()).to_obj(),
428
429 _ => ObjectBlock::Ref(self.inner.clone()).to_obj()
430 }
431 }
432
433 pub fn get_mut(&self) -> Object {
434 return match self.inner.borrow() {
435 ObjectBlock::Ref(i) |
436 ObjectBlock::Mut(i) => ObjectBlock::Mut(i.clone()).to_obj(),
437
438 _ => ObjectBlock::Mut(self.inner.clone()).to_obj()
439 }
440 }
441
442 pub fn get_ref_nostack(&self) -> Object {
443 ObjectBlock::Ref(self.inner.clone()).to_obj()
444 }
445
446 pub fn get_mut_nostack(&self) -> Object {
447 ObjectBlock::Mut(self.inner.clone()).to_obj()
448 }
449
450 pub fn to_debug_string(&self) -> String {
451 format!("{:?}", self.inner.borrow())
452 }
453
454 pub fn deref_if_ref(&self) -> Object {
455 return match self.inner.borrow() {
456 ObjectBlock::Ref(i) |
457 ObjectBlock::Mut(i) => Object::from_inner(i.clone()),
458
459 _ => self.clone()
460 }
461 }
462
463 pub fn deref_deep_clone(&self) -> Object {
464 return match self.inner.borrow() {
465 ObjectBlock::Ref(i) |
466 ObjectBlock::Mut(i) => i.borrow().deep_clone().to_obj(),
467
468 obj => obj.deep_clone().to_obj()
469 }
470 }
471
472 pub fn deep_clone(&self) -> Object {
473 self.inner.borrow().deep_clone().to_obj()
474 }
475
476 pub fn get_type_id(&self) -> usize {
477 return self.inner.borrow().get_type_id();
478 }
479
480 pub fn get_type(&self) -> Type {
481 return self.inner.borrow().get_type();
482 }
483
484 pub fn deref_obj(&self) -> Object {
485 return match self.inner.borrow() {
486 ObjectBlock::Ref(r) | ObjectBlock::Mut(r) => Object::from_inner(r.clone()),
487 _ => unreachable!()
488 };
489 }
490}
491
492pub trait NessaData {
493 fn data(self) -> ObjectBlock;
494}
495
496pub trait Get<T> {
497 fn get(&self) -> &T;
498}
499
500pub trait GetMut<T> {
501 fn get(&mut self) -> &mut T;
502}
503
504pub trait Deref<T> {
505 #[allow(clippy::mut_from_ref)]
506 fn deref(&self) -> &mut T;
507}
508
509macro_rules! impl_nessa_data {
510 ($t: ty, $v: tt) => {
511 impl NessaData for $t {
512 #[inline(always)]
513 fn data(self) -> ObjectBlock {
514 return ObjectBlock::$v(self)
515 }
516 }
517
518 impl Get<$t> for ObjectBlock {
519 #[inline(always)]
520 fn get(&self) -> &$t {
521 if let ObjectBlock::$v(n) = self {
522 return n;
523 }
524
525 unreachable!("Unable to get {:?}", self);
526 }
527 }
528
529 impl GetMut<$t> for ObjectBlock {
530 #[inline(always)]
531 fn get(&mut self) -> &mut $t {
532 if let ObjectBlock::$v(n) = self {
533 return n;
534 }
535
536 unreachable!("Unable to get mut {:?}", self);
537 }
538 }
539
540 impl Deref<$t> for ObjectBlock {
541 #[inline(always)]
542 fn deref(&self) -> &mut $t {
543 return GetMut::<$t>::get(self.dereference().borrow_mut());
544 }
545 }
546 };
547}
548
549impl_nessa_data!(Integer, Int);
550impl_nessa_data!(f64, Float);
551impl_nessa_data!(String, Str);
552impl_nessa_data!(bool, Bool);
553impl_nessa_data!(TypeInstance, Instance);
554impl_nessa_data!(NessaArray, Array);
555impl_nessa_data!(NessaTuple, Tuple);
556impl_nessa_data!(NessaLambda, Lambda);
557impl_nessa_data!(NessaArrayIt, ArrayIter);
558impl_nessa_data!(NessaFile, File);
559
560#[cfg(test)]
567mod tests {
568 use crate::context::standard_ctx;
569 use malachite::Integer;
570 use crate::object::*;
571
572 #[test]
573 fn object_construction() {
574 let number = Object::new(Integer::from(10));
575
576 assert_eq!(*number.get::<Integer>(), Integer::from(10));
577
578 let string = Object::new(String::from("Test"));
579
580 assert_eq!(*string.get::<String>(), "Test".to_string());
581
582 assert_ne!(number.get_type_id(), string.get_type_id());
583 }
584
585 #[test]
586 fn references() {
587 let ctx = standard_ctx();
588
589 let number = Object::new(Integer::from(10));
590
591 assert_eq!(*number.get::<Integer>(), Integer::from(10));
592
593 let reference = number.get_mut();
594 let ref_of_ref = reference.get_ref();
595
596 assert_eq!(*reference.deref::<Integer>(), Integer::from(10));
597 assert_eq!(*ref_of_ref.deref::<Integer>(), Integer::from(10));
598
599 assert_ne!(number.get_ptr(), reference.get_ptr());
600 assert_ne!(number.get_ptr(), ref_of_ref.get_ptr());
601 assert_ne!(reference.get_ptr(), ref_of_ref.get_ptr());
602 assert_eq!(number.get_ptr(), (**reference.inner.borrow().dereference()).as_ptr());
603 assert_eq!(number.get_ptr(), (**ref_of_ref.inner.borrow().dereference()).as_ptr());
604
605 {
606 *reference.deref::<Integer>() += Integer::from(5);
607 }
608
609 assert_eq!(*number.get::<Integer>(), Integer::from(15));
610 assert_eq!(*reference.deref::<Integer>(), Integer::from(15));
611 assert_eq!(*ref_of_ref.deref::<Integer>(), Integer::from(15));
612
613 reference.assign(ObjectBlock::Int(Integer::from(20)).to_obj(), &ctx).unwrap();
614
615 assert_eq!(*number.get::<Integer>(), Integer::from(20));
616 assert_eq!(*reference.deref::<Integer>(), Integer::from(20));
617 assert_eq!(*ref_of_ref.deref::<Integer>(), Integer::from(20));
618 }
619
620 #[test]
621 fn value_moving() {
622 let number = Object::new(Integer::from(10));
623
624 assert_eq!(*number.get::<Integer>(), Integer::from(10));
625
626 let reference = number.get_mut();
627 let ref_of_ref = reference.get_mut();
628
629 assert_ne!(number.get_ptr(), reference.get_ptr());
630 assert_ne!(number.get_ptr(), ref_of_ref.get_ptr());
631 assert_ne!(reference.get_ptr(), ref_of_ref.get_ptr());
632 assert_eq!(number.get_ptr(), (**reference.inner.borrow().dereference()).as_ptr());
633 assert_eq!(number.get_ptr(), (**ref_of_ref.inner.borrow().dereference()).as_ptr());
634
635 assert_eq!(number.ref_count(), 3);
636
637 let number_2 = reference.move_contents();
638
639 assert!(number.is_moved());
640 assert!(reference.deref_obj().is_moved());
641 assert!(ref_of_ref.deref_obj().is_moved());
642 assert_eq!(number.ref_count(), 3);
643
644 assert!(!number_2.is_moved());
645 assert_eq!(number_2.ref_count(), 1);
646 assert_eq!(*number_2.get::<Integer>(), Integer::from(10));
647 }
648}