github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/expressions/parse_switch.go (about) 1 package expressions 2 3 import ( 4 "errors" 5 "strings" 6 7 "github.com/lmorg/murex/lang" 8 "github.com/lmorg/murex/lang/types" 9 ) 10 11 type SwitchT struct { 12 Condition string 13 Parameters [][]rune 14 } 15 16 func (s *SwitchT) ParametersLen() int { 17 return len(s.Parameters) 18 } 19 20 func (s *SwitchT) ParametersString(i int) string { 21 return string(s.Parameters[i]) 22 } 23 24 func (s *SwitchT) ParametersAll() []string { 25 params := make([]string, len(s.Parameters)) 26 27 for i := range s.Parameters { 28 params[i] = string(s.Parameters[i]) 29 } 30 31 return params 32 } 33 34 func (s *SwitchT) ParametersStringAll() string { 35 return strings.Join(s.ParametersAll(), " ") 36 } 37 38 func (s *SwitchT) Block(i int) ([]rune, error) { 39 if i > len(s.Parameters)-1 { 40 return nil, errors.New("too few parameters") 41 } 42 if types.IsBlockRune(s.Parameters[i]) { 43 return s.Parameters[i], nil 44 } 45 return nil, errors.New("not a code block") 46 } 47 48 func ParseSwitch(p *lang.Process, expression []rune) ([]*SwitchT, error) { 49 var swt []*SwitchT 50 51 for i := 0; i < len(expression); i++ { 52 53 switch expression[i] { 54 case ' ', '\t', '\r', '\n', ';': 55 continue 56 57 default: 58 tree := NewParser(p, expression[i:], 0) 59 tree.statement = new(StatementT) 60 newPos, err := tree.parseSwitch() 61 if err != nil { 62 return nil, err 63 } 64 if len(tree.statement.command) > 0 || len(tree.statement.parameters) > 0 { 65 swt = append(swt, &SwitchT{ 66 Condition: tree.statement.String(), 67 Parameters: tree.statement.parameters, 68 }) 69 i += newPos 70 } 71 } 72 73 } 74 75 return swt, nil 76 } 77 78 func (tree *ParserT) parseSwitch() (int, error) { 79 var escape bool 80 81 for ; tree.charPos < len(tree.expression); tree.charPos++ { 82 r := tree.expression[tree.charPos] 83 84 if escape { 85 escape = false 86 switch r { 87 case 's': 88 appendToParam(tree, ' ') 89 case 't': 90 appendToParam(tree, '\t') 91 case 'r': 92 appendToParam(tree, '\r') 93 case 'n': 94 appendToParam(tree, '\n') 95 default: 96 appendToParam(tree, r) 97 } 98 continue 99 } 100 101 switch r { 102 case '#': 103 tree.parseComment() 104 105 case '/': 106 if tree.nextChar() == '#' { 107 if err := tree.parseCommentMultiLine(); err != nil { 108 return 0, err 109 } 110 } else { 111 appendToParam(tree, r) 112 } 113 114 case '\\': 115 escape = true 116 117 case ' ', '\t', '\r': 118 // whitespace. do nothing 119 if err := tree.nextParameter(); err != nil { 120 return 0, err 121 } 122 123 case '\n', ';': 124 // ignore empty lines while in the statement parser 125 if len(tree.statement.command) > 0 { 126 if err := tree.nextParameter(); err != nil { 127 return 0, err 128 } 129 tree.charPos-- 130 return tree.charPos, nil 131 } 132 133 case ':': 134 if err := processStatementColon(tree, true); err != nil { 135 return 0, err 136 } 137 138 case '~': 139 // tilde 140 appendToParam(tree, []rune(tree.parseVarTilde(true))...) 141 if err := tree.nextParameter(); err != nil { 142 return 0, err 143 } 144 145 case '(': 146 if len(tree.statement.command) == 0 && len(tree.statement.paramTemp) == 0 { 147 appendToParam(tree, r) 148 if err := tree.nextParameter(); err != nil { 149 return 0, err 150 } 151 continue 152 } 153 prev := tree.prevChar() 154 if prev == ' ' || prev == '\t' { 155 // quotes 156 value, err := tree.parseParenthesis(true) 157 if err != nil { 158 return 0, err 159 } 160 appendToParam(tree, value...) 161 continue 162 } 163 appendToParam(tree, r) 164 165 case '%': 166 switch tree.nextChar() { 167 case '[': 168 // JSON array 169 err := processStatementFromExpr(tree, tree.parseArray, true) 170 if err != nil { 171 return 0, err 172 } 173 case '{': 174 // JSON object 175 err := processStatementFromExpr(tree, tree.parseObject, true) 176 if err != nil { 177 return 0, err 178 } 179 case '(': 180 tree.charPos++ 181 value, err := tree.parseParenthesis(true) 182 if err != nil { 183 return 0, err 184 } 185 appendToParam(tree, value...) 186 default: 187 appendToParam(tree, r) 188 } 189 190 case '{': 191 // block literal 192 value, err := tree.parseBlockQuote() 193 if err != nil { 194 return 0, err 195 } 196 appendToParam(tree, value...) 197 198 case '}': 199 return 0, raiseError(tree.expression, nil, tree.charPos, 200 "unexpected closing bracket '}'") 201 202 case '\'', '"': 203 value, err := tree.parseString(r, r, true) 204 if err != nil { 205 return 0, err 206 } 207 appendToParam(tree, value...) 208 tree.statement.canHaveZeroLenStr = true 209 tree.charPos++ 210 211 case '$': 212 switch { 213 case tree.nextChar() == '{': 214 // subshell 215 _, fn, err := tree.parseSubShell(true, r, varAsString) 216 if err != nil { 217 return 0, err 218 } 219 val, err := fn() 220 if err != nil { 221 return 0, err 222 } 223 appendToParam(tree, []rune(val.Value.(string))...) 224 tree.statement.canHaveZeroLenStr = true 225 case isBareChar(tree.nextChar()): 226 // start scalar 227 _, v, _, err := tree.parseVarScalar(true, true, varAsString) 228 if err != nil { 229 return 0, err 230 } 231 appendToParam(tree, []rune(v.(string))...) 232 tree.statement.canHaveZeroLenStr = true 233 default: 234 appendToParam(tree, r) 235 } 236 237 case '@': 238 prev := tree.prevChar() 239 switch { 240 case prev != ' ' && prev != '\t': 241 appendToParam(tree, r) 242 case tree.nextChar() == '{': 243 // subshell 244 if err := tree.nextParameter(); err != nil { 245 return 0, err 246 } 247 value, fn, err := tree.parseSubShell(true, r, varAsString) 248 if err != nil { 249 return 0, err 250 } 251 val, err := fn() 252 if err != nil { 253 return 0, err 254 } 255 processStatementArrays(tree, value, val.Value, true) 256 case isBareChar(tree.nextChar()): 257 // start scalar 258 if err := tree.nextParameter(); err != nil { 259 return 0, err 260 } 261 value, v, err := tree.parseVarArray(true) 262 if err != nil { 263 return 0, err 264 } 265 processStatementArrays(tree, value, v, true) 266 default: 267 appendToParam(tree, r) 268 } 269 270 default: 271 // assign value 272 appendToParam(tree, r) 273 } 274 } 275 276 if err := tree.nextParameter(); err != nil { 277 return 0, err 278 } 279 tree.charPos-- 280 return tree.charPos, nil 281 }