kalc_lib/
load_vars.rs

1use crate::{
2    complex::NumStr::Num,
3    math::do_math,
4    options::set_commands,
5    parse::input_var,
6    units::{Colors, Number, Options, Variable},
7};
8use rug::{Float, float::Constant::Pi};
9pub fn get_file_vars(
10    options: Options,
11    vars: &mut Vec<Variable>,
12    lines: Vec<String>,
13    r: &str,
14    blacklist: &mut Vec<String>,
15)
16{
17    if r.chars().all(|c| !c.is_alphabetic())
18    {
19        return;
20    }
21    get_preset_vars(options, r, vars, blacklist);
22    'lower: for i in lines.clone()
23    {
24        let mut split = i.splitn(2, '=');
25        if split.clone().count() == 2
26        {
27            let l = split.next().unwrap().to_string();
28            let left = if l.contains('(')
29            {
30                l.split('(').next().unwrap().to_owned()
31            }
32            else
33            {
34                l.clone()
35            };
36            if !blacklist.contains(&l) && {
37                let mut word = String::new();
38                let mut b = false;
39                for c in r.chars()
40                {
41                    if c.is_alphanumeric() || matches!(c, '\'' | '`' | '_')
42                    {
43                        word.push(c)
44                    }
45                    else
46                    {
47                        if l.contains('(')
48                        {
49                            b = word.trim_end_matches('\'').trim_end_matches('`') == left
50                                && matches!(c, '(' | '{' | '[' | '|');
51                        }
52                        else
53                        {
54                            b = word == left;
55                        }
56                        if b
57                        {
58                            break;
59                        }
60                        word.clear()
61                    }
62                }
63                b
64            }
65            {
66                if let Some(r) = split.next()
67                {
68                    let le = l.chars().collect::<Vec<char>>();
69                    blacklist.push(l.clone());
70                    get_file_vars(options, vars, lines.clone(), r, blacklist);
71                    for (i, j) in vars.iter().enumerate()
72                    {
73                        if j.name.len() <= le.len()
74                        {
75                            if let Err(s) = add_var(le, r, i, vars, options, false, false, false)
76                            {
77                                println!("{s}")
78                            }
79                            continue 'lower;
80                        }
81                    }
82                    if let Err(s) = add_var(le, r, 0, vars, options, false, false, false)
83                    {
84                        println!("{s}")
85                    }
86                }
87            }
88        }
89    }
90}
91fn get_preset_vars(
92    options: Options,
93    args: &str,
94    vars: &mut Vec<Variable>,
95    blacklist: &mut Vec<String>,
96)
97{
98    {
99        let phi1 = args.contains("phi") && !blacklist.contains(&"phi".to_string());
100        let phi2 = args.contains('φ') && !blacklist.contains(&"φ".to_string());
101        if phi1 || phi2
102        {
103            let phi: Float = (1 + Float::with_val(options.prec, 5).sqrt()) / 2;
104            if phi1
105            {
106                blacklist.push("phi".to_string());
107                vars.insert(
108                    0,
109                    Variable {
110                        name: vec!['p', 'h', 'i'],
111                        parsed: vec![Num(Number::from(phi.clone().into(), None))],
112                        unparsed: String::new(),
113                        funcvars: Vec::new(),
114                    },
115                );
116            }
117            if phi2
118            {
119                blacklist.push("φ".to_string());
120                vars.push(Variable {
121                    name: vec!['φ'],
122                    parsed: vec![Num(Number::from(phi.into(), None))],
123                    unparsed: String::new(),
124                    funcvars: Vec::new(),
125                });
126            }
127        }
128    }
129    {
130        let pi1 = args.contains("pi") && !blacklist.contains(&"pi".to_string());
131        let pi2 = args.contains('π') && !blacklist.contains(&"π".to_string());
132        let tau1 = args.contains("tau") && !blacklist.contains(&"tau".to_string());
133        let tau2 = args.contains('τ') && !blacklist.contains(&"τ".to_string());
134        if pi1 || pi2 || tau1 || tau2
135        {
136            let pi = Float::with_val(options.prec, Pi);
137            if pi1
138            {
139                blacklist.push("pi".to_string());
140                vars.insert(
141                    vars.iter().position(|c| c.name.len() != 3).unwrap_or(0),
142                    Variable {
143                        name: vec!['p', 'i'],
144                        parsed: vec![Num(Number::from(pi.clone().into(), None))],
145                        unparsed: String::new(),
146                        funcvars: Vec::new(),
147                    },
148                );
149            }
150            if pi2
151            {
152                blacklist.push("π".to_string());
153                vars.push(Variable {
154                    name: vec!['π'],
155                    parsed: vec![Num(Number::from(pi.clone().into(), None))],
156                    unparsed: String::new(),
157                    funcvars: Vec::new(),
158                });
159            }
160            if tau1 || tau2
161            {
162                let tau: Float = pi.clone() * 2;
163                if tau1
164                {
165                    blacklist.push("tau".to_string());
166                    vars.insert(
167                        0,
168                        Variable {
169                            name: vec!['t', 'a', 'u'],
170                            parsed: vec![Num(Number::from(tau.clone().into(), None))],
171                            unparsed: String::new(),
172                            funcvars: Vec::new(),
173                        },
174                    );
175                }
176                if tau2
177                {
178                    blacklist.push("τ".to_string());
179                    vars.push(Variable {
180                        name: vec!['τ'],
181                        parsed: vec![Num(Number::from(tau.into(), None))],
182                        unparsed: String::new(),
183                        funcvars: Vec::new(),
184                    });
185                }
186            }
187        }
188    }
189    if args.contains('e') && !blacklist.contains(&"e".to_string())
190    {
191        blacklist.push("e".to_string());
192        let e = Float::with_val(options.prec, 1).exp();
193        vars.push(Variable {
194            name: vec!['e'],
195            parsed: vec![Num(Number::from(e.into(), None))],
196            unparsed: String::new(),
197            funcvars: Vec::new(),
198        });
199    }
200}
201pub fn get_cli_vars(options: Options, args: String, vars: &mut Vec<Variable>)
202{
203    if args.chars().all(|c| !c.is_alphabetic())
204    {
205        return;
206    }
207    {
208        let phi1 = args.contains("phi");
209        let phi2 = args.contains('φ');
210        if phi1 || phi2
211        {
212            let phi: Float = (1 + Float::with_val(options.prec, 5).sqrt()) / 2;
213            if phi1
214            {
215                vars.insert(
216                    0,
217                    Variable {
218                        name: vec!['p', 'h', 'i'],
219                        parsed: vec![Num(Number::from(phi.clone().into(), None))],
220                        unparsed: String::new(),
221                        funcvars: Vec::new(),
222                    },
223                );
224            }
225            if phi2
226            {
227                vars.push(Variable {
228                    name: vec!['φ'],
229                    parsed: vec![Num(Number::from(phi.into(), None))],
230                    unparsed: String::new(),
231                    funcvars: Vec::new(),
232                });
233            }
234        }
235    }
236    {
237        let pi1 = args.contains("pi");
238        let pi2 = args.contains('π');
239        let tau1 = args.contains("tau");
240        let tau2 = args.contains('τ');
241        if pi1 || pi2 || tau1 || tau2
242        {
243            let pi = Float::with_val(options.prec, Pi);
244            if pi1
245            {
246                vars.insert(
247                    vars.iter().position(|c| c.name.len() != 3).unwrap_or(0),
248                    Variable {
249                        name: vec!['p', 'i'],
250                        parsed: vec![Num(Number::from(pi.clone().into(), None))],
251                        unparsed: String::new(),
252                        funcvars: Vec::new(),
253                    },
254                );
255            }
256            if pi2
257            {
258                vars.push(Variable {
259                    name: vec!['π'],
260                    parsed: vec![Num(Number::from(pi.clone().into(), None))],
261                    unparsed: String::new(),
262                    funcvars: Vec::new(),
263                });
264            }
265            if tau1 || tau2
266            {
267                let tau: Float = pi.clone() * 2;
268                if tau1
269                {
270                    vars.insert(
271                        0,
272                        Variable {
273                            name: vec!['t', 'a', 'u'],
274                            parsed: vec![Num(Number::from(tau.clone().into(), None))],
275                            unparsed: String::new(),
276                            funcvars: Vec::new(),
277                        },
278                    );
279                }
280                if tau2
281                {
282                    vars.push(Variable {
283                        name: vec!['τ'],
284                        parsed: vec![Num(Number::from(tau.into(), None))],
285                        unparsed: String::new(),
286                        funcvars: Vec::new(),
287                    });
288                }
289            }
290        }
291    }
292    if args.contains('e')
293    {
294        let e = Float::with_val(options.prec, 1).exp();
295        vars.push(Variable {
296            name: vec!['e'],
297            parsed: vec![Num(Number::from(e.into(), None))],
298            unparsed: String::new(),
299            funcvars: Vec::new(),
300        });
301    }
302}
303pub fn get_vars(options: Options) -> Vec<Variable>
304{
305    let pi = Float::with_val(options.prec, Pi);
306    let tau: Float = pi.clone() * 2;
307    let phi: Float = (1 + Float::with_val(options.prec, 5).sqrt()) / 2;
308    let e = Float::with_val(options.prec, 1).exp();
309    vec![
310        Variable {
311            name: vec!['p', 'h', 'i'],
312            parsed: vec![Num(Number::from(phi.clone().into(), None))],
313            unparsed: String::new(),
314            funcvars: Vec::new(),
315        },
316        Variable {
317            name: vec!['t', 'a', 'u'],
318            parsed: vec![Num(Number::from(tau.clone().into(), None))],
319            unparsed: String::new(),
320            funcvars: Vec::new(),
321        },
322        Variable {
323            name: vec!['p', 'i'],
324            parsed: vec![Num(Number::from(pi.clone().into(), None))],
325            unparsed: String::new(),
326            funcvars: Vec::new(),
327        },
328        Variable {
329            name: vec!['e'],
330            parsed: vec![Num(Number::from(e.into(), None))],
331            unparsed: String::new(),
332            funcvars: Vec::new(),
333        },
334        Variable {
335            name: vec!['φ'],
336            parsed: vec![Num(Number::from(phi.into(), None))],
337            unparsed: String::new(),
338            funcvars: Vec::new(),
339        },
340        Variable {
341            name: vec!['π'],
342            parsed: vec![Num(Number::from(pi.into(), None))],
343            unparsed: String::new(),
344            funcvars: Vec::new(),
345        },
346        Variable {
347            name: vec!['τ'],
348            parsed: vec![Num(Number::from(tau.into(), None))],
349            unparsed: String::new(),
350            funcvars: Vec::new(),
351        },
352    ]
353}
354#[allow(clippy::too_many_arguments)]
355pub fn add_var(
356    l: Vec<char>,
357    mut r: &str,
358    i: usize,
359    vars: &mut Vec<Variable>,
360    options: Options,
361    redef: bool,
362    replace: bool,
363    null: bool,
364) -> Result<(), &'static str>
365{
366    if null
367    {
368        vars.remove(i);
369    }
370    else
371    {
372        let orig = r;
373        let mut func_vars: Vec<(isize, String)> = Vec::new();
374        if l.contains(&'(')
375        {
376            let mut l = l.clone();
377            l.pop();
378            let st = l
379                .drain(0..=l.iter().position(|c| c == &'(').unwrap_or(0))
380                .collect::<String>();
381            if st.contains(',') || st.len() == 1
382            {
383                return Err("bad var name");
384            }
385            for i in l.split(|c| c == &',')
386            {
387                func_vars.push((-1, i.iter().collect()));
388            }
389        }
390        else if l.contains(&',') || l.is_empty()
391        {
392            return Err("bad var name");
393        }
394        let mut fvs = Vec::new();
395        let mut parsed = if r.contains("pw") || r.contains("piecewise")
396        {
397            let mut k = 0;
398            for (j, v) in vars.iter().enumerate()
399            {
400                if v.name.len() <= l.len()
401                {
402                    k = j;
403                    break;
404                }
405            }
406            let mut tempvars = vars.clone();
407            tempvars.insert(
408                k,
409                Variable {
410                    name: l.clone(),
411                    parsed: Vec::new(),
412                    unparsed: String::new(),
413                    funcvars: Vec::new(),
414                },
415            );
416            if r.contains(':')
417            {
418                let mut split = r.split(':').collect::<Vec<&str>>();
419                r = split.pop().unwrap();
420                for i in split
421                {
422                    if i.contains('=')
423                    {
424                        let mut split = i.splitn(2, '=');
425                        let s = split.next().unwrap().to_string();
426                        let parsed = input_var(
427                            split.next().unwrap(),
428                            &tempvars,
429                            &mut func_vars,
430                            &mut 0,
431                            options,
432                            false,
433                            0,
434                            s.chars().collect::<Vec<char>>(),
435                            false,
436                            &mut Vec::new(),
437                            None,
438                        )?;
439                        func_vars.push((-1, s.clone()));
440                        fvs.push((s, parsed.0));
441                        fvs.extend(parsed.1)
442                    }
443                }
444            }
445            input_var(
446                r,
447                &tempvars,
448                &mut func_vars,
449                &mut 0,
450                options,
451                false,
452                0,
453                l.clone(),
454                false,
455                &mut Vec::new(),
456                None,
457            )?
458        }
459        else
460        {
461            if r.contains(':')
462            {
463                let mut split = r.split(':').collect::<Vec<&str>>();
464                r = split.pop().unwrap();
465                for i in split
466                {
467                    if i.contains('=')
468                    {
469                        let mut split = i.splitn(2, '=');
470                        let s = split.next().unwrap().to_string();
471                        let parsed = input_var(
472                            split.next().unwrap(),
473                            vars,
474                            &mut func_vars,
475                            &mut 0,
476                            options,
477                            false,
478                            0,
479                            s.chars().collect::<Vec<char>>(),
480                            false,
481                            &mut Vec::new(),
482                            None,
483                        )?;
484                        func_vars.push((-1, s.clone()));
485                        fvs.push((s, parsed.0));
486                        fvs.extend(parsed.1)
487                    }
488                }
489            }
490            input_var(
491                r,
492                vars,
493                &mut func_vars,
494                &mut 0,
495                options,
496                false,
497                0,
498                l.clone(),
499                false,
500                &mut Vec::new(),
501                None,
502            )?
503        };
504        parsed.1.extend(fvs);
505        if l.contains(&'(')
506            && r.contains(l.split(|c| c == &'(').next().unwrap())
507            && (r.contains("piecewise") || r.contains("pw"))
508        {
509            parsed
510                .1
511                .push((l.iter().collect::<String>(), parsed.0.clone()))
512        }
513        if parsed.0.is_empty()
514        {
515            return Err("bad input");
516        }
517        else if replace
518        {
519            vars[i] = Variable {
520                name: l.clone(),
521                parsed: if l.contains(&'(')
522                {
523                    parsed.0
524                }
525                else
526                {
527                    vec![do_math(parsed.0, options, parsed.1.clone())?]
528                },
529                unparsed: orig.to_string(),
530                funcvars: parsed.1,
531            };
532        }
533        else
534        {
535            vars.insert(
536                i,
537                Variable {
538                    name: l.clone(),
539                    parsed: if l.contains(&'(')
540                    {
541                        parsed.0
542                    }
543                    else
544                    {
545                        vec![do_math(parsed.0, options, parsed.1.clone())?]
546                    },
547                    unparsed: orig.to_string(),
548                    funcvars: parsed.1,
549                },
550            )
551        }
552    }
553    if redef
554    {
555        let mut redef = vec![(l.clone(), Vec::new())];
556        let mut k = 0;
557        while k < redef.len()
558        {
559            let mut j = 0;
560            while j < vars.len()
561            {
562                let v = &vars[j];
563                let check = &redef[k].0[0..=redef[k]
564                    .0
565                    .iter()
566                    .position(|a| a == &'(')
567                    .unwrap_or(redef[k].0.len().saturating_sub(1))]
568                    .iter()
569                    .collect::<String>();
570                if !redef.iter().any(|a| a.0 == v.name && a.1 == redef[k].0)
571                    && v.unparsed.contains(check)
572                {
573                    let mut func_vars: Vec<(isize, String)> = Vec::new();
574                    if v.name.contains(&'(')
575                    {
576                        let mut l = v.name.clone();
577                        l.drain(0..=l.iter().position(|c| c == &'(').unwrap());
578                        l.pop();
579                        for i in l.split(|c| c == &',')
580                        {
581                            func_vars.push((-1, i.iter().collect::<String>()));
582                        }
583                    }
584                    let mut fvs = Vec::new();
585                    let mut unparsed = v.unparsed.clone();
586                    if unparsed.contains(':')
587                    {
588                        let un = unparsed;
589                        let mut split = un.split(':').collect::<Vec<&str>>();
590                        unparsed = split.pop().unwrap().to_string();
591                        for i in split
592                        {
593                            if i.contains('=')
594                            {
595                                let mut split = i.splitn(2, '=');
596                                let s = split.next().unwrap().to_string();
597                                let parsed = input_var(
598                                    split.next().unwrap(),
599                                    vars,
600                                    &mut func_vars,
601                                    &mut 0,
602                                    options,
603                                    false,
604                                    0,
605                                    s.chars().collect::<Vec<char>>(),
606                                    false,
607                                    &mut Vec::new(),
608                                    None,
609                                )?;
610                                func_vars.push((-1, s.clone()));
611                                fvs.push((s, parsed.0));
612                                fvs.extend(parsed.1)
613                            }
614                        }
615                    }
616                    let mut parsed = input_var(
617                        &unparsed,
618                        vars,
619                        &mut func_vars,
620                        &mut 0,
621                        options,
622                        false,
623                        0,
624                        v.name.clone(),
625                        false,
626                        &mut Vec::new(),
627                        None,
628                    )?;
629                    parsed.1.extend(fvs);
630                    if v.name.contains(&'(')
631                        && v.unparsed
632                            .contains(v.name.split(|c| c == &'(').next().unwrap())
633                        && (v.unparsed.contains("piecewise") || v.unparsed.contains("pw"))
634                    {
635                        parsed
636                            .1
637                            .push((v.name.iter().collect::<String>(), parsed.0.clone()));
638                    }
639                    if v.name.contains(&'(')
640                    {
641                        if v.parsed != parsed.0 || v.funcvars != parsed.1
642                        {
643                            redef.push((v.name.clone(), redef[k].0.clone()));
644                            vars[j].parsed = parsed.0;
645                            vars[j].funcvars = parsed.1;
646                        }
647                    }
648                    else if let Ok(n) = do_math(parsed.0.clone(), options, parsed.1.clone())
649                    {
650                        if n != v.parsed[0]
651                        {
652                            redef.push((v.name.clone(), redef[k].0.clone()));
653                            vars[j].parsed = vec![n];
654                        }
655                    }
656                }
657                j += 1;
658            }
659            k += 1;
660        }
661    }
662    Ok(())
663}
664pub fn set_commands_or_vars(
665    colors: &mut Colors,
666    options: &mut Options,
667    vars: &mut Vec<Variable>,
668    input: &[char],
669) -> Result<(), &'static str>
670{
671    let n = input.iter().collect::<String>();
672    let mut split = n.splitn(2, '=');
673    let s = split.next().unwrap().replace(' ', "");
674    let l = s;
675    let r = split.next().unwrap();
676    if l.is_empty()
677        || l.chars()
678            .any(|c| !c.is_alphanumeric() && !matches!(c, '(' | ')' | ',' | '\'' | '`' | '_'))
679    {
680        return Ok(());
681    }
682    else if let Err(s) = set_commands(options, colors, vars, &l, r)
683    {
684        if s.is_empty()
685        {
686            return Ok(());
687        }
688        return Err(s);
689    }
690    let l = l.chars().collect::<Vec<char>>();
691    for (i, v) in vars.iter().enumerate()
692    {
693        if v.name.split(|c| c == &'(').next() == l.split(|c| c == &'(').next()
694            && v.name.contains(&'(') == l.contains(&'(')
695            && v.name.iter().filter(|c| c == &&',').count()
696                == l.iter().filter(|c| c == &&',').count()
697        {
698            if r == "null"
699            {
700                add_var(l, r, i, vars, *options, true, true, true)?
701            }
702            else
703            {
704                add_var(l, r, i, vars, *options, true, true, false)?
705            }
706            return Ok(());
707        }
708    }
709    for (i, j) in vars.iter().enumerate()
710    {
711        if j.name.len() <= l.len()
712        {
713            add_var(l, r, i, vars, *options, true, false, false)?;
714            return Ok(());
715        }
716    }
717    add_var(l, r, vars.len(), vars, *options, true, false, false)?;
718    Ok(())
719}