1use crate::core::cons::Cons;
3use crate::core::gc::Context;
4use crate::core::object::{
5 ByteFn, ByteString, FnArgs, Gc, IntoObject, LispVec, NIL, Object, RecordBuilder, Symbol,
6};
7use anyhow::{Result, ensure};
8use rune_macros::{defun, elprop};
9
10#[defun]
11pub(crate) fn list<'ob>(objects: &[Object<'ob>], cx: &'ob Context) -> Object<'ob> {
12 let mut head = NIL;
13 for object in objects.iter().rev() {
14 head = Cons::new(*object, head, cx).into();
15 }
16 head
17}
18
19#[defun]
22pub(crate) fn make_closure<'ob>(
23 prototype: &ByteFn,
24 closure_vars: &[Object<'ob>],
25 cx: &'ob Context,
26) -> Result<Gc<&'ob ByteFn>> {
27 let const_len = prototype.consts().len();
28 let vars = closure_vars.len();
29 ensure!(vars <= const_len, "Closure vars do not fit in const vec");
30 let mut constants = prototype.consts().to_vec();
31 let zipped = constants.iter_mut().zip(closure_vars.iter());
32 for (cnst, var) in zipped {
33 *cnst = *var;
34 }
35
36 unsafe {
37 Ok(ByteFn::make(
38 prototype.codes(),
39 constants.into_obj(cx).untag(),
40 prototype.args,
41 prototype.depth,
42 )
43 .into_obj(cx))
44 }
45}
46
47#[defun]
48#[expect(clippy::too_many_arguments)]
49pub(crate) fn make_byte_code<'ob>(
50 arglist: i64,
51 byte_code: &'ob ByteString,
52 constants: &'ob LispVec,
53 depth: usize,
54 _docstring: Option<Object>,
55 _interactive_spec: Option<Object>,
56 _elements: &[Object],
57 cx: &'ob Context,
58) -> Result<&'ob ByteFn> {
59 unsafe {
60 let bytefn = ByteFn::make(byte_code, constants, FnArgs::from_arg_spec(arglist)?, depth);
61 Ok(bytefn.into_obj(cx).untag())
62 }
63}
64
65#[defun]
66#[elprop(u8, _)]
67fn make_vector(length: usize, init: Object) -> Vec<Object> {
68 vec![init; length]
69}
70
71#[defun]
72fn vector<'ob>(objects: &[Object<'ob>]) -> Vec<Object<'ob>> {
73 objects.into()
74}
75
76#[defun]
77fn record<'ob>(type_: Object<'ob>, slots: &[Object<'ob>], cx: &'ob Context) -> RecordBuilder<'ob> {
78 let mut record = cx.vec_with_capacity(1 + slots.len());
79 record.push(type_);
80 record.extend_from_slice(slots);
81 RecordBuilder(record)
82}
83
84#[defun]
85fn purecopy(obj: Object) -> Object {
86 obj
87}
88
89#[defun]
90fn make_symbol<'ob>(name: &str, cx: &'ob Context) -> Symbol<'ob> {
91 Symbol::new_uninterned(name, cx)
92}
93
94#[defun]
95fn garbage_collect(cx: &mut Context) -> bool {
96 cx.garbage_collect(true);
97 true
98}
99
100#[cfg(test)]
101mod test {
102 use rune_core::macros::root;
103
104 use crate::core::{env::intern, gc::RootSet, object::ObjectType};
105
106 use super::*;
107
108 #[test]
109 fn build_record() {
110 let roots = &RootSet::default();
111 let cx = &mut Context::new(roots);
112 let type_ = intern("dummy-type", cx);
113 let slots = vec![cx.add("slot1"), cx.add("slot2")];
114 let record = record(type_.into(), &slots, cx);
115 assert_eq!(record.0.len(), 3);
116 assert_eq!(record.0[0], type_);
117 assert_eq!(record.0[1], slots[0]);
118 assert_eq!(record.0[2], slots[1]);
119 let x = cx.add(record);
120 root!(x, cx);
121 cx.garbage_collect(true);
122 let ObjectType::Record(record) = x.bind(cx).untag() else { unreachable!() };
123 assert_eq!(record.len(), 3);
124 assert_eq!(record[1].get(), "slot1");
125 assert_eq!(record[2].get(), "slot2");
126 }
127}