~vpzom/four

9125f520f06985f43041da99b69d3fcaa66100b7 — Colin Reeder 4 years ago 52cb562
Change addition and multiplication to take any number of arguments
2 files changed, 58 insertions(+), 58 deletions(-)

M README.md
M src/eval.rs
M README.md => README.md +2 -2
@@ 23,8 23,8 @@ Four supports the following data types:
 ID  |       Operation       | Description
---- | --------------------- | -----------
   0 |  function declaration | Takes one expression as a parameter, and returns a callable function form of it.  Functions can be used as operations.
   1 |              multiply | Takes two values and multiplies them.  If either is nil, returns the other.  Strings can be multiplied by integers for repetition.
   4 |                   add | Adds two numbers, or concatenates two strings.  If either value is nil, returns the other.
   1 |              multiply | Takes any number of values and multiplies them, ignoring nils. If passed zero values, returns nil. Strings can be multiplied by integers for repetition.
   4 |                   add | Takes any number of values and adds or concatenates them, ignoring nils. If passed zero values, returns nil.
   8 |                divide | Divides two numbers.  If either value is nil, returns nil.
   9 | character from string | Takes a string and an integer, returns the character at the given index in the given string as a string.
  12 |           conditional | Takes three values. If the first value is 4, the second is returned, otherwise the third is returned.

M src/eval.rs => src/eval.rs +56 -56
@@ 49,69 49,69 @@ fn exec_op(pos: Location, id: i32, args: &[ParsedExpr], ctx: &Context) -> Result
        }
        1 => {
            // multiply
            if args.len() != 2 {
                return Err(EvalError::InvalidParameters(
                    pos,
                    format!(
                        "multiply operation requires exactly 2 parameters, got {}",
                        args.len()
                    ),
                ));
            }

            let a = eval(&args[0], ctx)?;
            let b = eval(&args[1], ctx)?;

            Ok(match (a, b) {
                (Value::Nil, b) => b,
                (a, Value::Nil) => a,
                (Value::I32(a), Value::I32(b)) => Value::I32(a * b),
                (Value::String(a), Value::I32(b)) | (Value::I32(b), Value::String(a)) => {
                    Value::String(a.repeat(b.max(0) as usize))
                }
                (Value::String(_), Value::String(_)) => {
                    return Err(EvalError::InvalidParameters(
                        pos,
                        format!("multiply operation cannot be applied to two strings"),
                    ))
                }
                (Value::Function(_), _) | (_, Value::Function(_)) => {
                    return Err(EvalError::InvalidParameters(
                        pos,
                        format!("multiply operation cannot be applied to functions"),
                    ))
            if args.is_empty() {
                Ok(Value::Nil)
            } else if args.len() == 1 {
                eval(&args[0], ctx)
            } else {
                let mut acc = eval(&args[0], ctx)?;
                for b in args.iter().skip(1) {
                    let b = eval(b, ctx)?;
                    acc = match (acc, b) {
                        (Value::Nil, b) => b,
                        (a, Value::Nil) => a,
                        (Value::I32(a), Value::I32(b)) => Value::I32(a * b),
                        (Value::String(a), Value::I32(b)) | (Value::I32(b), Value::String(a)) => {
                            Value::String(a.repeat(b.max(0) as usize))
                        }
                        (Value::String(_), Value::String(_)) => {
                            return Err(EvalError::InvalidParameters(
                                pos,
                                format!("multiply operation cannot be applied to two strings"),
                            ))
                        }
                        (Value::Function(_), _) | (_, Value::Function(_)) => {
                            return Err(EvalError::InvalidParameters(
                                pos,
                                format!("multiply operation cannot be applied to functions"),
                            ))
                        }
                    };
                }
            })

                Ok(acc)
            }
        }
        4 => {
            // add
            if args.len() != 2 {
                return Err(EvalError::InvalidParameters(
                    pos,
                    format!(
                        "add operation requires exactly 2 parameters, got {}",
                        args.len()
                    ),
                ));
            }

            let a = eval(&args[0], ctx)?;
            let b = eval(&args[1], ctx)?;

            Ok(match (a, b) {
                (Value::Nil, b) => b,
                (a, Value::Nil) => a,
                (Value::I32(a), Value::I32(b)) => Value::I32(a + b),
                (Value::String(a), Value::I32(b)) => Value::String(format!("{}{}", a, b)),
                (Value::I32(a), Value::String(b)) => Value::String(format!("{}{}", a, b)),
                (Value::String(a), Value::String(b)) => Value::String(format!("{}{}", a, b)),
                (Value::Function(_), _) | (_, Value::Function(_)) => {
                    return Err(EvalError::InvalidParameters(
                        pos,
                        format!("add operation cannot be applied to functions"),
                    ))
            if args.is_empty() {
                Ok(Value::Nil)
            } else if args.len() == 1 {
                eval(&args[0], ctx)
            } else {
                let mut acc = eval(&args[0], ctx)?;
                for b in args.iter().skip(1) {
                    let b = eval(b, ctx)?;
                    acc = match (acc, b) {
                        (Value::Nil, b) => b,
                        (a, Value::Nil) => a,
                        (Value::I32(a), Value::I32(b)) => Value::I32(a + b),
                        (Value::String(a), Value::I32(b)) => Value::String(format!("{}{}", a, b)),
                        (Value::I32(a), Value::String(b)) => Value::String(format!("{}{}", a, b)),
                        (Value::String(a), Value::String(b)) => Value::String(format!("{}{}", a, b)),
                        (Value::Function(_), _) | (_, Value::Function(_)) => {
                            return Err(EvalError::InvalidParameters(
                                pos,
                                format!("add operation cannot be applied to functions"),
                            ))
                        }
                    }
                }
            })

                Ok(acc)
            }
        }
        8 => {
            // divide