mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-17 05:17:53 +08:00
108 lines
2.3 KiB
Go
108 lines
2.3 KiB
Go
package eval
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strconv"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
// Conversion between Go value and Value.
|
|
|
|
func toFloat(arg Value) (float64, error) {
|
|
if _, ok := arg.(String); !ok {
|
|
return 0, fmt.Errorf("must be string")
|
|
}
|
|
s := string(arg.(String))
|
|
num, err := strconv.ParseFloat(s, 64)
|
|
if err != nil {
|
|
num, err2 := strconv.ParseInt(s, 0, 64)
|
|
if err2 != nil {
|
|
return 0, err
|
|
}
|
|
return float64(num), nil
|
|
}
|
|
return num, nil
|
|
}
|
|
|
|
func floatToString(f float64) String {
|
|
return String(strconv.FormatFloat(f, 'g', -1, 64))
|
|
}
|
|
|
|
func toInt(arg Value) (int, error) {
|
|
arg, ok := arg.(String)
|
|
if !ok {
|
|
return 0, fmt.Errorf("must be string")
|
|
}
|
|
num, err := strconv.ParseInt(string(arg.(String)), 0, 0)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(num), nil
|
|
}
|
|
|
|
func toRune(arg Value) (rune, error) {
|
|
ss, ok := arg.(String)
|
|
if !ok {
|
|
return -1, fmt.Errorf("must be string")
|
|
}
|
|
s := string(ss)
|
|
r, size := utf8.DecodeRuneInString(s)
|
|
if r == utf8.RuneError {
|
|
return -1, fmt.Errorf("string is not valid UTF-8")
|
|
}
|
|
if size != len(s) {
|
|
return -1, fmt.Errorf("string has multiple runes")
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
// scanValueToGo converts Value to Go data, depending on the type of the
|
|
// destination.
|
|
func scanValueToGo(src Value, dstPtr interface{}) {
|
|
switch dstPtr := dstPtr.(type) {
|
|
case *string:
|
|
s, ok := src.(String)
|
|
if !ok {
|
|
throwf("cannot convert %T to string", src)
|
|
}
|
|
*dstPtr = string(s)
|
|
case *int:
|
|
i, err := toInt(src)
|
|
maybeThrow(err)
|
|
*dstPtr = i
|
|
case *float64:
|
|
f, err := toFloat(src)
|
|
maybeThrow(err)
|
|
*dstPtr = f
|
|
default:
|
|
ptr := reflect.ValueOf(dstPtr)
|
|
if ptr.Kind() != reflect.Ptr {
|
|
throwf("internal bug: %T to ScanArgs, need pointer", dstPtr)
|
|
}
|
|
dstReflect := reflect.Indirect(ptr)
|
|
if reflect.TypeOf(src).ConvertibleTo(dstReflect.Type()) {
|
|
dstReflect.Set(reflect.ValueOf(src).Convert(dstReflect.Type()))
|
|
} else {
|
|
throwf("need %T argument, got %s", dstReflect.Interface(), src.Kind())
|
|
}
|
|
}
|
|
}
|
|
|
|
// convertGoToValue converts Go data to Value.
|
|
func convertGoToValue(src interface{}) Value {
|
|
switch src := src.(type) {
|
|
case string:
|
|
return String(src)
|
|
case int:
|
|
return String(strconv.Itoa(src))
|
|
case float64:
|
|
return floatToString(src)
|
|
case Value:
|
|
return src
|
|
default:
|
|
throwf("cannot convert type %T to Value", src)
|
|
panic("unreachable")
|
|
}
|
|
}
|