github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/eval/compile_value.go (about) 1 package eval 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "io" 8 "os" 9 "path" 10 "strings" 11 "sync" 12 13 "github.com/u-root/u-root/cmds/core/elvish/eval/vals" 14 "github.com/u-root/u-root/cmds/core/elvish/glob" 15 "github.com/u-root/u-root/cmds/core/elvish/parse" 16 "github.com/u-root/u-root/cmds/core/elvish/util" 17 ) 18 19 var outputCaptureBufferSize = 16 20 21 // ValuesOp is an operation on an Frame that produce Value's. 22 type ValuesOp struct { 23 Body ValuesOpBody 24 Begin, End int 25 } 26 27 // ValuesOpBody is the body of ValuesOp. 28 type ValuesOpBody interface { 29 Invoke(*Frame) ([]interface{}, error) 30 } 31 32 // Exec executes a ValuesOp and produces Value's. 33 func (op ValuesOp) Exec(fm *Frame) ([]interface{}, error) { 34 fm.begin, fm.end = op.Begin, op.End 35 return op.Body.Invoke(fm) 36 } 37 38 func (cp *compiler) compound(n *parse.Compound) ValuesOpBody { 39 if len(n.Indexings) == 0 { 40 return literalStr("") 41 } 42 43 tilde := false 44 indexings := n.Indexings 45 46 if n.Indexings[0].Head.Type == parse.Tilde { 47 // A lone ~. 48 if len(n.Indexings) == 1 { 49 return funcValuesOp(func(fm *Frame) ([]interface{}, error) { 50 home, err := util.GetHome("") 51 if err != nil { 52 return nil, err 53 } 54 return []interface{}{home}, nil 55 }) 56 } 57 tilde = true 58 indexings = indexings[1:] 59 } 60 61 return compoundOp{tilde, cp.indexingOps(indexings)} 62 } 63 64 type compoundOp struct { 65 tilde bool 66 subops []ValuesOp 67 } 68 69 func (op compoundOp) Invoke(fm *Frame) ([]interface{}, error) { 70 // Accumulator. 71 vs, err := op.subops[0].Exec(fm) 72 if err != nil { 73 return nil, err 74 } 75 76 for _, subop := range op.subops[1:] { 77 us, err := subop.Exec(fm) 78 if err != nil { 79 return nil, err 80 } 81 vs, err = outerProduct(vs, us, vals.Concat) 82 if err != nil { 83 return nil, err 84 } 85 } 86 if op.tilde { 87 newvs := make([]interface{}, len(vs)) 88 for i, v := range vs { 89 newvs[i] = doTilde(v) 90 } 91 vs = newvs 92 } 93 hasGlob := false 94 for _, v := range vs { 95 if _, ok := v.(GlobPattern); ok { 96 hasGlob = true 97 break 98 } 99 } 100 if hasGlob { 101 newvs := make([]interface{}, 0, len(vs)) 102 for _, v := range vs { 103 if gp, ok := v.(GlobPattern); ok { 104 // Logger.Printf("globbing %v", gp) 105 newvs = append(newvs, doGlob(gp, fm.Interrupts())...) 106 } else { 107 newvs = append(newvs, v) 108 } 109 } 110 vs = newvs 111 } 112 return vs, nil 113 } 114 115 func outerProduct(vs []interface{}, us []interface{}, f func(interface{}, interface{}) (interface{}, error)) ([]interface{}, error) { 116 ws := make([]interface{}, len(vs)*len(us)) 117 nu := len(us) 118 for i, v := range vs { 119 for j, u := range us { 120 var err error 121 ws[i*nu+j], err = f(v, u) 122 if err != nil { 123 return nil, err 124 } 125 } 126 } 127 return ws, nil 128 } 129 130 // Errors thrown when globbing. 131 var ( 132 ErrBadGlobPattern = errors.New("bad GlobPattern; elvish bug") 133 ErrCannotDetermineUsername = errors.New("cannot determine user name from glob pattern") 134 ) 135 136 func doTilde(v interface{}) interface{} { 137 switch v := v.(type) { 138 case string: 139 s := v 140 i := strings.Index(s, "/") 141 var uname, rest string 142 if i == -1 { 143 uname = s 144 } else { 145 uname = s[:i] 146 rest = s[i+1:] 147 } 148 dir := mustGetHome(uname) 149 return path.Join(dir, rest) 150 case GlobPattern: 151 if len(v.Segments) == 0 { 152 throw(ErrBadGlobPattern) 153 } 154 switch seg := v.Segments[0].(type) { 155 case glob.Literal: 156 s := seg.Data 157 // Find / in the first segment to determine the username. 158 i := strings.Index(s, "/") 159 if i == -1 { 160 throw(ErrCannotDetermineUsername) 161 } 162 uname := s[:i] 163 dir := mustGetHome(uname) 164 // Replace ~uname in first segment with the found path. 165 v.Segments[0] = glob.Literal{dir + s[i:]} 166 case glob.Slash: 167 v.DirOverride = mustGetHome("") 168 default: 169 throw(ErrCannotDetermineUsername) 170 } 171 return v 172 default: 173 throw(fmt.Errorf("tilde doesn't work on value of type %s", vals.Kind(v))) 174 panic("unreachable") 175 } 176 } 177 178 func (cp *compiler) array(n *parse.Array) ValuesOpBody { 179 return seqValuesOp{cp.compoundOps(n.Compounds)} 180 } 181 182 func (cp *compiler) indexing(n *parse.Indexing) ValuesOpBody { 183 if len(n.Indicies) == 0 { 184 return cp.primary(n.Head) 185 } 186 187 return &indexingOp{cp.primaryOp(n.Head), cp.arrayOps(n.Indicies)} 188 } 189 190 type indexingOp struct { 191 headOp ValuesOp 192 indexOps []ValuesOp 193 } 194 195 func (op *indexingOp) Invoke(fm *Frame) ([]interface{}, error) { 196 vs, err := op.headOp.Exec(fm) 197 if err != nil { 198 return nil, err 199 } 200 for _, indexOp := range op.indexOps { 201 indicies, err := indexOp.Exec(fm) 202 if err != nil { 203 return nil, err 204 } 205 newvs := make([]interface{}, 0, len(vs)*len(indicies)) 206 for _, v := range vs { 207 for _, index := range indicies { 208 result, err := vals.Index(v, index) 209 if err != nil { 210 return nil, err 211 } 212 newvs = append(newvs, result) 213 } 214 } 215 vs = newvs 216 } 217 return vs, nil 218 } 219 220 func (cp *compiler) primary(n *parse.Primary) ValuesOpBody { 221 switch n.Type { 222 case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted: 223 return literalStr(n.Value) 224 case parse.Variable: 225 explode, ns, name := ParseVariableRef(n.Value) 226 if !cp.registerVariableGet(ns, name) { 227 cp.errorf("variable $%s not found", n.Value) 228 } 229 return &variableOp{explode, ns, name} 230 case parse.Wildcard: 231 seg, err := wildcardToSegment(n.SourceText()) 232 if err != nil { 233 cp.errorf("%s", err) 234 } 235 vs := []interface{}{ 236 GlobPattern{glob.Pattern{[]glob.Segment{seg}, ""}, 0, nil}} 237 return literalValues(vs...) 238 case parse.Tilde: 239 cp.errorf("compiler bug: Tilde not handled in .compound") 240 return literalStr("~") 241 case parse.ExceptionCapture: 242 return exceptionCaptureOp{cp.chunkOp(n.Chunk)} 243 case parse.OutputCapture: 244 return outputCaptureOp{cp.chunkOp(n.Chunk)} 245 case parse.List: 246 return cp.list(n) 247 case parse.Lambda: 248 return cp.lambda(n) 249 case parse.Map: 250 return cp.map_(n) 251 case parse.Braced: 252 return cp.braced(n) 253 default: 254 cp.errorf("bad PrimaryType; parser bug") 255 return literalStr(n.SourceText()) 256 } 257 } 258 259 type variableOp struct { 260 explode bool 261 ns string 262 name string 263 } 264 265 func (op variableOp) Invoke(fm *Frame) ([]interface{}, error) { 266 variable := fm.ResolveVar(op.ns, op.name) 267 if variable == nil { 268 return nil, fmt.Errorf("variable $%s:%s not found", op.ns, op.name) 269 } 270 value := variable.Get() 271 if op.explode { 272 return vals.Collect(value) 273 } 274 return []interface{}{value}, nil 275 } 276 277 func (cp *compiler) list(n *parse.Primary) ValuesOpBody { 278 return listOp{cp.compoundOps(n.Elements)} 279 } 280 281 type listOp struct{ subops []ValuesOp } 282 283 func (op listOp) Invoke(fm *Frame) ([]interface{}, error) { 284 list := vals.EmptyList 285 for _, subop := range op.subops { 286 moreValues, err := subop.Exec(fm) 287 if err != nil { 288 return nil, err 289 } 290 for _, moreValue := range moreValues { 291 list = list.Cons(moreValue) 292 } 293 } 294 return []interface{}{list}, nil 295 } 296 297 type exceptionCaptureOp struct{ subop Op } 298 299 func (op exceptionCaptureOp) Invoke(fm *Frame) ([]interface{}, error) { 300 err := fm.Eval(op.subop) 301 if err == nil { 302 return []interface{}{OK}, nil 303 } 304 return []interface{}{err.(*Exception)}, nil 305 } 306 307 type outputCaptureOp struct{ subop Op } 308 309 func (op outputCaptureOp) Invoke(fm *Frame) ([]interface{}, error) { 310 return pcaptureOutput(fm, op.subop) 311 } 312 313 func pcaptureOutput(fm *Frame, op Op) ([]interface{}, error) { 314 vs := []interface{}{} 315 var m sync.Mutex 316 valueCb := func(ch <-chan interface{}) { 317 for v := range ch { 318 m.Lock() 319 vs = append(vs, v) 320 m.Unlock() 321 } 322 } 323 bytesCb := func(r *os.File) { 324 buffered := bufio.NewReader(r) 325 for { 326 line, err := buffered.ReadString('\n') 327 if line != "" { 328 v := strings.TrimSuffix(line, "\n") 329 m.Lock() 330 vs = append(vs, v) 331 m.Unlock() 332 } 333 if err != nil { 334 if err != io.EOF { 335 logger.Println("error on reading:", err) 336 } 337 break 338 } 339 } 340 } 341 342 err := pcaptureOutputInner(fm, op, valueCb, bytesCb) 343 return vs, err 344 } 345 346 func pcaptureOutputInner(fm *Frame, op Op, valuesCb func(<-chan interface{}), bytesCb func(*os.File)) error { 347 348 newFm := fm.fork("[output capture]") 349 350 ch := make(chan interface{}, outputCaptureBufferSize) 351 pipeRead, pipeWrite, err := os.Pipe() 352 if err != nil { 353 return fmt.Errorf("failed to create pipe: %v", err) 354 } 355 newFm.ports[1] = &Port{ 356 Chan: ch, CloseChan: true, 357 File: pipeWrite, CloseFile: true, 358 } 359 360 bytesCollected := make(chan struct{}) 361 chCollected := make(chan struct{}) 362 363 go func() { 364 valuesCb(ch) 365 close(chCollected) 366 }() 367 go func() { 368 bytesCb(pipeRead) 369 pipeRead.Close() 370 close(bytesCollected) 371 }() 372 373 err = newFm.Eval(op) 374 375 newFm.Close() 376 <-bytesCollected 377 <-chCollected 378 379 return err 380 } 381 382 func (cp *compiler) lambda(n *parse.Primary) ValuesOpBody { 383 // Parse signature. 384 var ( 385 argNames []string 386 restArgName string 387 optNames []string 388 optDefaultOps []ValuesOp 389 ) 390 if len(n.Elements) > 0 { 391 // Argument list. 392 argNames = make([]string, len(n.Elements)) 393 for i, arg := range n.Elements { 394 qname := mustString(cp, arg, "argument name must be literal string") 395 explode, ns, name := ParseVariableRef(qname) 396 if ns != "" { 397 cp.errorpf(arg.Begin(), arg.End(), "argument name must be unqualified") 398 } 399 if name == "" { 400 cp.errorpf(arg.Begin(), arg.End(), "argument name must not be empty") 401 } 402 if explode { 403 if i != len(n.Elements)-1 { 404 cp.errorpf(arg.Begin(), arg.End(), "only the last argument may have @") 405 } 406 restArgName = name 407 argNames = argNames[:i] 408 } else { 409 argNames[i] = name 410 } 411 } 412 } 413 if len(n.MapPairs) > 0 { 414 optNames = make([]string, len(n.MapPairs)) 415 optDefaultOps = make([]ValuesOp, len(n.MapPairs)) 416 for i, opt := range n.MapPairs { 417 qname := mustString(cp, opt.Key, "option name must be literal string") 418 _, ns, name := ParseVariableRef(qname) 419 if ns != "" { 420 cp.errorpf(opt.Key.Begin(), opt.Key.End(), "option name must be unqualified") 421 } 422 if name == "" { 423 cp.errorpf(opt.Key.Begin(), opt.Key.End(), "option name must not be empty") 424 } 425 optNames[i] = name 426 if opt.Value == nil { 427 cp.errorpf(opt.End(), opt.End(), "option must have default value") 428 } else { 429 optDefaultOps[i] = cp.compoundOp(opt.Value) 430 } 431 } 432 } 433 434 thisScope := cp.pushScope() 435 for _, argName := range argNames { 436 thisScope.set(argName) 437 } 438 if restArgName != "" { 439 thisScope.set(restArgName) 440 } 441 for _, optName := range optNames { 442 thisScope.set(optName) 443 } 444 445 subop := cp.chunkOp(n.Chunk) 446 447 // XXX The fiddlings with cp.capture is error-prone. 448 capture := cp.capture 449 cp.capture = make(staticNs) 450 cp.popScope() 451 452 for name := range capture { 453 cp.registerVariableGetQname(name) 454 } 455 456 return &lambdaOp{argNames, restArgName, optNames, optDefaultOps, capture, subop, cp.srcMeta, n.Begin(), n.End()} 457 } 458 459 type lambdaOp struct { 460 argNames []string 461 restArgName string 462 optNames []string 463 optDefaultOps []ValuesOp 464 capture staticNs 465 subop Op 466 srcMeta *Source 467 defBegin int 468 defEnd int 469 } 470 471 func (op *lambdaOp) Invoke(fm *Frame) ([]interface{}, error) { 472 evCapture := make(Ns) 473 for name := range op.capture { 474 evCapture[name] = fm.ResolveVar("", name) 475 } 476 optDefaults := make([]interface{}, len(op.optDefaultOps)) 477 for i, op := range op.optDefaultOps { 478 defaultValue := fm.ExecAndUnwrap("option default value", op).One().Any() 479 optDefaults[i] = defaultValue 480 } 481 // XXX(xiaq): Capture uses. 482 return []interface{}{&Closure{op.argNames, op.restArgName, op.optNames, optDefaults, op.subop, evCapture, op.srcMeta, op.defBegin, op.defEnd}}, nil 483 } 484 485 func (cp *compiler) map_(n *parse.Primary) ValuesOpBody { 486 return cp.mapPairs(n.MapPairs) 487 } 488 489 func (cp *compiler) mapPairs(pairs []*parse.MapPair) ValuesOpBody { 490 npairs := len(pairs) 491 keysOps := make([]ValuesOp, npairs) 492 valuesOps := make([]ValuesOp, npairs) 493 begins, ends := make([]int, npairs), make([]int, npairs) 494 for i, pair := range pairs { 495 keysOps[i] = cp.compoundOp(pair.Key) 496 if pair.Value == nil { 497 p := pair.End() 498 valuesOps[i] = ValuesOp{literalValues(true), p, p} 499 } else { 500 valuesOps[i] = cp.compoundOp(pairs[i].Value) 501 } 502 begins[i], ends[i] = pair.Begin(), pair.End() 503 } 504 return &mapPairsOp{keysOps, valuesOps, begins, ends} 505 } 506 507 type mapPairsOp struct { 508 keysOps []ValuesOp 509 valuesOps []ValuesOp 510 begins []int 511 ends []int 512 } 513 514 func (op *mapPairsOp) Invoke(fm *Frame) ([]interface{}, error) { 515 m := vals.EmptyMap 516 for i := range op.keysOps { 517 keys, err := op.keysOps[i].Exec(fm) 518 if err != nil { 519 return nil, err 520 } 521 values, err := op.valuesOps[i].Exec(fm) 522 if err != nil { 523 return nil, err 524 } 525 if len(keys) != len(values) { 526 fm.errorpf(op.begins[i], op.ends[i], 527 "%d keys but %d values", len(keys), len(values)) 528 } 529 for j, key := range keys { 530 m = m.Assoc(key, values[j]) 531 } 532 } 533 return []interface{}{m}, nil 534 } 535 536 func (cp *compiler) braced(n *parse.Primary) ValuesOpBody { 537 ops := cp.compoundOps(n.Braced) 538 // TODO: n.IsRange 539 // isRange := n.IsRange 540 return seqValuesOp{ops} 541 } 542 543 type literalValuesOp struct{ values []interface{} } 544 545 func (op literalValuesOp) Invoke(*Frame) ([]interface{}, error) { 546 return op.values, nil 547 } 548 549 func literalValues(v ...interface{}) ValuesOpBody { 550 return literalValuesOp{v} 551 } 552 553 func literalStr(text string) ValuesOpBody { 554 return literalValues(text) 555 } 556 557 type seqValuesOp struct{ subops []ValuesOp } 558 559 func (op seqValuesOp) Invoke(fm *Frame) ([]interface{}, error) { 560 var values []interface{} 561 for _, subop := range op.subops { 562 moreValues, err := subop.Exec(fm) 563 if err != nil { 564 return nil, err 565 } 566 values = append(values, moreValues...) 567 } 568 return values, nil 569 } 570 571 type funcValuesOp func(*Frame) ([]interface{}, error) 572 573 func (op funcValuesOp) Invoke(fm *Frame) ([]interface{}, error) { return op(fm) }