r/interpreter/native/
sexp.rs1use std::ffi::CStr;
11use std::os::raw::c_char;
12
13extern "C" {
16 fn calloc(count: usize, size: usize) -> *mut u8;
17 fn malloc(size: usize) -> *mut u8;
18 fn free(ptr: *mut u8);
19}
20
21pub const NILSXP: u8 = 0;
26pub const SYMSXP: u8 = 1;
27pub const LISTSXP: u8 = 2;
28pub const ENVSXP: u8 = 4;
29pub const LANGSXP: u8 = 6;
30pub const CHARSXP: u8 = 9;
31pub const LGLSXP: u8 = 10;
32pub const INTSXP: u8 = 13;
33pub const REALSXP: u8 = 14;
34pub const CPLXSXP: u8 = 15;
35pub const STRSXP: u8 = 16;
36pub const VECSXP: u8 = 19;
37pub const RAWSXP: u8 = 24;
38
39pub const NA_REAL: f64 = f64::from_bits(0x7FF00000000007A2);
45pub const NA_INTEGER: i32 = i32::MIN;
47pub const NA_LOGICAL: i32 = i32::MIN;
49
50pub fn is_na_real(x: f64) -> bool {
52 x.to_bits() == NA_REAL.to_bits()
53}
54
55#[repr(C)]
65pub struct SexpRec {
66 pub stype: u8,
68 pub flags: u8,
70 pub padding: u16,
72 pub length: i32,
74 pub data: *mut u8,
76 pub attrib: *mut SexpRec,
78}
79
80pub type Sexp = *mut SexpRec;
82
83#[repr(C)]
86pub struct PairlistData {
87 pub car: Sexp,
88 pub cdr: Sexp,
89 pub tag: Sexp,
90}
91
92pub const R_NIL_VALUE: Sexp = std::ptr::null_mut();
94
95pub fn alloc_vector(stype: u8, length: i32) -> Sexp {
101 unsafe {
102 let rec = calloc(1, std::mem::size_of::<SexpRec>()) as Sexp;
103 if rec.is_null() {
104 return R_NIL_VALUE;
105 }
106 (*rec).stype = stype;
107 (*rec).length = length;
108 (*rec).attrib = R_NIL_VALUE;
109
110 if length > 0 {
111 let len = length as usize;
112 (*rec).data = match stype {
113 REALSXP => calloc(len, std::mem::size_of::<f64>()),
114 INTSXP | LGLSXP => calloc(len, std::mem::size_of::<i32>()),
115 CPLXSXP => calloc(len, 2 * std::mem::size_of::<f64>()),
117 STRSXP | VECSXP => calloc(len, std::mem::size_of::<Sexp>()),
118 RAWSXP => calloc(len, 1),
119 _ => std::ptr::null_mut(),
120 };
121 }
122
123 rec
124 }
125}
126
127pub fn mk_char(s: &str) -> Sexp {
129 unsafe {
130 let rec = calloc(1, std::mem::size_of::<SexpRec>()) as Sexp;
131 if rec.is_null() {
132 return R_NIL_VALUE;
133 }
134 (*rec).stype = CHARSXP;
135 (*rec).length = s.len() as i32;
136
137 let buf = malloc(s.len() + 1);
138 if !buf.is_null() {
139 std::ptr::copy_nonoverlapping(s.as_ptr(), buf, s.len());
140 *buf.add(s.len()) = 0; }
142 (*rec).data = buf;
143 (*rec).attrib = R_NIL_VALUE;
144
145 rec
146 }
147}
148
149pub fn scalar_real(x: f64) -> Sexp {
151 let s = alloc_vector(REALSXP, 1);
152 if !s.is_null() {
153 unsafe { *((*s).data as *mut f64) = x };
154 }
155 s
156}
157
158pub fn scalar_integer(x: i32) -> Sexp {
160 let s = alloc_vector(INTSXP, 1);
161 if !s.is_null() {
162 unsafe { *((*s).data as *mut i32) = x };
163 }
164 s
165}
166
167pub fn scalar_logical(x: i32) -> Sexp {
169 let s = alloc_vector(LGLSXP, 1);
170 if !s.is_null() {
171 unsafe { *((*s).data as *mut i32) = x };
172 }
173 s
174}
175
176pub fn mk_string(s: &str) -> Sexp {
178 let strsxp = alloc_vector(STRSXP, 1);
179 let charsxp = mk_char(s);
180 if !strsxp.is_null() {
181 unsafe {
182 let elts = (*strsxp).data as *mut Sexp;
183 *elts = charsxp;
184 }
185 }
186 strsxp
187}
188
189pub fn mk_null() -> Sexp {
191 unsafe {
192 let rec = calloc(1, std::mem::size_of::<SexpRec>()) as Sexp;
193 if rec.is_null() {
194 return R_NIL_VALUE;
195 }
196 (*rec).stype = NILSXP;
197 rec
198 }
199}
200
201pub unsafe fn char_data(s: Sexp) -> &'static str {
210 if s.is_null() || (*s).data.is_null() {
211 return "";
212 }
213 let cstr = CStr::from_ptr((*s).data as *const c_char);
214 cstr.to_str().unwrap_or("")
215}
216
217pub unsafe fn real_ptr(s: Sexp) -> *mut f64 {
222 (*s).data as *mut f64
223}
224
225pub unsafe fn integer_ptr(s: Sexp) -> *mut i32 {
230 (*s).data as *mut i32
231}
232
233pub unsafe fn logical_ptr(s: Sexp) -> *mut i32 {
238 (*s).data as *mut i32
239}
240
241pub unsafe fn string_elt(s: Sexp, i: usize) -> Sexp {
246 let elts = (*s).data as *const Sexp;
247 *elts.add(i)
248}
249
250pub unsafe fn vector_elt(s: Sexp, i: usize) -> Sexp {
255 let elts = (*s).data as *const Sexp;
256 *elts.add(i)
257}
258
259pub unsafe fn free_sexp(s: Sexp) {
270 if s.is_null() {
271 return;
272 }
273 let rec = &*s;
274 if !rec.data.is_null() {
275 let len = rec.length.max(0) as usize;
276 match rec.stype {
277 STRSXP => {
278 let elts = rec.data as *mut Sexp;
280 for i in 0..len {
281 let elt = *elts.add(i);
282 if !elt.is_null() {
283 free_sexp(elt);
284 }
285 }
286 free(rec.data);
287 }
288 VECSXP => {
289 let elts = rec.data as *mut Sexp;
291 for i in 0..len {
292 let elt = *elts.add(i);
293 if !elt.is_null() {
294 free_sexp(elt);
295 }
296 }
297 free(rec.data);
298 }
299 ENVSXP => {
300 let env_ptr = rec.data as *mut crate::interpreter::environment::Environment;
302 drop(Box::from_raw(env_ptr));
303 }
304 _ => {
305 free(rec.data);
307 }
308 }
309 }
310 free(s as *mut u8);
312}
313
314