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  }