github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/eval/unwrap.go (about) 1 package eval 2 3 import ( 4 "fmt" 5 "strconv" 6 7 "github.com/u-root/u-root/cmds/core/elvish/eval/vals" 8 ) 9 10 // Unwrappers are helper types for "unwrapping" values, the process for 11 // asserting certain properties of values and throwing exceptions when such 12 // properties are not satisfied. 13 14 type unwrapperInner struct { 15 // ctx is the evaluation context. 16 ctx *Frame 17 // description describes what is being unwrapped. It is used in error 18 // messages. 19 description string 20 // begin and end contains positions in the source code to point to when 21 // error occurs. 22 begin, end int 23 // values contain the Value's to unwrap. 24 values []interface{} 25 } 26 27 func (u *unwrapperInner) error(want, gotfmt string, gotargs ...interface{}) { 28 got := fmt.Sprintf(gotfmt, gotargs...) 29 u.ctx.errorpf(u.begin, u.end, "%s must be %s; got %s", u.description, 30 want, got) 31 } 32 33 // ValuesUnwrapper unwraps []Value. 34 type ValuesUnwrapper struct{ *unwrapperInner } 35 36 // Unwrap creates an Unwrapper. 37 func (ctx *Frame) Unwrap(desc string, begin, end int, vs []interface{}) ValuesUnwrapper { 38 return ValuesUnwrapper{&unwrapperInner{ctx, desc, begin, end, vs}} 39 } 40 41 // ExecAndUnwrap executes a ValuesOp and creates an Unwrapper for the obtained 42 // values. 43 func (ctx *Frame) ExecAndUnwrap(desc string, op ValuesOp) ValuesUnwrapper { 44 values, err := op.Exec(ctx) 45 maybeThrow(err) 46 return ctx.Unwrap(desc, op.Begin, op.End, values) 47 } 48 49 // One unwraps the value to be exactly one value. 50 func (u ValuesUnwrapper) One() ValueUnwrapper { 51 if len(u.values) != 1 { 52 u.error("a single value", "%d values", len(u.values)) 53 } 54 return ValueUnwrapper{u.unwrapperInner} 55 } 56 57 // ValueUnwrapper unwraps one Value. 58 type ValueUnwrapper struct{ *unwrapperInner } 59 60 func (u ValueUnwrapper) Any() interface{} { 61 return u.values[0] 62 } 63 64 func (u ValueUnwrapper) String() string { 65 s, ok := u.values[0].(string) 66 if !ok { 67 u.error("string", "%s", vals.Kind(u.values[0])) 68 } 69 return s 70 } 71 72 func (u ValueUnwrapper) Int() int { 73 s := u.String() 74 i, err := strconv.Atoi(s) 75 if err != nil { 76 u.error("integer", "%s", s) 77 } 78 return i 79 } 80 81 func (u ValueUnwrapper) NonNegativeInt() int { 82 i := u.Int() 83 if i < 0 { 84 u.error("non-negative int", "%d", i) 85 } 86 return i 87 } 88 89 func (u ValueUnwrapper) FdOrClose() int { 90 s := u.String() 91 if s == "-" { 92 return -1 93 } 94 return u.NonNegativeInt() 95 } 96 97 func (u ValueUnwrapper) Callable() Callable { 98 c, ok := u.values[0].(Callable) 99 if !ok { 100 u.error("callable", "%s", vals.Kind(u.values[0])) 101 } 102 return c 103 }