1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use logisheets_parser::ast;

use super::calc_vertex::{CalcValue, CalcVertex, Value};

use super::super::connector::Connector;
use super::funcs;
use super::infix;

pub fn calc<C>(ast: &ast::Node, fetcher: &mut C) -> CalcValue
where
    C: Connector,
{
    let v = calc_node(ast, fetcher);
    fetcher.get_calc_value(v)
}

fn calc_node<C>(node: &ast::Node, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    match &node.pure {
        ast::PureNode::Value(v) => CalcVertex::Value(CalcValue::Scalar(Value::from_ast_value(v))),
        ast::PureNode::Func(f) => calc_func(f, fetcher),
        ast::PureNode::Reference(r) => fetcher.convert(r),
    }
}

fn calc_func<C>(func: &ast::Func, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    let args = func
        .args
        .iter()
        .map(|arg| calc_node(arg, fetcher))
        .collect::<Vec<_>>();
    let op = &func.op;
    match op {
        ast::Operator::Infix(op) => {
            let mut iter = args.into_iter();
            let lhs = iter.next().unwrap();
            let rhs = iter.next().unwrap();
            infix::calc_infix(lhs, op, rhs, fetcher)
        }
        ast::Operator::Prefix(p) => {
            let lhs = CalcVertex::Value(CalcValue::Scalar(Value::Number(0_f64)));
            let mut iter = args.into_iter();
            let rhs = iter.next().unwrap();
            let op = match p {
                ast::PrefixOperator::Minus => ast::InfixOperator::Minus,
                ast::PrefixOperator::Plus => ast::InfixOperator::Plus,
            };
            infix::calc_infix(lhs, &op, rhs, fetcher)
        }
        ast::Operator::Postfix(_) => {
            let mut iter = args.into_iter();
            let lhs = iter.next().unwrap();
            let rhs = CalcVertex::Value(CalcValue::Scalar(Value::Number(100_f64)));
            let op = ast::InfixOperator::Divide;
            infix::calc_infix(lhs, &op, rhs, fetcher)
        }
        ast::Operator::Function(fid) => {
            let name = fetcher.get_func_name(fid);
            match name {
                Ok(func) => funcs::function_calculate(&func, args, fetcher),
                Err(_) => CalcVertex::from_error(ast::Error::Unspecified),
            }
        }
        ast::Operator::Comma => {
            let mut new_args = Vec::new();
            args.into_iter().for_each(|cv| match cv {
                CalcVertex::Union(cvs) => {
                    new_args.extend(cvs);
                }
                _ => new_args.push(Box::new(cv)),
            });
            CalcVertex::Union(new_args)
        }
    }
}