@@ 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.
@@ 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