mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-17 16:38:54 +00:00
* plans/lintfixes.md * plans/lintfixes.md * Fix remaining govet lint findings - Rename MarshalJSON -> FormatAsJSON on Mlrval and Mlrmap (govet stdmethods): the methods shadowed json.Marshaler with an incompatible signature. - Remove unreachable return after exhaustive if-else in pkg/mlrval/mlrval_collections.go (govet unreachable). - Update plans/lintfixes.md with current status: 84 findings remain (50 errcheck, 34 staticcheck). Part of #2109. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Return nil on successful single-index array unset removeIndexedOnArray removed the element on the in-bounds path but then fell through to return an "array index out of bounds for unset" error, so the success path never returned nil. Callers currently ignore the error, which masked this; return nil on success so that upcoming errcheck fixes can propagate the error meaningfully. This matches removeIndexedOnMap, which returns nil on success. Add unit tests for RemoveIndexed on arrays. Part of #2109. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
141 lines
4.1 KiB
Go
141 lines
4.1 KiB
Go
package mlrval
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"strconv"
|
|
)
|
|
|
|
// Must have non-pointer receiver in order to implement the fmt.Stringer
|
|
// interface to make this printable via fmt.Println et al. However, that
|
|
// results in a needless copy of the Mlrval. So, we intentionally use pointer
|
|
// receiver, and if we need to print to stdout, we can fmt.Printf with "%s" and
|
|
// mv.String().
|
|
func (mv *Mlrval) String() string {
|
|
// TODO: comment re deferral -- important perf effect!
|
|
// if mv.IsFloat() && floatOutputFormatter != nil
|
|
// if mv.mvtype == MT_FLOAT && floatOutputFormatter != nil {
|
|
//if floatOutputFormatter != nil && (mv.mvtype == MT_FLOAT || mv.mvtype == MT_PENDING) {
|
|
if floatOutputFormatter != nil && mv.Type() == MT_FLOAT {
|
|
// Use the format string from global --ofmt, if supplied
|
|
return floatOutputFormatter.FormatFloat(mv.intf.(float64))
|
|
}
|
|
|
|
// TODO: track dirty-flag checking / somesuch.
|
|
// At present it's cumbersome to check if an array or map has been modified
|
|
// and it's safest to always recompute the string-rep.
|
|
if mv.IsArrayOrMap() {
|
|
mv.printrepValid = false
|
|
}
|
|
|
|
mv.setPrintRep()
|
|
return mv.printrep
|
|
}
|
|
|
|
// OriginalString gets the field value as a string regardless of --ofmt specification.
|
|
// E.g if the ofmt is "%.4f" and input is 3.1415926535, OriginalString() will return
|
|
// "3.1415926535" while String() will return "3.1416".
|
|
func (mv *Mlrval) OriginalString() string {
|
|
if mv.printrepValid {
|
|
return mv.printrep
|
|
}
|
|
return mv.String()
|
|
}
|
|
|
|
// StringMaybeQuoted Returns strings double-quoted; all else not.
|
|
func (mv *Mlrval) StringMaybeQuoted() string {
|
|
output := mv.String()
|
|
if mv.mvtype == MT_VOID || mv.mvtype == MT_STRING {
|
|
return `"` + output + `"`
|
|
}
|
|
return output
|
|
}
|
|
|
|
// See mlrval.go for more about JIT-formatting of string backings
|
|
func (mv *Mlrval) setPrintRep() {
|
|
if !mv.printrepValid {
|
|
switch mv.mvtype {
|
|
|
|
case MT_PENDING:
|
|
// Should not have gotten outside of the JSON decoder, so flag this
|
|
// clearly visually if it should (buggily) slip through to
|
|
// user-level visibility.
|
|
mv.printrep = "(bug-if-you-see-this:case=3)" // xxx constdef at top of file
|
|
|
|
case MT_ERROR:
|
|
mv.printrep = "(error)" // xxx constdef at top of file
|
|
|
|
case MT_ABSENT:
|
|
// Callsites should be using absence to do non-assigns, so flag
|
|
// this clearly visually if it should (buggily) slip through to
|
|
// user-level visibility.
|
|
mv.printrep = "(bug-if-you-see-this:case=4)" // xxx constdef at top of file
|
|
|
|
case MT_VOID:
|
|
mv.printrep = "" // xxx constdef at top of file
|
|
|
|
case MT_STRING:
|
|
break
|
|
|
|
case MT_INT:
|
|
mv.printrep = strconv.FormatInt(mv.intf.(int64), 10)
|
|
|
|
case MT_FLOAT:
|
|
mv.printrep = strconv.FormatFloat(mv.intf.(float64), 'f', -1, 64)
|
|
|
|
case MT_BOOL:
|
|
if mv.intf.(bool) {
|
|
mv.printrep = "true"
|
|
} else {
|
|
mv.printrep = "false"
|
|
}
|
|
|
|
case MT_ARRAY:
|
|
bytes, err := mv.FormatAsJSON(JSON_MULTILINE, false)
|
|
// maybe just InternalCodingErrorIf(err != nil)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "mlr: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
mv.printrep = string(bytes)
|
|
|
|
case MT_MAP:
|
|
bytes, err := mv.FormatAsJSON(JSON_MULTILINE, false)
|
|
// maybe just InternalCodingErrorIf(err != nil)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "mlr: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
mv.printrep = string(bytes)
|
|
}
|
|
mv.printrepValid = true
|
|
}
|
|
}
|
|
|
|
// StringifyValuesRecursively is nominally for the `--jvquoteall` flag.
|
|
func (mv *Mlrval) StringifyValuesRecursively() {
|
|
switch mv.mvtype {
|
|
|
|
case MT_ARRAY:
|
|
for i := range mv.intf.([]*Mlrval) {
|
|
mv.intf.([]*Mlrval)[i].StringifyValuesRecursively()
|
|
}
|
|
|
|
case MT_MAP:
|
|
for pe := mv.intf.(*Mlrmap).Head; pe != nil; pe = pe.Next {
|
|
pe.Value.StringifyValuesRecursively()
|
|
}
|
|
|
|
default:
|
|
mv.SetFromString(mv.String())
|
|
}
|
|
}
|
|
|
|
func (mv *Mlrval) ShowSizes() {
|
|
fmt.Printf("TOTAL %p %d\n", mv, reflect.TypeFor[Mlrval]().Size())
|
|
//fmt.Printf("mv.intf %p %d\n", &mv.intf, reflect.TypeOf(mv.intf).Size())
|
|
fmt.Printf("mv.printrep %p %d\n", &mv.printrep, reflect.TypeFor[string]().Size())
|
|
fmt.Printf("mv.printrepValid %p %d\n", &mv.printrepValid, reflect.TypeFor[bool]().Size())
|
|
fmt.Printf("mv.mvtype %p %d\n", &mv.mvtype, reflect.TypeFor[MVType]().Size())
|
|
}
|