miller/pkg/mlrval/mlrval_new.go

365 lines
8.7 KiB
Go

// ================================================================
// Constructors
// ================================================================
package mlrval
import (
"errors"
"fmt"
"github.com/johnkerl/miller/v6/pkg/lib"
)
// TODO: comment for JSON-scanner context.
func FromPending() *Mlrval {
return &Mlrval{
mvtype: MT_PENDING,
printrep: "(bug-if-you-see-this:case-1)",
printrepValid: false,
}
}
// TODO: comment JIT context. Some things we already know are typed -- DSL
// things, or JSON contents. Others are deferred, e.g. items from any file
// format except JSON.
// TODO: comment re inferBool.
func FromDeferredType(input string) *Mlrval {
return &Mlrval{
mvtype: MT_PENDING,
printrep: input,
printrepValid: true,
}
}
func FromError(err error) *Mlrval {
return &Mlrval{
mvtype: MT_ERROR,
err: err,
printrep: ERROR_PRINTREP,
printrepValid: true,
}
}
func FromErrorString(err string) *Mlrval {
return &Mlrval{
mvtype: MT_ERROR,
err: errors.New(err),
printrep: ERROR_PRINTREP,
printrepValid: true,
}
}
func FromAnonymousError() *Mlrval {
return &Mlrval{
mvtype: MT_ERROR,
printrep: ERROR_PRINTREP,
printrepValid: true,
}
}
func FromTypeErrorUnary(funcname string, v *Mlrval) *Mlrval {
return FromError(
fmt.Errorf(
"%s: unacceptable type %s with value %s",
funcname,
v.GetTypeName(),
v.StringMaybeQuoted(),
),
)
}
func FromTypeErrorBinary(funcname string, v, input2 *Mlrval) *Mlrval {
return FromError(
fmt.Errorf(
"%s: unacceptable types %s, %s with values %s, %s",
funcname,
v.GetTypeName(),
input2.GetTypeName(),
v.StringMaybeQuoted(),
input2.StringMaybeQuoted(),
),
)
}
func FromTypeErrorTernary(funcname string, v, input2, input3 *Mlrval) *Mlrval {
return FromError(
fmt.Errorf(
"%s: unacceptable types %s, %s, %s with values %s, %s, %s",
funcname,
v.GetTypeName(),
input2.GetTypeName(),
input3.GetTypeName(),
v.StringMaybeQuoted(),
input2.StringMaybeQuoted(),
input3.StringMaybeQuoted(),
),
)
}
func FromNotStringError(funcname string, v *Mlrval) *Mlrval {
return FromNotNamedTypeError(funcname, v, "string")
}
func FromNotBooleanError(funcname string, v *Mlrval) *Mlrval {
return FromNotNamedTypeError(funcname, v, "boolean")
}
func FromNotIntError(funcname string, v *Mlrval) *Mlrval {
return FromNotNamedTypeError(funcname, v, "int")
}
func FromNotNumericError(funcname string, v *Mlrval) *Mlrval {
return FromNotNamedTypeError(funcname, v, "int or float")
}
func FromNotArrayError(funcname string, v *Mlrval) *Mlrval {
return FromNotNamedTypeError(funcname, v, "array")
}
func FromNotMapError(funcname string, v *Mlrval) *Mlrval {
return FromNotNamedTypeError(funcname, v, "map")
}
func FromNotCollectionError(funcname string, v *Mlrval) *Mlrval {
return FromNotNamedTypeError(funcname, v, "array or map")
}
func FromNotFunctionError(funcname string, v *Mlrval) *Mlrval {
return FromNotNamedTypeError(funcname, v, "function")
}
func FromNotNamedTypeError(funcname string, v *Mlrval, expected_type_name string) *Mlrval {
return FromError(
fmt.Errorf(
"%s: unacceptable value %s with type %s; needed type %s",
funcname,
v.StringMaybeQuoted(),
v.GetTypeName(),
expected_type_name,
),
)
}
// TODO: comment non-JIT context like mlr put -s.
// TODO: comment re inferBool.
func FromInferredType(input string) *Mlrval {
mv := &Mlrval{
mvtype: MT_PENDING,
printrep: input,
printrepValid: true,
}
// TODO: comment re data files vs literals context -- this is for the latter
if input == "true" {
return TRUE
} else if input == "false" {
return FALSE
} else {
packageLevelInferrer(mv)
return mv
}
}
func FromString(input string) *Mlrval {
if input == "" {
return VOID
}
return &Mlrval{
mvtype: MT_STRING,
printrep: input,
printrepValid: true,
}
}
func (mv *Mlrval) SetFromString(input string) *Mlrval {
mv.printrep = input
mv.printrepValid = true
if input == "" {
mv.mvtype = MT_VOID
} else {
mv.mvtype = MT_STRING
}
return mv
}
func (mv *Mlrval) SetFromVoid() *Mlrval {
mv.printrep = ""
mv.printrepValid = true
mv.mvtype = MT_VOID
return mv
}
func FromInt(input int64) *Mlrval {
return &Mlrval{
mvtype: MT_INT,
printrepValid: false,
intf: input,
}
}
func FromIntShowingOctal(input int64) *Mlrval {
return &Mlrval{
mvtype: MT_INT,
printrepValid: true,
printrep: fmt.Sprintf("0%o", input),
intf: input,
}
}
// TryFromIntString is used by the mlrval Formatter (fmtnum DSL function,
// format-values verb, etc). Each mlrval has printrep and a printrepValid for
// its original string, then a type-code like MT_INT or MT_FLOAT, and
// type-specific storage like intval or floatval.
//
// If the user has taken a mlrval with original string "314" and formatted it
// with "0x%04x" then its printrep will be "0x013a" but its type should still
// be MT_INT.
//
// If on the other hand the user has formatted the same mlrval with
// "[[%0x04x]]" then its printrep will be "[[0x013a]]" and it will be
// MT_STRING. This function supports that.
func TryFromIntString(input string) *Mlrval {
intval, ok := lib.TryIntFromString(input)
if ok {
return FromPrevalidatedIntString(input, intval)
} else {
return FromString(input)
}
}
// TODO: comment
func (mv *Mlrval) SetFromPrevalidatedIntString(input string, intval int64) *Mlrval {
mv.printrep = input
mv.printrepValid = true
mv.intf = intval
mv.mvtype = MT_INT
return mv
}
// TODO: comment
func FromPrevalidatedIntString(input string, intval int64) *Mlrval {
mv := &Mlrval{}
mv.SetFromPrevalidatedIntString(input, intval)
return mv
}
func FromFloat(input float64) *Mlrval {
return &Mlrval{
mvtype: MT_FLOAT,
printrepValid: false,
intf: input,
}
}
// TryFromFloatString is used by the mlrval Formatter (fmtnum DSL function,
// format-values verb, etc). Each mlrval has printrep and a printrepValid for
// its original string, then a type-code like MT_INT or MT_FLOAT, and
// type-specific storage like intval or floatval.
//
// If the user has taken a mlrval with original string "3.14" and formatted it
// with "%.4f" then its printrep will be "3.1400" but its type should still be
// MT_FLOAT.
//
// If on the other hand the user has formatted the same mlrval with "[[%.4f]]"
// then its printrep will be "[[3.1400]]" and it will be MT_STRING. This
// function supports that.
func TryFromFloatString(input string) *Mlrval {
floatval, ok := lib.TryFloatFromString(input)
if ok {
return FromPrevalidatedFloatString(input, floatval)
} else {
return FromString(input)
}
}
// TODO: comment
func (mv *Mlrval) SetFromPrevalidatedFloatString(input string, floatval float64) *Mlrval {
mv.printrep = input
mv.printrepValid = true
mv.intf = floatval
mv.mvtype = MT_FLOAT
return mv
}
// TODO: comment
func FromPrevalidatedFloatString(input string, floatval float64) *Mlrval {
mv := &Mlrval{}
mv.SetFromPrevalidatedFloatString(input, floatval)
return mv
}
func FromBool(input bool) *Mlrval {
if input {
return TRUE
} else {
return FALSE
}
}
func FromBoolString(input string) *Mlrval {
if input == "true" {
return TRUE
} else if input == "false" {
return FALSE
} else {
lib.InternalCodingErrorIf(true)
return nil // not reached
}
}
// TODO: comment
func (mv *Mlrval) SetFromPrevalidatedBoolString(input string, boolval bool) *Mlrval {
mv.printrep = input
mv.printrepValid = true
mv.intf = boolval
mv.mvtype = MT_BOOL
return mv
}
// The user-defined function is of type 'interface{}' here to avoid what would
// otherwise be a package-dependency cycle between this package and
// github.com/johnkerl/miller/v6/pkg/dsl/cst.
//
// Nominally the name argument is the user-specified name if `func f(a, b) {
// ... }`, or some autogenerated UUID like `fl0052` if `func (a, b) { ... }`.
func FromFunction(funcval interface{}, name string) *Mlrval {
return &Mlrval{
mvtype: MT_FUNC,
printrep: name,
printrepValid: true,
intf: funcval,
}
}
func FromArray(arrayval []*Mlrval) *Mlrval {
return &Mlrval{
mvtype: MT_ARRAY,
printrep: "(bug-if-you-see-this:case-4)", // INVALID_PRINTREP,
printrepValid: false,
intf: CopyMlrvalArray(arrayval),
}
}
func FromSingletonArray(element *Mlrval) *Mlrval {
a := make([]*Mlrval, 1)
a[0] = element
return FromArray(a)
}
func FromEmptyArray() *Mlrval {
return FromArray(make([]*Mlrval, 0))
}
func FromMap(mapval *Mlrmap) *Mlrval {
return &Mlrval{
mvtype: MT_MAP,
printrep: "(bug-if-you-see-this:case-5)", // INVALID_PRINTREP,
printrepValid: false,
intf: mapval.Copy(),
}
}
func FromEmptyMap() *Mlrval {
return FromMap(NewMlrmap())
}