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