ISibboI / evalexpr

A powerful expression evaluation crate 🦀.
GNU Affero General Public License v3.0
325 stars 54 forks source link

Added feature: dot operator support #152

Closed sweihub closed 1 year ago

sweihub commented 1 year ago

Hi @ISibboI

Would you review and merge this? Once the dot operator supported, we can do object like expressions, a quick glance:

  1. Demo 1: array
    assert_eq!(
    eval_with_context_mut(
        "v = array(1,2,3,4,5); 
         v = v.push(6); 
         v.length == v.get(5)",
        &mut context
    ),
    Ok(Value::Boolean(true))
    );
  2. Demo 2: tuple accessor, partly solved: https://github.com/ISibboI/evalexpr/issues/99
    assert_eq!(
    eval_with_context_mut("x = (1,2,3,4,5); x.get(4)", &mut context),
    Ok(Value::Int(5))
    );
  3. Demo 3: attributes of a future instrument
    eval_with_context_mut("
    f = future("IC2312");
    // return the prices
    (f.bid, f.ask, f.mid, f.last)
    ",
    &mut context);

The full test


#[test]
fn test_dot_attribute() {
    let mut context = HashMapContext::new();

    context
        .set_function(
            "array".to_string(),
            Function::new(|argument| Ok(Value::Tuple(argument.as_tuple()?))),
        )
        .unwrap();

    context
        .set_function(
            "dot".to_string(),
            Function::new(move |argument| {
                let x = argument.as_fixed_len_tuple(3)?;
                if let (Value::Tuple(id), Value::String(method)) = (&x[0], &x[1]) {
                    match method.as_str() {
                        "push" => {
                            // array.push(x)
                            let mut array = id.clone();
                            array.push(x[2].clone());
                            return Ok(Value::Tuple(array));
                        },
                        "get" => {
                            // array.get(i)
                            let index = x[2].as_int()?;
                            let value = &id[index as usize];
                            return Ok(value.clone());
                        },
                        "length" => {
                            // array.length
                            return Ok(Value::Int(id.len() as i64));
                        },
                        _ => {},
                    }
                }
                Err(EvalexprError::CustomMessage("unexpected dot call".into()))
            }),
        )
        .unwrap();

    assert_eq!(
        eval_with_context_mut(
            "v = array(1,2,3,4,5); 
             v = v.push(6); 
             v.length == v.get(5)",
            &mut context
        ),
        Ok(Value::Boolean(true))
    );

    assert_eq!(
        eval_with_context_mut("x = (1,2,3,4,5); x.get(4)", &mut context),
        Ok(Value::Int(5))
    );
}