]> Witch of Git - ivy/blob - rt/src/lam.rs
[tools] Add tools/test.py as the project test runner
[ivy] / rt / src / lam.rs
1 use crate::{sys, trace, Obj, ObjHeader, ObjTag};
2 use std::sync::atomic::AtomicU32;
3
4 #[repr(C)]
5 pub struct ObjLam {
6 tag: ObjTag,
7 _pad: [u8; 1],
8 upvars: u16,
9 rc: AtomicU32,
10 func: extern "C" fn(&ObjLam) -> Obj,
11 params: u16,
12 filled: u16,
13 }
14
15 #[no_mangle]
16 pub unsafe extern "C" fn ivy_check_lam(obj: Obj) {
17 if obj.tag() != Some(ObjTag::Lam) {
18 panic!(
19 "ivy_check_lam called with non-lambda object {:016x}.",
20 obj.int
21 );
22 }
23 }
24
25 #[no_mangle]
26 pub unsafe extern "C" fn ivy_make_lam(
27 func: extern "C" fn(&ObjLam) -> Obj,
28 params: u16,
29 upvars: u16,
30 ) -> Obj {
31 let size = ObjLam::size_of(params, upvars);
32 let box_lam = sys::malloc(size) as *mut ObjLam;
33 box_lam.write(ObjLam {
34 tag: ObjTag::Lam,
35 _pad: [0; 1],
36 upvars,
37 rc: AtomicU32::new(1),
38 func,
39 params,
40 filled: 0,
41 });
42 (*box_lam)
43 .raw_fields_mut()
44 .write_bytes(0, (params + upvars) as usize);
45 trace!("MAKE {:016x} {:016x}", box_lam as usize, func as usize);
46 Obj { box_lam }
47 }
48
49 #[no_mangle]
50 pub unsafe extern "C" fn ivy_clone_lam(lam: &ObjLam) -> *mut ObjLam {
51 let size = lam.size();
52 let data = sys::malloc(size);
53 core::ptr::copy(lam as *const _ as *const u8, data, size);
54 let box_hdr = data as *mut ObjHeader;
55 *(*box_hdr).rc.get_mut() = 1;
56 trace!(
57 "COPY {:016x} {:016x}",
58 lam as *const _ as usize,
59 box_hdr as usize
60 );
61 data as *mut ObjLam
62 }
63
64 #[no_mangle]
65 pub unsafe extern "C" fn ivy_app(fun: Obj, arg: Obj) -> Obj {
66 ivy_app_mut(crate::ivy_clone(fun), arg)
67 }
68
69 #[no_mangle]
70 pub unsafe extern "C" fn ivy_app_mut(fun: Obj, arg: Obj) -> Obj {
71 trace!("APP {:016x} {:016x}", fun.int, arg.int);
72 if fun.tag() != Some(ObjTag::Lam) {
73 panic!(
74 "ivy_app called with a non-lam as the function: {:016x}.",
75 fun.int
76 );
77 }
78 let lam = &mut *fun.box_lam;
79 if lam.filled < lam.params {
80 if arg.is_null() {
81 println!(
82 "Lam @ {:016x} ({:016x}) has {} of {} arguments filled.",
83 fun.int, lam.func as usize, lam.filled, lam.params
84 );
85 panic!("ivy_app called with a null arg.");
86 }
87 arg.incref();
88 let idx = lam.filled as usize;
89 lam.params_mut()[idx] = arg;
90 lam.filled += 1;
91 } else if lam.params == lam.filled {
92 if !arg.is_null() {
93 panic!("ivy_app called for a 0-arity application with a non-null arg.");
94 }
95 }
96
97 if lam.params == lam.filled {
98 trace!("RUN {:016x}", fun.int);
99 (lam.func)(lam)
100 } else {
101 trace!("UPD8 {:016x}", fun.int);
102 fun
103 }
104 }
105
106 impl ObjLam {
107 pub(crate) fn size_of(params: u16, upvars: u16) -> usize {
108 let obj_size = core::mem::size_of::<Obj>();
109 core::mem::size_of::<ObjLam>() + params as usize * obj_size + upvars as usize * obj_size
110 }
111
112 pub(crate) fn size(&self) -> usize {
113 ObjLam::size_of(self.params, self.upvars)
114 }
115
116 fn raw_fields_mut(&self) -> *mut Obj {
117 unsafe { (self as *const ObjLam).add(1) as *mut Obj }
118 }
119
120 unsafe fn params_mut(&mut self) -> &mut [Obj] {
121 let ptr = self.raw_fields_mut();
122 core::slice::from_raw_parts_mut(ptr, self.params as usize)
123 }
124
125 pub(crate) fn params(&self) -> &[Obj] {
126 let ptr = self.raw_fields_mut();
127 unsafe { core::slice::from_raw_parts(ptr, self.params as usize) }
128 }
129
130 pub(crate) fn upvars(&self) -> &[Obj] {
131 unsafe {
132 let ptr = self.raw_fields_mut().add(self.params as usize);
133 core::slice::from_raw_parts(ptr, self.upvars as usize)
134 }
135 }
136 }