Skip to main content

atmos/os_lib/aura/builtins/
arith.rs

1// 分割: aura/builtins.rs より機械的に移動(2026-07-16 リファクタ フェーズ6)。
2// ロジック不変。可視性のみ pub(crate) へ昇格し、親が pub(crate) use で再エクスポート。
3use 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; // 0: Num, 1: Ratio, 2: Complex
14
15    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
317// builtin_def was removed and integrated into builtin_set
318
319pub(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// ----------------------------------------------------
403// 比較演算子・論理演算子の実装
404// ----------------------------------------------------
405