1mod error;
2mod primitive;
3
4pub use self::error::Error;
5use self::primitive::Primitive;
6use core::ops::{Add, Div, Mul, Rem, Sub};
7use stak_device::{Device, DevicePrimitiveSet};
8use stak_file::{FilePrimitiveSet, FileSystem};
9use stak_inexact::InexactPrimitiveSet;
10use stak_native::{EqualPrimitiveSet, ListPrimitiveSet, TypeCheckPrimitiveSet};
11use stak_process_context::{ProcessContext, ProcessContextPrimitiveSet};
12use stak_time::{Clock, TimePrimitiveSet};
13use stak_vm::{Memory, Number, PrimitiveSet, Tag, Type, Value};
14use winter_maybe_async::{maybe_async, maybe_await};
15
16pub struct SmallPrimitiveSet<D: Device, F: FileSystem, P: ProcessContext, C: Clock> {
18 device: DevicePrimitiveSet<D>,
19 file: FilePrimitiveSet<F>,
20 process_context: ProcessContextPrimitiveSet<P>,
21 time: TimePrimitiveSet<C>,
22 inexact: InexactPrimitiveSet,
23 equal: EqualPrimitiveSet,
24 type_check: TypeCheckPrimitiveSet,
25 list: ListPrimitiveSet,
26}
27
28impl<D: Device, F: FileSystem, P: ProcessContext, C: Clock> SmallPrimitiveSet<D, F, P, C> {
29 pub fn new(device: D, file_system: F, process_context: P, clock: C) -> Self {
31 Self {
32 device: DevicePrimitiveSet::new(device),
33 file: FilePrimitiveSet::new(file_system),
34 process_context: ProcessContextPrimitiveSet::new(process_context),
35 time: TimePrimitiveSet::new(clock),
36 inexact: Default::default(),
37 equal: Default::default(),
38 type_check: Default::default(),
39 list: Default::default(),
40 }
41 }
42
43 pub fn device(&self) -> &D {
45 self.device.device()
46 }
47
48 pub fn device_mut(&mut self) -> &mut D {
50 self.device.device_mut()
51 }
52
53 fn operate_comparison(
54 memory: &mut Memory,
55 operate: fn(Number, Number) -> bool,
56 ) -> Result<(), Error> {
57 let [x, y] = memory.pop_numbers()?;
58
59 memory.push(memory.boolean(operate(x, y))?.into())?;
60 Ok(())
61 }
62
63 fn rib(memory: &mut Memory, car: Value, cdr: Value, tag: Tag) -> Result<(), Error> {
64 let rib = memory.allocate(car, cdr.set_tag(tag))?;
65 memory.push(rib.into())?;
66 Ok(())
67 }
68
69 #[inline(always)]
72 fn set_field<'a>(
73 memory: &mut Memory<'a>,
74 set_field: fn(&mut Memory<'a>, Value, Value) -> Result<(), stak_vm::Error>,
75 ) -> Result<(), Error> {
76 let [x, y] = memory.pop_many()?;
77
78 set_field(memory, x, y)?;
79 memory.push(y)?;
80 Ok(())
81 }
82
83 fn tag<'a>(
84 memory: &mut Memory<'a>,
85 field: impl Fn(&Memory<'a>, Value) -> Result<Value, stak_vm::Error>,
86 ) -> Result<(), Error> {
87 memory.operate_top(|memory, value| {
88 Ok(if let Some(cons) = field(memory, value)?.to_cons() {
89 Number::from_i64(cons.tag() as _)
90 } else {
91 Default::default()
92 }
93 .into())
94 })?;
95
96 Ok(())
97 }
98}
99
100impl<D: Device, F: FileSystem, P: ProcessContext, C: Clock> PrimitiveSet
101 for SmallPrimitiveSet<D, F, P, C>
102{
103 type Error = Error;
104
105 #[maybe_async]
106 fn operate(&mut self, memory: &mut Memory<'_>, primitive: usize) -> Result<(), Self::Error> {
107 match primitive {
108 Primitive::RIB => {
109 let [car, cdr, tag] = memory.pop_many()?;
110
111 Self::rib(memory, car, cdr, tag.assume_number().to_i64() as _)?;
112 }
113 Primitive::CLOSE => {
114 let closure = memory.pop()?;
115
116 Self::rib(
117 memory,
118 memory.car_value(closure)?,
119 memory.stack().into(),
120 Type::Procedure as _,
121 )?;
122 }
123 Primitive::IS_RIB => {
124 memory.operate_top(|memory, value| Ok(memory.boolean(value.is_cons())?.into()))?
125 }
126 Primitive::CAR => memory.operate_top(Memory::car_value)?,
127 Primitive::CDR => memory.operate_top(Memory::cdr_value)?,
128 Primitive::TAG => Self::tag(memory, Memory::cdr_value)?,
129 Primitive::SET_CAR => Self::set_field(memory, Memory::set_car_value)?,
130 Primitive::SET_CDR => Self::set_field(memory, Memory::set_cdr_value)?,
131 Primitive::EQUAL => {
132 let [x, y] = memory.pop_many()?;
133 memory.push(memory.boolean(x == y)?.into())?;
134 }
135 Primitive::LESS_THAN => Self::operate_comparison(memory, |x, y| x < y)?,
136 Primitive::ADD => memory.operate_binary(Add::add)?,
137 Primitive::SUBTRACT => memory.operate_binary(Sub::sub)?,
138 Primitive::MULTIPLY => memory.operate_binary(Mul::mul)?,
139 Primitive::DIVIDE => memory.operate_binary(Div::div)?,
140 Primitive::REMAINDER => memory.operate_binary(Rem::rem)?,
141 Primitive::EXPONENTIATION
142 | Primitive::LOGARITHM
143 | Primitive::INFINITE
144 | Primitive::NAN
145 | Primitive::SQRT
146 | Primitive::COS
147 | Primitive::SIN
148 | Primitive::TAN
149 | Primitive::ACOS
150 | Primitive::ASIN
151 | Primitive::ATAN => maybe_await!(
152 self.inexact
153 .operate(memory, primitive - Primitive::EXPONENTIATION)
154 )?,
155 Primitive::HALT => return Err(Error::Halt),
156 Primitive::NULL | Primitive::PAIR => {
157 maybe_await!(self.type_check.operate(memory, primitive - Primitive::NULL))?
158 }
159 Primitive::ASSQ | Primitive::CONS | Primitive::MEMQ => {
160 maybe_await!(self.list.operate(memory, primitive - Primitive::ASSQ))?
161 }
162 Primitive::EQV | Primitive::EQUAL_INNER => {
163 maybe_await!(self.equal.operate(memory, primitive - Primitive::EQV))?
164 }
165 Primitive::READ | Primitive::WRITE | Primitive::WRITE_ERROR => {
166 maybe_await!(self.device.operate(memory, primitive - Primitive::READ))?
167 }
168 Primitive::OPEN_FILE
169 | Primitive::CLOSE_FILE
170 | Primitive::READ_FILE
171 | Primitive::WRITE_FILE
172 | Primitive::DELETE_FILE
173 | Primitive::EXISTS_FILE
174 | Primitive::FLUSH_FILE => {
175 maybe_await!(self.file.operate(memory, primitive - Primitive::OPEN_FILE))?
176 }
177 Primitive::COMMAND_LINE | Primitive::ENVIRONMENT_VARIABLES => maybe_await!(
178 self.process_context
179 .operate(memory, primitive - Primitive::COMMAND_LINE)
180 )?,
181 Primitive::CURRENT_JIFFY | Primitive::JIFFIES_PER_SECOND => maybe_await!(
182 self.time
183 .operate(memory, primitive - Primitive::CURRENT_JIFFY)
184 )?,
185 _ => return Err(stak_vm::Error::IllegalPrimitive.into()),
186 }
187
188 Ok(())
189 }
190}