github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/expressions/parse_object.go (about) 1 package expressions 2 3 import ( 4 "fmt" 5 6 "github.com/lmorg/murex/lang/expressions/primitives" 7 "github.com/lmorg/murex/lang/expressions/symbols" 8 "github.com/lmorg/murex/lang/types" 9 ) 10 11 func (tree *ParserT) createObjectAst(exec bool) error { 12 // create JSON dict 13 _, dt, err := tree.parseObject(exec) 14 if err != nil { 15 return err 16 } 17 tree.appendAstWithPrimitive(symbols.ObjectBegin, dt) 18 tree.charPos++ 19 20 return nil 21 } 22 23 func (tree *ParserT) parseObject(exec bool) ([]rune, *primitives.DataType, error) { 24 start := tree.charPos 25 o := newParseObjectT(tree) 26 27 for tree.charPos++; tree.charPos < len(tree.expression); tree.charPos++ { 28 r := tree.expression[tree.charPos] 29 30 switch r { 31 case '#': 32 tree.parseComment() 33 34 case '/': 35 if tree.nextChar() == '#' { 36 if err := tree.parseCommentMultiLine(); err != nil { 37 return nil, nil, err 38 } 39 } else { 40 err := o.AppendRune(r) 41 if err != nil { 42 return nil, nil, err 43 } 44 } 45 46 case '\'', '"': 47 // quoted string 48 value, err := tree.parseString(r, r, exec) 49 if err != nil { 50 return nil, nil, err 51 } 52 err = o.UpdateInterface(string(value)) 53 if err != nil { 54 return nil, nil, err 55 } 56 tree.charPos++ 57 58 case '%': 59 switch tree.nextChar() { 60 case '[', '{': 61 // do nothing because action covered in the next iteration 62 case '(': 63 // start nested string 64 tree.charPos++ 65 value, err := tree.parseParenthesis(exec) 66 if err != nil { 67 return nil, nil, err 68 } 69 err = o.UpdateInterface(string(value)) 70 if err != nil { 71 return nil, nil, err 72 } 73 default: 74 // string 75 err := o.AppendRune(r) 76 if err != nil { 77 return nil, nil, err 78 } 79 } 80 81 case '[': 82 // start nested array 83 if o.stage == 0 { 84 return nil, nil, fmt.Errorf("object keys cannot be an array") 85 } 86 _, dt, err := tree.parseArray(exec) 87 if err != nil { 88 return nil, nil, err 89 } 90 v, err := dt.GetValue() 91 if err != nil { 92 return nil, nil, err 93 } 94 err = o.UpdateInterface(v.Value) 95 if err != nil { 96 return nil, nil, err 97 } 98 tree.charPos++ 99 100 case '{': 101 // start nested object 102 if o.stage == 0 { 103 return nil, nil, raiseError( 104 tree.expression, nil, tree.charPos, "object keys cannot be another object") 105 } 106 _, dt, err := tree.parseObject(exec) 107 if err != nil { 108 return nil, nil, err 109 } 110 v, err := dt.GetValue() 111 if err != nil { 112 return nil, nil, err 113 } 114 err = o.UpdateInterface(v.Value) 115 if err != nil { 116 return nil, nil, err 117 } 118 tree.charPos++ 119 120 case '$': 121 switch { 122 case tree.nextChar() == '{': 123 // inline subshell 124 strOrVal := varFormatting(o.stage) 125 subshell, fn, err := tree.parseSubShell(exec, r, strOrVal) 126 if err != nil { 127 return nil, nil, err 128 } 129 if exec { 130 val, err := fn() 131 if err != nil { 132 return nil, nil, err 133 } 134 err = o.UpdateInterface(val.Value) 135 if err != nil { 136 return nil, nil, err 137 } 138 } else { 139 err = o.UpdateInterface(string(subshell)) 140 if err != nil { 141 return nil, nil, err 142 } 143 } 144 default: 145 // inline scalar 146 strOrVal := varFormatting(o.stage) 147 scalar, v, _, err := tree.parseVarScalar(exec, exec, strOrVal) 148 if err != nil { 149 return nil, nil, err 150 } 151 if exec { 152 err = o.UpdateInterface(v) 153 if err != nil { 154 return nil, nil, err 155 } 156 } else { 157 err = o.UpdateInterface(string(scalar)) 158 if err != nil { 159 return nil, nil, err 160 } 161 } 162 } 163 164 case '~': 165 // tilde 166 err := o.AppendRune([]rune(tree.parseVarTilde(exec))...) 167 if err != nil { 168 return nil, nil, err 169 } 170 171 case '@': 172 switch tree.nextChar() { 173 case '{': 174 subshell, fn, err := tree.parseSubShell(exec, r, varAsValue) 175 if err != nil { 176 return nil, nil, err 177 } 178 if exec { 179 val, err := fn() 180 if err != nil { 181 return nil, nil, err 182 } 183 err = o.UpdateInterface(val.Value) 184 if err != nil { 185 return nil, nil, err 186 } 187 } else { 188 err = o.UpdateInterface(string(subshell)) 189 if err != nil { 190 return nil, nil, err 191 } 192 } 193 default: 194 _, v, err := tree.parseVarArray(exec) 195 if err != nil { 196 return nil, nil, err 197 } 198 err = o.UpdateInterface(v) 199 if err != nil { 200 return nil, nil, err 201 } 202 } 203 204 case ':': 205 if o.stage != OBJ_STAGE_KEY { 206 return nil, nil, raiseError( 207 tree.expression, nil, tree.charPos, "invalid symbol ':' expecting ',' or '}' instead") 208 } 209 o.stage++ 210 211 case '\n': 212 err := o.WriteKeyValuePair() 213 if err != nil { 214 return nil, nil, err 215 } 216 tree.crLf() 217 218 case ',': 219 err := o.WriteKeyValuePair() 220 if err != nil { 221 return nil, nil, err 222 } 223 224 case '}': 225 err := o.WriteKeyValuePair() 226 if err != nil { 227 return nil, nil, err 228 } 229 goto endObject 230 231 case '\r': 232 continue 233 234 case ' ', '\t': 235 if !o.IsValueUndefined() { 236 o.keyValue[o.stage].ValueSet = true 237 } 238 continue 239 240 default: 241 value := tree.parseArrayBareword() 242 v, err := types.ConvertGoType(value, types.Number) 243 if err == nil { 244 // is a number 245 err = o.UpdateInterface(v) 246 } else { 247 // is a string 248 s := string(value) 249 switch s { 250 case "true": 251 err = o.UpdateInterface(true) 252 case "false": 253 err = o.UpdateInterface(false) 254 case "null": 255 err = o.UpdateInterface(nil) 256 default: 257 err = o.UpdateInterface(s) 258 } 259 } 260 if err != nil { 261 return nil, nil, err 262 } 263 } 264 } 265 266 return nil, nil, raiseError( 267 tree.expression, nil, tree.charPos, "missing closing bracket '}'") 268 269 endObject: 270 value := tree.expression[start:tree.charPos] 271 tree.charPos-- 272 dt := primitives.NewPrimitive(primitives.Object, o.obj) 273 return value, dt, nil 274 }