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  }