github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/eval/compile_value.go (about) 1 package eval 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 8 "github.com/markusbkk/elvish/pkg/diag" 9 "github.com/markusbkk/elvish/pkg/eval/errs" 10 "github.com/markusbkk/elvish/pkg/eval/vals" 11 "github.com/markusbkk/elvish/pkg/eval/vars" 12 "github.com/markusbkk/elvish/pkg/fsutil" 13 "github.com/markusbkk/elvish/pkg/glob" 14 "github.com/markusbkk/elvish/pkg/parse" 15 ) 16 17 // An operation that produces values. 18 type valuesOp interface { 19 diag.Ranger 20 exec(*Frame) ([]interface{}, Exception) 21 } 22 23 var outputCaptureBufferSize = 16 24 25 func (cp *compiler) compoundOp(n *parse.Compound) valuesOp { 26 if len(n.Indexings) == 0 { 27 return literalValues(n, "") 28 } 29 30 tilde := false 31 indexings := n.Indexings 32 33 if n.Indexings[0].Head.Type == parse.Tilde { 34 // A lone ~. 35 if len(n.Indexings) == 1 { 36 return loneTildeOp{n.Range()} 37 } 38 tilde = true 39 indexings = indexings[1:] 40 } 41 42 return compoundOp{n.Range(), tilde, cp.indexingOps(indexings)} 43 } 44 45 type loneTildeOp struct{ diag.Ranging } 46 47 func (op loneTildeOp) exec(fm *Frame) ([]interface{}, Exception) { 48 home, err := fsutil.GetHome("") 49 if err != nil { 50 return nil, fm.errorp(op, err) 51 } 52 return []interface{}{home}, nil 53 } 54 55 func (cp *compiler) compoundOps(ns []*parse.Compound) []valuesOp { 56 ops := make([]valuesOp, len(ns)) 57 for i, n := range ns { 58 ops[i] = cp.compoundOp(n) 59 } 60 return ops 61 } 62 63 type compoundOp struct { 64 diag.Ranging 65 tilde bool 66 subops []valuesOp 67 } 68 69 func (op compoundOp) exec(fm *Frame) ([]interface{}, Exception) { 70 // Accumulator. 71 vs, exc := op.subops[0].exec(fm) 72 if exc != nil { 73 return nil, exc 74 } 75 76 for _, subop := range op.subops[1:] { 77 us, exc := subop.exec(fm) 78 if exc != nil { 79 return nil, exc 80 } 81 var err error 82 vs, err = outerProduct(vs, us, vals.Concat) 83 if err != nil { 84 return nil, fm.errorp(op, err) 85 } 86 } 87 if op.tilde { 88 newvs := make([]interface{}, len(vs)) 89 for i, v := range vs { 90 tilded, err := doTilde(v) 91 if err != nil { 92 return nil, fm.errorp(op, err) 93 } 94 newvs[i] = tilded 95 } 96 vs = newvs 97 } 98 hasGlob := false 99 for _, v := range vs { 100 if _, ok := v.(globPattern); ok { 101 hasGlob = true 102 break 103 } 104 } 105 if hasGlob { 106 newvs := make([]interface{}, 0, len(vs)) 107 for _, v := range vs { 108 if gp, ok := v.(globPattern); ok { 109 results, err := doGlob(gp, fm.Interrupts()) 110 if err != nil { 111 return nil, fm.errorp(op, err) 112 } 113 newvs = append(newvs, results...) 114 } else { 115 newvs = append(newvs, v) 116 } 117 } 118 vs = newvs 119 } 120 return vs, nil 121 } 122 123 func outerProduct(vs []interface{}, us []interface{}, f func(interface{}, interface{}) (interface{}, error)) ([]interface{}, error) { 124 ws := make([]interface{}, len(vs)*len(us)) 125 nu := len(us) 126 for i, v := range vs { 127 for j, u := range us { 128 var err error 129 ws[i*nu+j], err = f(v, u) 130 if err != nil { 131 return nil, err 132 } 133 } 134 } 135 return ws, nil 136 } 137 138 // Errors thrown when globbing. 139 var ( 140 ErrBadglobPattern = errors.New("bad globPattern; elvish bug") 141 ErrCannotDetermineUsername = errors.New("cannot determine user name from glob pattern") 142 ) 143 144 func doTilde(v interface{}) (interface{}, error) { 145 switch v := v.(type) { 146 case string: 147 s := v 148 // TODO: Make this correct on Windows. 149 i := strings.Index(s, "/") 150 var uname, rest string 151 if i == -1 { 152 uname = s 153 } else { 154 uname = s[:i] 155 rest = s[i:] 156 } 157 dir, err := fsutil.GetHome(uname) 158 if err != nil { 159 return nil, err 160 } 161 return dir + rest, nil 162 case globPattern: 163 if len(v.Segments) == 0 { 164 return nil, ErrBadglobPattern 165 } 166 switch seg := v.Segments[0].(type) { 167 case glob.Literal: 168 if len(v.Segments) == 1 { 169 return nil, ErrBadglobPattern 170 } 171 _, isSlash := v.Segments[1].(glob.Slash) 172 if isSlash { 173 // ~username or ~username/xxx. Replace the first segment with 174 // the home directory of the specified user. 175 dir, err := fsutil.GetHome(seg.Data) 176 if err != nil { 177 return nil, err 178 } 179 v.Segments[0] = glob.Literal{Data: dir} 180 return v, nil 181 } 182 case glob.Slash: 183 dir, err := fsutil.GetHome("") 184 if err != nil { 185 return nil, err 186 } 187 v.DirOverride = dir 188 return v, nil 189 } 190 return nil, ErrCannotDetermineUsername 191 default: 192 return nil, fmt.Errorf("tilde doesn't work on value of type %s", vals.Kind(v)) 193 } 194 } 195 196 func (cp *compiler) arrayOp(n *parse.Array) valuesOp { 197 return seqValuesOp{n.Range(), cp.compoundOps(n.Compounds)} 198 } 199 200 func (cp *compiler) arrayOps(ns []*parse.Array) []valuesOp { 201 ops := make([]valuesOp, len(ns)) 202 for i, n := range ns { 203 ops[i] = cp.arrayOp(n) 204 } 205 return ops 206 } 207 208 func (cp *compiler) indexingOp(n *parse.Indexing) valuesOp { 209 if len(n.Indices) == 0 { 210 return cp.primaryOp(n.Head) 211 } 212 return &indexingOp{n.Range(), cp.primaryOp(n.Head), cp.arrayOps(n.Indices)} 213 } 214 215 func (cp *compiler) indexingOps(ns []*parse.Indexing) []valuesOp { 216 ops := make([]valuesOp, len(ns)) 217 for i, n := range ns { 218 ops[i] = cp.indexingOp(n) 219 } 220 return ops 221 } 222 223 type indexingOp struct { 224 diag.Ranging 225 headOp valuesOp 226 indexOps []valuesOp 227 } 228 229 func (op *indexingOp) exec(fm *Frame) ([]interface{}, Exception) { 230 vs, exc := op.headOp.exec(fm) 231 if exc != nil { 232 return nil, exc 233 } 234 for _, indexOp := range op.indexOps { 235 indices, exc := indexOp.exec(fm) 236 if exc != nil { 237 return nil, exc 238 } 239 newvs := make([]interface{}, 0, len(vs)*len(indices)) 240 for _, v := range vs { 241 for _, index := range indices { 242 result, err := vals.Index(v, index) 243 if err != nil { 244 return nil, fm.errorp(op, err) 245 } 246 newvs = append(newvs, result) 247 } 248 } 249 vs = newvs 250 } 251 return vs, nil 252 } 253 254 func (cp *compiler) primaryOp(n *parse.Primary) valuesOp { 255 switch n.Type { 256 case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted: 257 return literalValues(n, n.Value) 258 case parse.Variable: 259 sigil, qname := SplitSigil(n.Value) 260 ref := resolveVarRef(cp, qname, n) 261 if ref == nil { 262 cp.errorpf(n, "variable $%s not found", qname) 263 } 264 return &variableOp{n.Range(), sigil != "", qname, ref} 265 case parse.Wildcard: 266 seg, err := wildcardToSegment(parse.SourceText(n)) 267 if err != nil { 268 cp.errorpf(n, "%s", err) 269 } 270 vs := []interface{}{ 271 globPattern{Pattern: glob.Pattern{Segments: []glob.Segment{seg}, DirOverride: ""}, 272 Flags: 0, Buts: nil, TypeCb: nil}} 273 return literalValues(n, vs...) 274 case parse.Tilde: 275 cp.errorpf(n, "compiler bug: Tilde not handled in .compound") 276 return literalValues(n, "~") 277 case parse.ExceptionCapture: 278 return exceptionCaptureOp{n.Range(), cp.chunkOp(n.Chunk)} 279 case parse.OutputCapture: 280 return outputCaptureOp{n.Range(), cp.chunkOp(n.Chunk)} 281 case parse.List: 282 return listOp{n.Range(), cp.compoundOps(n.Elements)} 283 case parse.Lambda: 284 return cp.lambda(n) 285 case parse.Map: 286 return mapOp{n.Range(), cp.mapPairs(n.MapPairs)} 287 case parse.Braced: 288 return seqValuesOp{n.Range(), cp.compoundOps(n.Braced)} 289 default: 290 cp.errorpf(n, "bad PrimaryType; parser bug") 291 return literalValues(n, parse.SourceText(n)) 292 } 293 } 294 295 func (cp *compiler) primaryOps(ns []*parse.Primary) []valuesOp { 296 ops := make([]valuesOp, len(ns)) 297 for i, n := range ns { 298 ops[i] = cp.primaryOp(n) 299 } 300 return ops 301 } 302 303 type variableOp struct { 304 diag.Ranging 305 explode bool 306 qname string 307 ref *varRef 308 } 309 310 func (op variableOp) exec(fm *Frame) ([]interface{}, Exception) { 311 variable := deref(fm, op.ref) 312 if variable == nil { 313 return nil, fm.errorpf(op, "variable $%s not found", op.qname) 314 } 315 value := variable.Get() 316 if op.explode { 317 vs, err := vals.Collect(value) 318 return vs, fm.errorp(op, err) 319 } 320 return []interface{}{value}, nil 321 } 322 323 type listOp struct { 324 diag.Ranging 325 subops []valuesOp 326 } 327 328 func (op listOp) exec(fm *Frame) ([]interface{}, Exception) { 329 list := vals.EmptyList 330 for _, subop := range op.subops { 331 moreValues, exc := subop.exec(fm) 332 if exc != nil { 333 return nil, exc 334 } 335 for _, moreValue := range moreValues { 336 list = list.Conj(moreValue) 337 } 338 } 339 return []interface{}{list}, nil 340 } 341 342 type exceptionCaptureOp struct { 343 diag.Ranging 344 subop effectOp 345 } 346 347 func (op exceptionCaptureOp) exec(fm *Frame) ([]interface{}, Exception) { 348 exc := op.subop.exec(fm) 349 if exc == nil { 350 return []interface{}{OK}, nil 351 } 352 return []interface{}{exc}, nil 353 } 354 355 type outputCaptureOp struct { 356 diag.Ranging 357 subop effectOp 358 } 359 360 func (op outputCaptureOp) exec(fm *Frame) ([]interface{}, Exception) { 361 outPort, collect, err := CapturePort() 362 if err != nil { 363 return nil, fm.errorp(op, err) 364 } 365 exc := op.subop.exec(fm.forkWithOutput("[output capture]", outPort)) 366 return collect(), exc 367 } 368 369 func (cp *compiler) lambda(n *parse.Primary) valuesOp { 370 // Parse signature. 371 var ( 372 argNames []string 373 restArg int = -1 374 optNames []string 375 optDefaultOps []valuesOp 376 ) 377 if len(n.Elements) > 0 { 378 // Argument list. 379 argNames = make([]string, len(n.Elements)) 380 for i, arg := range n.Elements { 381 ref := stringLiteralOrError(cp, arg, "argument name") 382 sigil, qname := SplitSigil(ref) 383 name, rest := SplitQName(qname) 384 if rest != "" { 385 cp.errorpf(arg, "argument name must be unqualified") 386 } 387 if name == "" { 388 cp.errorpf(arg, "argument name must not be empty") 389 } 390 if sigil == "@" { 391 if restArg != -1 { 392 cp.errorpf(arg, "only one argument may have @") 393 } 394 restArg = i 395 } 396 argNames[i] = name 397 } 398 } 399 if len(n.MapPairs) > 0 { 400 optNames = make([]string, len(n.MapPairs)) 401 optDefaultOps = make([]valuesOp, len(n.MapPairs)) 402 for i, opt := range n.MapPairs { 403 qname := stringLiteralOrError(cp, opt.Key, "option name") 404 name, rest := SplitQName(qname) 405 if rest != "" { 406 cp.errorpf(opt.Key, "option name must be unqualified") 407 } 408 if name == "" { 409 cp.errorpf(opt.Key, "option name must not be empty") 410 } 411 optNames[i] = name 412 if opt.Value == nil { 413 cp.errorpf(opt.Key, "option must have default value") 414 } else { 415 optDefaultOps[i] = cp.compoundOp(opt.Value) 416 } 417 } 418 } 419 420 local, capture := cp.pushScope() 421 for _, argName := range argNames { 422 local.add(argName) 423 } 424 for _, optName := range optNames { 425 local.add(optName) 426 } 427 scopeSizeInit := len(local.infos) 428 chunkOp := cp.chunkOp(n.Chunk) 429 newLocal := local.infos[scopeSizeInit:] 430 cp.popScope() 431 432 return &lambdaOp{n.Range(), argNames, restArg, optNames, optDefaultOps, newLocal, capture, chunkOp, cp.srcMeta} 433 } 434 435 type lambdaOp struct { 436 diag.Ranging 437 argNames []string 438 restArg int 439 optNames []string 440 optDefaultOps []valuesOp 441 newLocal []staticVarInfo 442 capture *staticUpNs 443 subop effectOp 444 srcMeta parse.Source 445 } 446 447 func (op *lambdaOp) exec(fm *Frame) ([]interface{}, Exception) { 448 capture := &Ns{ 449 make([]vars.Var, len(op.capture.infos)), 450 make([]staticVarInfo, len(op.capture.infos))} 451 for i, info := range op.capture.infos { 452 if info.local { 453 capture.slots[i] = fm.local.slots[info.index] 454 capture.infos[i] = fm.local.infos[info.index] 455 } else { 456 capture.slots[i] = fm.up.slots[info.index] 457 capture.infos[i] = fm.up.infos[info.index] 458 } 459 } 460 optDefaults := make([]interface{}, len(op.optDefaultOps)) 461 for i, op := range op.optDefaultOps { 462 defaultValue, err := evalForValue(fm, op, "option default value") 463 if err != nil { 464 return nil, err 465 } 466 optDefaults[i] = defaultValue 467 } 468 return []interface{}{&Closure{op.argNames, op.restArg, op.optNames, optDefaults, op.srcMeta, op.Range(), op.subop, op.newLocal, capture}}, nil 469 } 470 471 type mapOp struct { 472 diag.Ranging 473 pairsOp *mapPairsOp 474 } 475 476 func (op mapOp) exec(fm *Frame) ([]interface{}, Exception) { 477 m := vals.EmptyMap 478 exc := op.pairsOp.exec(fm, func(k, v interface{}) Exception { 479 m = m.Assoc(k, v) 480 return nil 481 }) 482 if exc != nil { 483 return nil, exc 484 } 485 return []interface{}{m}, nil 486 } 487 488 func (cp *compiler) mapPairs(pairs []*parse.MapPair) *mapPairsOp { 489 npairs := len(pairs) 490 keysOps := make([]valuesOp, npairs) 491 valuesOps := make([]valuesOp, npairs) 492 begins, ends := make([]int, npairs), make([]int, npairs) 493 for i, pair := range pairs { 494 keysOps[i] = cp.compoundOp(pair.Key) 495 if pair.Value == nil { 496 p := pair.Range().To 497 valuesOps[i] = literalValues(diag.PointRanging(p), true) 498 } else { 499 valuesOps[i] = cp.compoundOp(pairs[i].Value) 500 } 501 begins[i], ends[i] = pair.Range().From, pair.Range().To 502 } 503 return &mapPairsOp{keysOps, valuesOps, begins, ends} 504 } 505 506 type mapPairsOp struct { 507 keysOps []valuesOp 508 valuesOps []valuesOp 509 begins []int 510 ends []int 511 } 512 513 func (op *mapPairsOp) exec(fm *Frame, f func(k, v interface{}) Exception) Exception { 514 for i := range op.keysOps { 515 keys, exc := op.keysOps[i].exec(fm) 516 if exc != nil { 517 return exc 518 } 519 values, exc := op.valuesOps[i].exec(fm) 520 if exc != nil { 521 return exc 522 } 523 if len(keys) != len(values) { 524 return fm.errorpf(diag.Ranging{From: op.begins[i], To: op.ends[i]}, 525 "%d keys but %d values", len(keys), len(values)) 526 } 527 for j, key := range keys { 528 err := f(key, values[j]) 529 if err != nil { 530 return err 531 } 532 } 533 } 534 return nil 535 } 536 537 type literalValuesOp struct { 538 diag.Ranging 539 values []interface{} 540 } 541 542 func (op literalValuesOp) exec(*Frame) ([]interface{}, Exception) { 543 return op.values, nil 544 } 545 546 func literalValues(r diag.Ranger, vs ...interface{}) valuesOp { 547 return literalValuesOp{r.Range(), vs} 548 } 549 550 type seqValuesOp struct { 551 diag.Ranging 552 subops []valuesOp 553 } 554 555 func (op seqValuesOp) exec(fm *Frame) ([]interface{}, Exception) { 556 var values []interface{} 557 for _, subop := range op.subops { 558 moreValues, exc := subop.exec(fm) 559 if exc != nil { 560 return nil, exc 561 } 562 values = append(values, moreValues...) 563 } 564 return values, nil 565 } 566 567 type nopValuesOp struct{ diag.Ranging } 568 569 func (nopValuesOp) exec(fm *Frame) ([]interface{}, Exception) { return nil, nil } 570 571 func evalForValue(fm *Frame, op valuesOp, what string) (interface{}, Exception) { 572 values, exc := op.exec(fm) 573 if exc != nil { 574 return nil, exc 575 } 576 if len(values) != 1 { 577 return nil, fm.errorp(op, errs.ArityMismatch{What: what, 578 ValidLow: 1, ValidHigh: 1, Actual: len(values)}) 579 } 580 return values[0], nil 581 }