arithmetic.go (4866B)
1 package subex 2 3 import ( 4 "main/walk" 5 "errors" 6 "strconv" 7 ) 8 9 func sumValues(values walk.ValueList) (walk.ValueList, error) { 10 allBools := true 11 var sum float64 = 0 12 var any bool = false 13 for _, value := range values { 14 switch v := value.(type) { 15 case walk.NullScalar: 16 allBools = false 17 case walk.BoolScalar: 18 if v { 19 sum += 1 20 any = true 21 } 22 case walk.NumberScalar: 23 allBools = false 24 sum += float64(v) 25 case walk.StringStructure: 26 allBools = false 27 num, err := strconv.ParseFloat(string(v), 64) 28 if err == nil { 29 sum += num 30 } else { 31 return nil, errors.New("Tried to sum non-castable string") 32 } 33 default: 34 return nil, errors.New("Tried to sum non-number") 35 } 36 } 37 if allBools { 38 return walk.ValueList{walk.BoolScalar(any)}, nil 39 } else { 40 return walk.ValueList{walk.NumberScalar(sum)}, nil 41 } 42 } 43 44 // Compounds atoms into values, if all values are booleans, does AND, if not, tries to cast to numbers and multiply 45 func multiplyValues(values walk.ValueList) (walk.ValueList, error) { 46 allBools := true 47 var product float64 = 1 48 var all bool = false 49 for _, value := range values { 50 switch v := value.(type) { 51 case walk.NullScalar: 52 allBools = false 53 product *= 0 54 case walk.BoolScalar: 55 if !v { 56 product *= 0 57 all = false 58 } 59 case walk.NumberScalar: 60 allBools = false 61 product *= float64(v) 62 case walk.StringStructure: 63 allBools = false 64 num, err := strconv.ParseFloat(string(v), 64) 65 if err == nil { 66 product *= num 67 } else { 68 return nil, errors.New("Tried to multiply non-castable string") 69 } 70 default: 71 return nil, errors.New("Tried to multiply non-number") 72 } 73 } 74 if allBools { 75 return walk.ValueList{walk.BoolScalar(all)}, nil 76 } else { 77 return walk.ValueList{walk.NumberScalar(product)}, nil 78 } 79 } 80 81 // Does tries to cast all to numbers and negates them 82 func negateValues(values walk.ValueList) (walk.ValueList, error) { 83 var negatedNumbers walk.ValueList 84 for _, value := range values { 85 switch v := value.(type) { 86 case walk.NullScalar: 87 negatedNumbers = append(negatedNumbers, walk.NumberScalar(0)) 88 case walk.BoolScalar: 89 if v { 90 negatedNumbers = append(negatedNumbers, walk.NumberScalar(-1)) 91 } else { 92 negatedNumbers = append(negatedNumbers, walk.NumberScalar(0)) 93 } 94 case walk.NumberScalar: 95 negatedNumbers = append(negatedNumbers, walk.NumberScalar(-float64(v))) 96 case walk.StringStructure: 97 num, err := strconv.ParseFloat(string(v), 64) 98 if err == nil { 99 negatedNumbers = append(negatedNumbers, walk.NumberScalar(-num)) 100 } else { 101 return nil, errors.New("Tried to negate non-castable string") 102 } 103 default: 104 return nil, errors.New("Tried to negate non-number") 105 } 106 } 107 return negatedNumbers, nil 108 } 109 110 // If all are castable to numbers, takes reciprocals of all and returns them 111 // Else errors 112 func reciprocalValues(values walk.ValueList) (walk.ValueList, error) { 113 var reciprocals walk.ValueList 114 for _, value := range values { 115 switch v := value.(type) { 116 case walk.NullScalar: 117 return nil, errors.New("Tried to take reciprocal of null") 118 case walk.BoolScalar: 119 if v { 120 reciprocals = append(reciprocals, walk.NumberScalar(1)) 121 } else { 122 return nil, errors.New("Tried to take reciprocal of false") 123 } 124 case walk.NumberScalar: 125 reciprocals = append(reciprocals, walk.NumberScalar(1 / float64(v))) 126 case walk.StringStructure: 127 num, err := strconv.ParseFloat(string(v), 64) 128 if err == nil { 129 reciprocals = append(reciprocals, walk.NumberScalar(1 / num)) 130 } else { 131 return nil, errors.New("Tried to take reciprocal of non-castable string") 132 } 133 default: 134 return nil, errors.New("Tried to take reciprocal of non-number") 135 } 136 } 137 return reciprocals, nil 138 } 139 140 // If all are castable to booleans, NOTs all and returns them 141 // Else errors 142 func notValues(values walk.ValueList) (notted walk.ValueList, err error) { 143 for _, value := range values { 144 switch v := value.(type) { 145 case walk.NullScalar: 146 notted = append(notted, walk.BoolScalar(true)) 147 case walk.BoolScalar: 148 notted = append(notted, walk.BoolScalar(!bool(v))) 149 case walk.NumberScalar: 150 notted = append(notted, walk.BoolScalar(v == 0)) 151 case walk.StringStructure: 152 notted = append(notted, walk.BoolScalar(len(v) == 0)) 153 default: 154 return nil, errors.New("Tried to NOT non-boolean") 155 } 156 } 157 return notted, nil 158 } 159 160 // Returns true if all values are equal, false if not 161 func equalValues(values walk.ValueList) (walk.ValueList, error) { 162 if len(values) == 0 { 163 return walk.ValueList{walk.BoolScalar(true)}, nil 164 } 165 first := values[0] 166 for _, value := range values[1:] { 167 // TODO: Refine the equality check 168 if value != first { 169 return walk.ValueList{walk.BoolScalar(false)}, nil 170 } 171 } 172 return walk.ValueList{walk.BoolScalar(true)}, nil 173 }