github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/expressions/exp14.go (about) 1 package expressions 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 8 "github.com/lmorg/murex/lang" 9 "github.com/lmorg/murex/lang/expressions/primitives" 10 "github.com/lmorg/murex/lang/expressions/symbols" 11 "github.com/lmorg/murex/lang/types" 12 "github.com/lmorg/murex/utils/alter" 13 ) 14 15 func scalarNameDetokenised(r []rune) []rune { 16 if r[1] == '(' { 17 return r[2 : len(r)-1] 18 } else { 19 return r[1:] 20 } 21 } 22 23 func convertScalarToBareword(node *astNodeT) { 24 if node.key == symbols.Scalar && len(node.value) > 1 && 25 node.value[0] == '$' && node.value[1] != '{' { 26 27 node.key = symbols.Bareword 28 node.value = scalarNameDetokenised(node.value) 29 } 30 } 31 32 func expAssign(tree *ParserT, overwriteType bool) error { 33 leftNode, rightNode, err := tree.getLeftAndRightSymbols() 34 if err != nil { 35 return err 36 } 37 38 convertScalarToBareword(leftNode) 39 40 if leftNode.key != symbols.Bareword { 41 return raiseError(tree.expression, leftNode, 0, fmt.Sprintf( 42 "left side of %s should be a bareword, instead got %s", 43 tree.currentSymbol().key, leftNode.key)) 44 } 45 46 if rightNode.key <= symbols.Bareword { 47 return raiseError(tree.expression, rightNode, 0, fmt.Sprintf( 48 "right side of %s should not be a %s", 49 tree.currentSymbol().key, rightNode.key)) 50 } 51 52 var ( 53 v interface{} 54 dt string 55 ) 56 57 right, err := rightNode.dt.GetValue() 58 if err != nil { 59 return err 60 } 61 62 switch right.Primitive { 63 case primitives.Array, primitives.Object: 64 if overwriteType { 65 dt = types.Json 66 } else { 67 dt = tree.p.Variables.GetDataType(leftNode.Value()) 68 if dt == "" { 69 dt = types.Json 70 } 71 } 72 73 // this is ugly but Go's JSON marshaller is better behaved than Murexes on with empty values 74 if dt == types.Json { 75 b, err := right.Marshal() 76 if err != nil { 77 raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) 78 } 79 v = string(b) 80 } else { 81 b, err := lang.MarshalData(tree.p, dt, right.Value) 82 if err != nil { 83 raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) 84 } 85 v = string(b) 86 } 87 88 default: 89 if overwriteType { 90 dt = right.DataType 91 v = right.Value 92 93 } else { 94 dt = tree.p.Variables.GetDataType(leftNode.Value()) 95 if dt == "" || dt == types.Null { 96 dt = right.DataType 97 v = right.Value 98 99 } else { 100 101 v, err = types.ConvertGoType(right.Value, dt) 102 if err != nil { 103 raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) 104 } 105 } 106 } 107 } 108 109 err = tree.setVar(leftNode.value, v, dt) 110 if err != nil { 111 return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) 112 } 113 114 return tree.foldAst(&astNodeT{ 115 key: symbols.Calculated, 116 pos: tree.ast[tree.astPos].pos, 117 dt: primitives.NewPrimitive(primitives.Null, nil), 118 }) 119 } 120 121 func expAssignAdd(tree *ParserT) error { 122 leftNode, rightNode, err := tree.getLeftAndRightSymbols() 123 if err != nil { 124 return err 125 } 126 127 convertScalarToBareword(leftNode) 128 129 right, err := rightNode.dt.GetValue() 130 if err != nil { 131 return err 132 } 133 134 if leftNode.key != symbols.Bareword { 135 return raiseError(tree.expression, leftNode, 0, fmt.Sprintf( 136 "left side of %s should be a bareword, instead got %s", 137 tree.currentSymbol().key, leftNode.key)) 138 } 139 140 /*if right.key != symbols.Number { 141 return raiseError(tree.expression,tree.currentSymbol(), fmt.Sprintf( 142 "right side should not be a %s", right.key)) 143 }*/ 144 145 v, dt, err := tree.getVar(leftNode.value, varAsValue) 146 if err != nil { 147 if !tree.StrictTypes() && strings.Contains(err.Error(), lang.ErrDoesNotExist) { 148 // var doesn't exist and we have strict types disabled so lets create var 149 v, dt, err = float64(0), types.Number, nil 150 } else { 151 return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) 152 } 153 } 154 155 var result interface{} 156 157 switch dt { 158 case types.Number, types.Float: 159 if right.Primitive != primitives.Number { 160 return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf( 161 "cannot %s %s to %s", tree.currentSymbol().key, right.Primitive, dt)) 162 } 163 result = v.(float64) + right.Value.(float64) 164 165 case types.Integer: 166 if right.Primitive != primitives.Number { 167 return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf( 168 "cannot %s %s to %s", tree.currentSymbol().key, right.Primitive, dt)) 169 } 170 result = float64(v.(int)) + right.Value.(float64) 171 172 case types.Boolean: 173 return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf( 174 "cannot %s %s", tree.currentSymbol().key, dt)) 175 176 case types.Null: 177 switch right.Primitive { 178 case primitives.String: 179 result = right.Value.(string) 180 case primitives.Number: 181 result = right.Value.(float64) 182 default: 183 return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf( 184 "cannot %s %s to %s", tree.currentSymbol().key, right.Primitive, dt)) 185 } 186 187 default: 188 if right.Primitive != primitives.String { 189 return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf( 190 "cannot %s %s to %s", tree.currentSymbol().key, right.Primitive, dt)) 191 } 192 result = v.(string) + right.Value.(string) 193 } 194 195 err = tree.setVar(leftNode.value, result, right.DataType) 196 if err != nil { 197 return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) 198 } 199 200 return tree.foldAst(&astNodeT{ 201 key: symbols.Calculated, 202 pos: tree.ast[tree.astPos].pos, 203 dt: primitives.NewPrimitive(primitives.Null, nil), 204 }) 205 } 206 207 type assFnT func(float64, float64) float64 208 209 func _assSub(lv float64, rv float64) float64 { return lv - rv } 210 func _assMulti(lv float64, rv float64) float64 { return lv * rv } 211 func _assDiv(lv float64, rv float64) float64 { return lv / rv } 212 213 func expAssignAndOperate(tree *ParserT, operation assFnT) error { 214 leftNode, rightNode, err := tree.getLeftAndRightSymbols() 215 if err != nil { 216 return err 217 } 218 219 convertScalarToBareword(leftNode) 220 221 right, err := rightNode.dt.GetValue() 222 if err != nil { 223 return err 224 } 225 226 if leftNode.key != symbols.Bareword { 227 return raiseError(tree.expression, leftNode, 0, fmt.Sprintf( 228 "left side of %s should be a bareword, instead got %s", 229 tree.currentSymbol().key, leftNode.key)) 230 } 231 232 if rightNode.key != symbols.Number { 233 return raiseError(tree.expression, rightNode, 0, fmt.Sprintf( 234 "right side of %s should not be a %s", 235 tree.currentSymbol().key, rightNode.key)) 236 } 237 238 v, dt, err := tree.getVar(leftNode.value, varAsValue) 239 if err != nil { 240 if !tree.StrictTypes() && strings.Contains(err.Error(), lang.ErrDoesNotExist) { 241 // var doesn't exist and we have strict types disabled so lets create var 242 v, dt, err = float64(0), types.Number, nil 243 } else { 244 return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) 245 } 246 } 247 248 var f float64 249 250 switch dt { 251 case types.Number, types.Float: 252 f = operation(v.(float64), right.Value.(float64)) 253 case types.Integer: 254 f = operation(float64(v.(int)), right.Value.(float64)) 255 case types.Null: 256 f = operation(0, right.Value.(float64)) 257 default: 258 return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf( 259 "cannot %s %s", tree.currentSymbol().key, dt)) 260 } 261 262 err = tree.setVar(leftNode.value, f, right.DataType) 263 if err != nil { 264 return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) 265 } 266 267 return tree.foldAst(&astNodeT{ 268 key: symbols.Calculated, 269 pos: tree.ast[tree.astPos].pos, 270 dt: primitives.NewPrimitive(primitives.Null, nil), 271 }) 272 } 273 274 func expAssignMerge(tree *ParserT) error { 275 leftNode, rightNode, err := tree.getLeftAndRightSymbols() 276 if err != nil { 277 return err 278 } 279 280 right, err := rightNode.dt.GetValue() 281 if err != nil { 282 return err 283 } 284 285 convertScalarToBareword(leftNode) 286 287 if leftNode.key != symbols.Bareword { 288 return raiseError(tree.expression, leftNode, 0, fmt.Sprintf( 289 "left side of %s should be a bareword, instead got %s", 290 tree.currentSymbol().key, leftNode.key)) 291 } 292 293 rightVal := right.Value 294 if right.Primitive != primitives.String && reflect.TypeOf(rightVal).Kind() == reflect.String { 295 rightVal, err = lang.UnmarshalDataBuffered(tree.p, []byte(rightVal.(string)), right.DataType) 296 if err != nil { 297 return err 298 } 299 } 300 301 v, dt, err := tree.getVar(leftNode.value, varAsValue) 302 if err != nil { 303 if !tree.StrictTypes() && strings.Contains(err.Error(), lang.ErrDoesNotExist) { 304 // var doesn't exist and we have strict types disabled so lets create var 305 err = tree.setVar(leftNode.value, rightVal, right.DataType) 306 if err != nil { 307 return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) 308 } 309 return tree.foldAst(&astNodeT{ 310 key: symbols.Calculated, 311 pos: tree.ast[tree.astPos].pos, 312 dt: primitives.NewPrimitive(primitives.Null, nil), 313 }) 314 } else { 315 return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) 316 } 317 } 318 319 merged, err := alter.Merge(tree.p.Context, v, nil, rightVal) 320 if err != nil { 321 return raiseError(tree.expression, leftNode, 0, fmt.Sprintf( 322 "cannot perform merge '%s' into '%s': %s", 323 right.Value, leftNode.Value(), 324 err.Error())) 325 } 326 327 err = tree.setVar(leftNode.value, merged, dt) 328 if err != nil { 329 return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) 330 } 331 332 return tree.foldAst(&astNodeT{ 333 key: symbols.Calculated, 334 pos: tree.ast[tree.astPos].pos, 335 dt: primitives.NewPrimitive(primitives.Null, nil), 336 }) 337 }