github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/expressions/variables.go (about)

     1  package expressions
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/lmorg/murex/builtins/pipes/streams"
     7  	"github.com/lmorg/murex/lang"
     8  	"github.com/lmorg/murex/lang/types"
     9  	"github.com/lmorg/murex/utils"
    10  )
    11  
    12  type varFormatting int
    13  
    14  const (
    15  	varAsString varFormatting = 0
    16  	varAsValue  varFormatting = 1
    17  )
    18  
    19  var errEmptyRange = "range '@%s[%s]%s' is empty"
    20  
    21  func (tree *ParserT) getVar(name []rune, strOrVal varFormatting) (interface{}, string, error) {
    22  	var (
    23  		value    interface{}
    24  		dataType string
    25  		err      error
    26  		nameS    = string(name)
    27  	)
    28  
    29  	if strOrVal == varAsString {
    30  		value, err = tree.p.Variables.GetString(nameS)
    31  		if err != nil {
    32  			return nil, "", err
    33  		}
    34  		value = utils.CrLfTrimString(value.(string))
    35  
    36  	} else {
    37  		dataType = tree.p.Variables.GetDataType(nameS)
    38  
    39  		switch dataType {
    40  		case types.String, types.Generic:
    41  			value, err = tree.p.Variables.GetString(nameS)
    42  			value = utils.CrLfTrimString(value.(string))
    43  
    44  		case types.Number, types.Integer, types.Float, types.Boolean, types.Null:
    45  			value, err = tree.p.Variables.GetValue(nameS)
    46  
    47  		default:
    48  			value, err = tree.p.Variables.GetString(nameS)
    49  			if err != nil {
    50  				return nil, "", err
    51  			}
    52  			fork := tree.p.Fork(lang.F_CREATE_STDIN | lang.F_NO_STDOUT | lang.F_NO_STDERR)
    53  			_, err := fork.Stdin.Write([]byte(value.(string)))
    54  			if err != nil {
    55  				return nil, "", err
    56  			}
    57  			v, err := lang.UnmarshalData(fork.Process, dataType)
    58  			if err != nil {
    59  				return value, dataType, nil
    60  			}
    61  			return v, dataType, nil
    62  		}
    63  	}
    64  
    65  	return value, dataType, err
    66  }
    67  
    68  const errEmptyArray = "array '@%s' is empty"
    69  
    70  func (tree *ParserT) getArray(name []rune) (interface{}, error) {
    71  	var nameS = string(name)
    72  
    73  	data, err := tree.p.Variables.GetString(nameS)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	if data == "" && tree.StrictArrays() {
    79  		return nil, fmt.Errorf(errEmptyArray, nameS)
    80  	}
    81  
    82  	var array []interface{}
    83  
    84  	variable := streams.NewStdin()
    85  	variable.SetDataType(tree.p.Variables.GetDataType(nameS))
    86  	variable.Write([]byte(data))
    87  
    88  	err = variable.ReadArrayWithType(tree.p.Context, func(v interface{}, _ string) {
    89  		array = append(array, v)
    90  	})
    91  
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	if len(array) == 0 && tree.StrictArrays() {
    97  		return nil, fmt.Errorf(errEmptyArray, nameS)
    98  	}
    99  
   100  	return array, nil
   101  }
   102  
   103  func (tree *ParserT) setVar(name []rune, value interface{}, dataType string) error {
   104  	nameS := string(name)
   105  	return tree.p.Variables.Set(tree.p, nameS, value, dataType)
   106  }
   107  
   108  const (
   109  	getVarIsIndex   = 1
   110  	getVarIsElement = 2
   111  )
   112  
   113  type getVarIndexOrElementT struct {
   114  	varName  []rune
   115  	key      []rune
   116  	isIorE   int
   117  	strOrVal varFormatting
   118  }
   119  
   120  func (tree *ParserT) getVarIndexOrElement(getIorE *getVarIndexOrElementT) (interface{}, string, error) {
   121  	var block []rune
   122  	if getIorE.isIorE == getVarIsIndex {
   123  		block = createIndexBlock(getIorE)
   124  	} else {
   125  		block = createElementBlock(getIorE)
   126  	}
   127  
   128  	fork := tree.p.Fork(lang.F_NO_STDIN | lang.F_CREATE_STDOUT)
   129  	fork.Execute(block)
   130  	b, err := fork.Stdout.ReadAll()
   131  	if err != nil {
   132  		return "", "", err
   133  	}
   134  
   135  	b = utils.CrLfTrim(b)
   136  	dataType := fork.Stdout.GetDataType()
   137  
   138  	v, err := formatBytes(b, dataType, getIorE.strOrVal)
   139  	return v, dataType, err
   140  }
   141  
   142  func createIndexBlock(getIorE *getVarIndexOrElementT) []rune {
   143  	l := len(getIorE.varName) + 1
   144  
   145  	block := make([]rune, 6+len(getIorE.varName)+len(getIorE.key))
   146  	block[0] = '$'
   147  	copy(block[1:], getIorE.varName)
   148  	copy(block[l:], []rune{'-', '>', ' ', '['})
   149  	copy(block[l+4:], getIorE.key)
   150  	block[len(block)-1] = ']'
   151  	return block
   152  }
   153  
   154  func createElementBlock(getIorE *getVarIndexOrElementT) []rune {
   155  	l := len(getIorE.varName) + 1
   156  
   157  	block := make([]rune, 8+len(getIorE.varName)+len(getIorE.key))
   158  	block[0] = '$'
   159  	copy(block[1:], getIorE.varName)
   160  	copy(block[l:], []rune{'-', '>', ' ', '[', '['})
   161  	copy(block[l+5:], getIorE.key)
   162  	copy(block[len(block)-2:], []rune{']', ']'})
   163  	return block
   164  }
   165  
   166  func createRangeBlock(name, key, flags []rune) []rune {
   167  	l := len(name) + 1
   168  
   169  	block := make([]rune, 7+len(name)+len(key)+len(flags))
   170  	block[0] = '$'
   171  	copy(block[1:], name)
   172  	copy(block[l:], []rune{'-', '>', ' ', '@', '['})
   173  	copy(block[l+5:], key)
   174  	block[l+len(key)+5] = ']'
   175  	copy(block[len(block)-len(flags):], flags)
   176  	return block
   177  }
   178  
   179  func (tree *ParserT) getVarRange(name, key, flags []rune) (interface{}, error) {
   180  	var array []interface{}
   181  
   182  	block := createRangeBlock(name, key, flags)
   183  	fork := tree.p.Fork(lang.F_NO_STDIN | lang.F_CREATE_STDOUT)
   184  	fork.Execute(block)
   185  	err := fork.Stdout.ReadArrayWithType(tree.p.Context, func(v interface{}, _ string) {
   186  		array = append(array, v)
   187  	})
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  
   192  	if len(array) == 0 && tree.StrictArrays() {
   193  		return nil, fmt.Errorf(errEmptyRange, string(name), string(key), string(flags))
   194  	}
   195  
   196  	return array, nil
   197  
   198  }
   199  
   200  func formatBytes(b []byte, dataType string, strOrVal varFormatting) (interface{}, error) {
   201  	if strOrVal == varAsString {
   202  		return string(b), nil
   203  	}
   204  
   205  	switch dataType {
   206  	case types.Number, types.String, types.Integer, types.Boolean, types.Null, types.Float:
   207  		v, err := types.ConvertGoType(b, dataType)
   208  		if err != nil {
   209  			return nil, err
   210  		}
   211  		return v, nil
   212  
   213  	default:
   214  		return string(b), nil
   215  	}
   216  }