1// Copyright (c) 2021, Peter Ohler, All rights reserved. 2 3package asm 4 5import ( 6 "fmt" 7) 8 9func init() { 10 Define(&Fn{ 11 Name: "sum", 12 Eval: sum, 13 Desc: `Returns the sum of all arguments. All arguments must be numbers 14or strings. If any argument is a string then the result will be 15a string otherwise the result will be a number. If any of the 16arguments are not a number or a string an error is raised.`, 17 }) 18 Define(&Fn{ 19 Name: "+", 20 Eval: sum, 21 Desc: `Returns the sum of all arguments. All arguments must be numbers 22or strings. If any argument is a string then the result will be 23a string otherwise the result will be a number. If any of the 24arguments are not a number or a string an error is raised.`, 25 }) 26} 27 28const ( 29 intSum = iota 30 floatSum 31 strSum 32) 33 34func sum(root map[string]interface{}, at interface{}, args ...interface{}) interface{} { 35 kind := intSum 36 var ssum string 37 var isum int64 38 var fsum float64 39 for i, arg := range args { 40 switch v := evalArg(root, at, arg).(type) { 41 case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: 42 ii, _ := asInt(v) 43 if i == 0 { 44 kind = intSum 45 } 46 switch kind { 47 case intSum: 48 isum += ii 49 case floatSum: 50 fsum += float64(ii) 51 case strSum: 52 ssum = fmt.Sprintf("%s%d", ssum, ii) 53 } 54 case float32, float64: 55 if i == 0 { 56 kind = floatSum 57 } 58 f, _ := asFloat(v) 59 switch kind { 60 case intSum: 61 kind = floatSum 62 fsum = float64(isum) + f 63 case floatSum: 64 fsum += f 65 case strSum: 66 ssum = fmt.Sprintf("%s%g", ssum, f) 67 } 68 case string: 69 if i == 0 { 70 kind = strSum 71 } 72 switch kind { 73 case intSum: 74 kind = strSum 75 ssum = fmt.Sprintf("%d%s", isum, v) 76 case floatSum: 77 kind = strSum 78 ssum = fmt.Sprintf("%g%s", fsum, v) 79 case strSum: 80 ssum += v 81 } 82 default: 83 panic(fmt.Errorf("a %T argument can not be summed", v)) 84 } 85 } 86 switch kind { 87 case intSum: 88 return isum 89 case floatSum: 90 return fsum 91 } 92 return ssum 93} 94