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 }