github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/expressions/parse_vars.go (about) 1 package expressions 2 3 import ( 4 "errors" 5 6 "github.com/lmorg/murex/lang/expressions/primitives" 7 "github.com/lmorg/murex/lang/types" 8 "github.com/lmorg/murex/utils/home" 9 ) 10 11 func (tree *ParserT) parseVarScalarExpr(exec, execScalars bool, strOrVal varFormatting) ([]rune, interface{}, string, primitives.FunctionT, error) { 12 runes, v, mxDt, err := tree.parseVarScalar(exec, execScalars, varAsValue) 13 14 if exec { 15 fn := func() (*primitives.Value, error) { 16 switch t := v.(type) { 17 case *getVarIndexOrElementT: 18 val, mxDt, err := tree.getVarIndexOrElement(t) 19 return &primitives.Value{Value: val, DataType: mxDt}, err 20 21 case parseLambdaExecTrueT: 22 _, val, mxDt, err := t() 23 return &primitives.Value{Value: val, DataType: mxDt}, err 24 25 default: 26 val, mxDt, err := tree.getVar(scalarNameDetokenised(runes), varAsValue) 27 return &primitives.Value{Value: val, DataType: mxDt}, err 28 } 29 } 30 return runes, v, mxDt, fn, err 31 } 32 33 return runes, v, mxDt, nil, err 34 } 35 36 func (tree *ParserT) parseVarScalar(exec, execScalars bool, strOrVal varFormatting) ([]rune, interface{}, string, error) { 37 if tree.nextChar() == '(' { 38 tree.charPos++ 39 return tree.parseVarParenthesis(execScalars, strOrVal) 40 } 41 42 if !isBareChar(tree.nextChar()) { 43 // always print $ 44 return []rune{'$'}, "$", types.String, nil 45 } 46 47 tree.charPos++ 48 value := tree.parseBareword() 49 50 if tree.charPos < len(tree.expression) && tree.expression[tree.charPos] == '[' { 51 return tree.parseVarIndexElement(execScalars, '$', value, strOrVal) 52 } 53 54 tree.charPos-- 55 56 r := append([]rune{'$'}, value...) 57 58 // don't getVar() until we come to execute the expression, skip when only 59 // parsing syntax 60 if execScalars { 61 v, dataType, err := tree.getVar(value, strOrVal) 62 return r, v, dataType, err 63 } 64 65 return r, nil, "", nil 66 } 67 68 func (tree *ParserT) parseVarParenthesis(exec bool, strOrVal varFormatting) ([]rune, interface{}, string, error) { 69 start := tree.charPos 70 71 for tree.charPos++; tree.charPos < len(tree.expression); tree.charPos++ { 72 r := tree.expression[tree.charPos] 73 74 switch { 75 case r == ')': 76 goto endParenthesis 77 } 78 } 79 80 return nil, nil, "", raiseError( 81 tree.expression, nil, tree.charPos, "expecting closing parenthesis, ')', after variable reference") 82 83 endParenthesis: 84 path := tree.expression[start+1 : tree.charPos] 85 value := tree.expression[start-1 : tree.charPos+1] 86 87 if !exec { 88 return value, nil, "", nil 89 } 90 91 v, dt, err := tree.getVar(path, strOrVal) 92 if err != nil { 93 return value, nil, "", err 94 } 95 return value, v, dt, nil 96 } 97 98 func (tree *ParserT) parseVarIndexElement(exec bool, sigil rune, varName []rune, strOrVal varFormatting) ([]rune, interface{}, string, error) { 99 if tree.nextChar() == '{' { 100 //return tree.parseLambdaScala(exec, '$', varName, strOrVal) 101 //return tree.parseLambdaStatement(exec, '$') 102 if exec { 103 return tree.parseLambdaExecTrue(varName, sigil, "") 104 } 105 r, err := tree.parseLambdaExecFalse(sigil, varName) 106 value := append([]rune{sigil}, varName...) 107 value = append(value, r...) 108 value = append(value, ']') 109 var fn parseLambdaExecTrueT = func() ([]rune, any, string, error) { 110 return _parseLambdaExecTrue(tree.p, varName, sigil, "", value, r[1:], tree.StrictArrays()) 111 } 112 return value, fn, "", err 113 } 114 115 var ( 116 brackets = 1 117 escape bool 118 getIorE = new(getVarIndexOrElementT) 119 ) 120 121 start := tree.charPos 122 123 if tree.nextChar() == '[' { 124 brackets++ 125 tree.charPos++ 126 } 127 128 tree.charPos++ 129 130 getIorE.isIorE = brackets 131 132 for ; tree.charPos < len(tree.expression); tree.charPos++ { 133 r := tree.expression[tree.charPos] 134 135 switch { 136 case escape: 137 escape = false 138 139 case r == '\\': 140 escape = true 141 142 case r == '[': 143 return nil, "", "", raiseError( 144 tree.expression, nil, tree.charPos, "too many nested square '[' brackets") 145 146 case r == ']': 147 brackets-- 148 if brackets == 0 { 149 goto endIndexElement 150 } 151 } 152 } 153 154 return nil, nil, "", raiseError( 155 tree.expression, nil, tree.charPos, "missing closing bracket ']'") 156 157 endIndexElement: 158 value := tree.expression[start-len(varName)-1 : tree.charPos+1] 159 getIorE.varName = varName 160 getIorE.key = tree.expression[start+getIorE.isIorE : tree.charPos-getIorE.isIorE+1] 161 getIorE.strOrVal = strOrVal 162 163 if !exec { 164 return value, getIorE, "", nil 165 } 166 167 v, dt, err := tree.getVarIndexOrElement(getIorE) 168 if err != nil { 169 return nil, nil, "", err 170 } 171 return nil, v, dt, nil 172 } 173 174 func (tree *ParserT) parseVarArray(exec bool) ([]rune, interface{}, error) { 175 if !isBareChar(tree.nextChar()) { 176 return nil, nil, errors.New("'@' symbol found but no variable name followed") 177 } 178 179 tree.charPos++ 180 value := tree.parseBareword() 181 182 if tree.charPos < len(tree.expression) && tree.expression[tree.charPos] == '[' { 183 return tree.parseVarRange(exec, value) 184 } 185 186 tree.charPos-- 187 188 if !exec { 189 // don't getArray() until we come to execute the expression, skip when only 190 // parsing syntax 191 return append([]rune{'@'}, value...), nil, nil 192 } 193 194 v, err := tree.getArray(value) 195 return value, v, err 196 } 197 198 func (tree *ParserT) parseVarRange(exec bool, varName []rune) ([]rune, interface{}, error) { 199 if tree.nextChar() == '{' { 200 if exec { 201 r, v, _, err := tree.parseLambdaExecTrue(varName, '@', "") // TODO: test me 202 return r, v, err 203 } else { 204 // just parsing source 205 //r, _, err := tree.parseSubShell(false, '@', varAsValue) 206 r, err := tree.parseLambdaExecFalse('@', nil) 207 return r, nil, err 208 209 //r, v, _, err := tree.parseLambdaScala(false, '@', varName, varAsValue) // just parsing source 210 //return r, v, err 211 } 212 } 213 214 var escape bool 215 216 start := tree.charPos 217 218 for tree.charPos++; tree.charPos < len(tree.expression); tree.charPos++ { 219 r := tree.expression[tree.charPos] 220 221 switch { 222 case escape: 223 escape = false 224 225 case r == '\\': 226 escape = true 227 228 case r == '[': 229 return nil, "", raiseError( 230 tree.expression, nil, tree.charPos, "too many nested square '[' brackets") 231 232 case r == ']': 233 goto endRange 234 } 235 } 236 237 return nil, "", raiseError( 238 tree.expression, nil, tree.charPos, "missing closing bracket ']'") 239 240 endRange: 241 key := tree.expression[start+1 : tree.charPos] 242 flags := []rune{} 243 if isBareChar(tree.nextChar()) { 244 tree.charPos++ 245 flags = tree.parseBareword() 246 tree.charPos-- 247 } 248 value := tree.expression[start-len(varName)-1 : tree.charPos] 249 250 if !exec { 251 return value, "", nil 252 } 253 254 v, err := tree.getVarRange(varName, key, flags) 255 if err != nil { 256 return nil, "", err 257 } 258 return nil, v, nil 259 } 260 261 func isUserNameChar(r rune) bool { 262 return isBareChar(r) || r == '.' || r == '-' 263 } 264 265 func (tree *ParserT) parseVarTilde(exec bool) string { 266 tree.charPos++ 267 start := tree.charPos 268 269 for ; tree.charPos < len(tree.expression); tree.charPos++ { 270 switch { 271 case isUserNameChar(tree.expression[tree.charPos]): 272 // valid user name 273 274 default: 275 // not a valid username character 276 goto endTilde 277 } 278 } 279 280 endTilde: 281 user := string(tree.expression[start:tree.charPos]) 282 tree.charPos-- 283 284 if !exec { 285 return "~" + user 286 } 287 288 if len(user) == 0 { 289 return home.MyDir 290 } 291 292 return home.UserDir(user) 293 }