atmos/os_lib/aura/builtins/
arith.rs1use super::*;
4
5pub(crate) fn builtin_add(env: &mut Env, args: &[AST]) -> Result<Value, String> {
6 let vals = eval_args(env, args)?;
7 let mut sum = BigInt::zero();
8 let mut r_sum = Ratio::from_bigint(BigInt::zero());
9 let mut c_sum = Complex::new(
10 Ratio::from_bigint(BigInt::zero()),
11 Ratio::from_bigint(BigInt::zero()),
12 );
13 let mut mode = 0; for val in vals {
16 match val {
17 Value::Num(n) => {
18 if mode == 2 {
19 c_sum = c_sum.add(&Complex::new(
20 Ratio::from_bigint(n),
21 Ratio::from_bigint(BigInt::zero()),
22 ));
23 } else if mode == 1 {
24 r_sum = r_sum.add(&Ratio::from_bigint(n));
25 } else {
26 sum = sum.add(&n);
27 }
28 }
29 Value::Ratio(r) => {
30 if mode == 2 {
31 c_sum = c_sum.add(&Complex::new(r, Ratio::from_bigint(BigInt::zero())));
32 } else if mode == 0 {
33 mode = 1;
34 r_sum = Ratio::from_bigint(sum.clone()).add(&r);
35 } else {
36 r_sum = r_sum.add(&r);
37 }
38 }
39 Value::Complex(c) => {
40 if mode == 0 {
41 c_sum = Complex::new(
42 Ratio::from_bigint(sum.clone()),
43 Ratio::from_bigint(BigInt::zero()),
44 )
45 .add(&c);
46 } else if mode == 1 {
47 c_sum = Complex::new(r_sum.clone(), Ratio::from_bigint(BigInt::zero())).add(&c);
48 } else {
49 c_sum = c_sum.add(&c);
50 }
51 mode = 2;
52 }
53 _ => return Err(String::from("Invalid argument for +")),
54 }
55 }
56
57 if mode == 2 {
58 Ok(Value::Complex(c_sum))
59 } else if mode == 1 {
60 if r_sum.den == BigInt::one() {
61 Ok(Value::Num(r_sum.num))
62 } else {
63 Ok(Value::Ratio(r_sum))
64 }
65 } else {
66 Ok(Value::Num(sum))
67 }
68}
69
70pub(crate) fn builtin_sub(env: &mut Env, args: &[AST]) -> Result<Value, String> {
71 let vals = eval_args(env, args)?;
72 if vals.is_empty() {
73 return Err(String::from("Missing arguments for -"));
74 }
75
76 let mut first = true;
77 let mut res = BigInt::zero();
78 let mut r_res = Ratio::from_bigint(BigInt::zero());
79 let mut c_res = Complex::new(
80 Ratio::from_bigint(BigInt::zero()),
81 Ratio::from_bigint(BigInt::zero()),
82 );
83 let mut mode = 0;
84
85 for val in vals {
86 match val {
87 Value::Num(n) => {
88 if first {
89 res = n;
90 first = false;
91 } else {
92 if mode == 2 {
93 c_res = c_res.sub(&Complex::new(
94 Ratio::from_bigint(n),
95 Ratio::from_bigint(BigInt::zero()),
96 ));
97 } else if mode == 1 {
98 r_res = r_res.sub(&Ratio::from_bigint(n));
99 } else {
100 res = res.sub(&n);
101 }
102 }
103 }
104 Value::Ratio(r) => {
105 if first {
106 mode = 1;
107 r_res = r;
108 first = false;
109 } else {
110 if mode == 2 {
111 c_res = c_res.sub(&Complex::new(r, Ratio::from_bigint(BigInt::zero())));
112 } else if mode == 0 {
113 mode = 1;
114 r_res = Ratio::from_bigint(res.clone()).sub(&r);
115 } else {
116 r_res = r_res.sub(&r);
117 }
118 }
119 }
120 Value::Complex(c) => {
121 if first {
122 mode = 2;
123 c_res = c;
124 first = false;
125 } else {
126 if mode == 0 {
127 c_res = Complex::new(
128 Ratio::from_bigint(res.clone()),
129 Ratio::from_bigint(BigInt::zero()),
130 )
131 .sub(&c);
132 } else if mode == 1 {
133 c_res =
134 Complex::new(r_res.clone(), Ratio::from_bigint(BigInt::zero())).sub(&c);
135 } else {
136 c_res = c_res.sub(&c);
137 }
138 mode = 2;
139 }
140 }
141 _ => return Err(String::from("Invalid argument for -")),
142 }
143 }
144
145 if mode == 2 {
146 Ok(Value::Complex(c_res))
147 } else if mode == 1 {
148 if r_res.den == BigInt::one() {
149 Ok(Value::Num(r_res.num))
150 } else {
151 Ok(Value::Ratio(r_res))
152 }
153 } else {
154 Ok(Value::Num(res))
155 }
156}
157
158pub(crate) fn builtin_mul(env: &mut Env, args: &[AST]) -> Result<Value, String> {
159 let vals = eval_args(env, args)?;
160 let mut prod = BigInt::one();
161 let mut r_prod = Ratio::from_bigint(BigInt::one());
162 let mut c_prod = Complex::new(
163 Ratio::from_bigint(BigInt::one()),
164 Ratio::from_bigint(BigInt::zero()),
165 );
166 let mut mode = 0;
167
168 for val in vals {
169 match val {
170 Value::Num(n) => {
171 if mode == 2 {
172 c_prod = c_prod.mul(&Complex::new(
173 Ratio::from_bigint(n),
174 Ratio::from_bigint(BigInt::zero()),
175 ));
176 } else if mode == 1 {
177 r_prod = r_prod.mul(&Ratio::from_bigint(n));
178 } else {
179 prod = prod.mul(&n);
180 }
181 }
182 Value::Ratio(r) => {
183 if mode == 2 {
184 c_prod = c_prod.mul(&Complex::new(r, Ratio::from_bigint(BigInt::zero())));
185 } else if mode == 0 {
186 mode = 1;
187 r_prod = Ratio::from_bigint(prod.clone()).mul(&r);
188 } else {
189 r_prod = r_prod.mul(&r);
190 }
191 }
192 Value::Complex(c) => {
193 if mode == 0 {
194 c_prod = Complex::new(
195 Ratio::from_bigint(prod.clone()),
196 Ratio::from_bigint(BigInt::zero()),
197 )
198 .mul(&c);
199 } else if mode == 1 {
200 c_prod =
201 Complex::new(r_prod.clone(), Ratio::from_bigint(BigInt::zero())).mul(&c);
202 } else {
203 c_prod = c_prod.mul(&c);
204 }
205 mode = 2;
206 }
207 _ => return Err(String::from("Invalid argument for *")),
208 }
209 }
210
211 if mode == 2 {
212 Ok(Value::Complex(c_prod))
213 } else if mode == 1 {
214 if r_prod.den == BigInt::one() {
215 Ok(Value::Num(r_prod.num))
216 } else {
217 Ok(Value::Ratio(r_prod))
218 }
219 } else {
220 Ok(Value::Num(prod))
221 }
222}
223
224pub(crate) fn builtin_div(env: &mut Env, args: &[AST]) -> Result<Value, String> {
225 let vals = eval_args(env, args)?;
226 if vals.is_empty() {
227 return Err(String::from("Missing arguments for /"));
228 }
229
230 let mut first = true;
231 let mut r_res = Ratio::from_bigint(BigInt::zero());
232 let mut c_res = Complex::new(
233 Ratio::from_bigint(BigInt::zero()),
234 Ratio::from_bigint(BigInt::zero()),
235 );
236 let mut is_complex = false;
237
238 for val in vals {
239 match val {
240 Value::Num(n) => {
241 let r = Ratio::from_bigint(n);
242 if first {
243 r_res = r;
244 first = false;
245 } else {
246 if is_complex {
247 if let Some(res) =
248 c_res.div(&Complex::new(r, Ratio::from_bigint(BigInt::zero())))
249 {
250 c_res = res;
251 } else {
252 return Err(String::from("Division by zero"));
253 }
254 } else {
255 if let Some(res) = r_res.div(&r) {
256 r_res = res;
257 } else {
258 return Err(String::from("Division by zero"));
259 }
260 }
261 }
262 }
263 Value::Ratio(r) => {
264 if first {
265 r_res = r;
266 first = false;
267 } else {
268 if is_complex {
269 if let Some(res) =
270 c_res.div(&Complex::new(r, Ratio::from_bigint(BigInt::zero())))
271 {
272 c_res = res;
273 } else {
274 return Err(String::from("Division by zero"));
275 }
276 } else {
277 if let Some(res) = r_res.div(&r) {
278 r_res = res;
279 } else {
280 return Err(String::from("Division by zero"));
281 }
282 }
283 }
284 }
285 Value::Complex(c) => {
286 if first {
287 is_complex = true;
288 c_res = c;
289 first = false;
290 } else {
291 if !is_complex {
292 is_complex = true;
293 c_res = Complex::new(r_res.clone(), Ratio::from_bigint(BigInt::zero()));
294 }
295 if let Some(res) = c_res.div(&c) {
296 c_res = res;
297 } else {
298 return Err(String::from("Division by zero"));
299 }
300 }
301 }
302 _ => return Err(String::from("Invalid argument for /")),
303 }
304 }
305
306 if is_complex {
307 Ok(Value::Complex(c_res))
308 } else {
309 if r_res.den == BigInt::one() {
310 Ok(Value::Num(r_res.num))
311 } else {
312 Ok(Value::Ratio(r_res))
313 }
314 }
315}
316
317pub(crate) fn builtin_if(env: &mut Env, args: &[AST]) -> Result<Value, String> {
320 if args.len() != 3 {
321 return Err(String::from(
322 "if requires exactly 3 arguments (cond true_branch false_branch)",
323 ));
324 }
325 let cond_val = eval(env, &args[0])?;
326 let cond_val = force_eval(env, cond_val)?;
327
328 if super::super::eval::is_truthy(&cond_val)? {
329 eval(env, &args[1])
330 } else {
331 eval(env, &args[2])
332 }
333}
334
335pub(crate) fn builtin_condition(env: &mut Env, args: &[AST]) -> Result<Value, String> {
336 for arg in args {
337 if let AST::List(pair) = arg {
338 if pair.len() != 2 {
339 return Err(String::from("condition requires (cond expr) pairs"));
340 }
341
342 let is_else = if let AST::Symbol(s) = &pair[0] {
343 s == "else"
344 } else {
345 false
346 };
347
348 if is_else {
349 return eval(env, &pair[1]);
350 } else {
351 let eval_cond = eval(env, &pair[0])?;
352 let cond_val = force_eval(env, eval_cond)?;
353 if super::super::eval::is_truthy(&cond_val)? {
354 return eval(env, &pair[1]);
355 }
356 }
357 } else {
358 return Err(String::from(
359 "condition arguments must be lists like (cond expr)",
360 ));
361 }
362 }
363 Ok(Value::Nil)
364}
365
366pub(crate) fn builtin_case(env: &mut Env, args: &[AST]) -> Result<Value, String> {
367 if args.is_empty() {
368 return Err(String::from("case requires a target value"));
369 }
370 let eval_target = eval(env, &args[0])?;
371 let target_val = force_eval(env, eval_target)?;
372
373 for arg in &args[1..] {
374 if let AST::List(pair) = arg {
375 if pair.len() != 2 {
376 return Err(String::from("case requires (value expr) pairs"));
377 }
378
379 let is_else = if let AST::Symbol(s) = &pair[0] {
380 s == "else"
381 } else {
382 false
383 };
384 if is_else {
385 return eval(env, &pair[1]);
386 } else {
387 let eval_match = eval(env, &pair[0])?;
388 let match_val = force_eval(env, eval_match)?;
389 if values_equal(&target_val, &match_val) {
390 return eval(env, &pair[1]);
391 }
392 }
393 } else {
394 return Err(String::from(
395 "case arguments must be lists like (value expr)",
396 ));
397 }
398 }
399 Ok(Value::Nil)
400}
401
402