Convert mlrval polymorphism from struct to unionish interface (#1133)

* Convert mlrval polymorphism from struct to unionish interface: arrayval/mapval/funcval

* Convert mlrval polymorphism from struct to unionish interface:: boolval

* Convert mlrval polymorphism from struct to unionish interface:: floatval

* Convert mlrval polymorphism from struct to unionish interface:: intval
This commit is contained in:
John Kerl 2022-11-26 20:55:21 -05:00 committed by GitHub
parent 36f3c3cb0f
commit b6846fcd0f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 150 additions and 159 deletions

View file

@ -2,7 +2,9 @@
// Experiments for type-inference performance optimization
// ================================================================
// go build github.com/johnkerl/miller/cmd/sizes
/*
go build github.com/johnkerl/miller/cmd/sizes
*/
package main

View file

@ -339,7 +339,7 @@ func (mlrmap *Mlrmap) getWithMlrvalArrayIndex(index *Mlrval) (*Mlrval, error) {
current := mlrmap
var retval *Mlrval = nil
lib.InternalCodingErrorIf(!index.IsArray())
array := index.x.arrayval
array := index.intf.([]*Mlrval)
n := len(array)
for i, piece := range array {
next, err := current.GetWithMlrvalIndex(piece)
@ -350,7 +350,7 @@ func (mlrmap *Mlrmap) getWithMlrvalArrayIndex(index *Mlrval) (*Mlrval, error) {
if !next.IsMap() {
return nil, fmt.Errorf("mlr: cannot multi-index non-map.")
}
current = next.x.mapval
current = next.intf.(*Mlrmap)
} else {
retval = next.Copy()
}
@ -782,11 +782,11 @@ func (mlrmap *Mlrmap) SortByKeyRecursively() {
for _, key := range keys {
// Old record will be GC'ed: just move pointers
value := mlrmap.Get(key)
if value.IsMap() {
value.x.mapval.SortByKeyRecursively()
val := mlrmap.Get(key)
if val.IsMap() {
val.intf.(*Mlrmap).SortByKeyRecursively()
}
other.PutReference(key, value)
other.PutReference(key, val)
}
*mlrmap = *other

View file

@ -137,13 +137,14 @@ func (mlrmap *Mlrmap) CopyUnflattened(
// Is the field name something dot something?
if strings.Contains(pe.Key, separator) {
arrayOfIndices := SplitAXHelper(pe.Key, separator)
lib.InternalCodingErrorIf(len(arrayOfIndices.x.arrayval) < 1)
arrayval := arrayOfIndices.intf.([]*Mlrval)
lib.InternalCodingErrorIf(len(arrayval) < 1)
// If the input field name was "x.a" then remember the "x".
baseIndex := arrayOfIndices.x.arrayval[0].String()
baseIndex := arrayval[0].String()
affectedBaseIndices[baseIndex] = true
// Use PutIndexed to assign $x["a"] = 7, or $x["b"] = 8, etc.
other.PutIndexed(
CopyMlrvalArray(arrayOfIndices.x.arrayval),
CopyMlrvalArray(arrayval),
unflattenTerminal(pe.Value).Copy(),
)
} else {
@ -187,13 +188,14 @@ func (mlrmap *Mlrmap) CopyUnflattenFields(
// Is the field name something dot something?
if strings.Contains(pe.Key, separator) {
arrayOfIndices := SplitAXHelper(pe.Key, separator)
lib.InternalCodingErrorIf(len(arrayOfIndices.x.arrayval) < 1)
arrayval := arrayOfIndices.intf.([]*Mlrval)
lib.InternalCodingErrorIf(len(arrayval) < 1)
// If the input field name was "x.a" then remember the "x".
baseIndex := arrayOfIndices.x.arrayval[0].String()
baseIndex := arrayval[0].String()
if fieldNameSet[baseIndex] {
// Use PutIndexed to assign $x["a"] = 7, or $x["b"] = 8, etc.
other.PutIndexed(
CopyMlrvalArray(arrayOfIndices.x.arrayval),
CopyMlrvalArray(arrayval),
unflattenTerminal(pe.Value).Copy(),
)
affectedBaseIndices[baseIndex] = true
@ -247,7 +249,7 @@ func SplitAXHelper(input string, separator string) *Mlrval {
output := FromArray(make([]*Mlrval, len(fields)))
for i, field := range fields {
output.x.arrayval[i] = FromString(field)
output.intf.([]*Mlrval)[i] = FromString(field)
}
return output

View file

@ -8,7 +8,7 @@ import (
func (mv *Mlrval) GetArrayLength() (int, bool) {
if mv.IsArray() {
return len(mv.x.arrayval), true
return len(mv.intf.([]*Mlrval)), true
} else {
return -999, false
}
@ -35,13 +35,13 @@ func (mv *Mlrval) FlattenToMap(prefix string, delimiter string) Mlrval {
if mv.IsMap() {
// Without this, the for-loop below is zero-pass and fields with "{}"
// values would disappear entirely in a JSON-to-CSV conversion.
if mv.x.mapval.IsEmpty() {
if mv.intf.(*Mlrmap).IsEmpty() {
if prefix != "" {
retval.PutCopy(prefix, FromString("{}"))
}
}
for pe := mv.x.mapval.Head; pe != nil; pe = pe.Next {
for pe := mv.intf.(*Mlrmap).Head; pe != nil; pe = pe.Next {
nextPrefix := pe.Key
if prefix != "" {
nextPrefix = prefix + delimiter + nextPrefix
@ -49,7 +49,7 @@ func (mv *Mlrval) FlattenToMap(prefix string, delimiter string) Mlrval {
if pe.Value.IsMap() || pe.Value.IsArray() {
nextResult := pe.Value.FlattenToMap(nextPrefix, delimiter)
lib.InternalCodingErrorIf(nextResult.mvtype != MT_MAP)
for pf := nextResult.x.mapval.Head; pf != nil; pf = pf.Next {
for pf := nextResult.intf.(*Mlrmap).Head; pf != nil; pf = pf.Next {
retval.PutCopy(pf.Key, pf.Value.Copy())
}
} else {
@ -60,13 +60,13 @@ func (mv *Mlrval) FlattenToMap(prefix string, delimiter string) Mlrval {
} else if mv.IsArray() {
// Without this, the for-loop below is zero-pass and fields with "[]"
// values would disappear entirely in a JSON-to-CSV conversion.
if len(mv.x.arrayval) == 0 {
if len(mv.intf.([]*Mlrval)) == 0 {
if prefix != "" {
retval.PutCopy(prefix, FromString("[]"))
}
}
for zindex, value := range mv.x.arrayval {
for zindex, value := range mv.intf.([]*Mlrval) {
nextPrefix := strconv.Itoa(zindex + 1) // Miller user-space indices are 1-up
if prefix != "" {
nextPrefix = prefix + delimiter + nextPrefix
@ -74,7 +74,7 @@ func (mv *Mlrval) FlattenToMap(prefix string, delimiter string) Mlrval {
if value.IsMap() || value.IsArray() {
nextResult := value.FlattenToMap(nextPrefix, delimiter)
lib.InternalCodingErrorIf(nextResult.mvtype != MT_MAP)
for pf := nextResult.x.mapval.Head; pf != nil; pf = pf.Next {
for pf := nextResult.intf.(*Mlrmap).Head; pf != nil; pf = pf.Next {
retval.PutCopy(pf.Key, pf.Value.Copy())
}
} else {
@ -92,8 +92,8 @@ func (mv *Mlrval) FlattenToMap(prefix string, delimiter string) Mlrval {
// Increment is used by stats1.
func (mv *Mlrval) Increment() {
if mv.mvtype == MT_INT {
mv.intval++
mv.intf = mv.intf.(int64) + 1
} else if mv.mvtype == MT_FLOAT {
mv.floatval++
mv.intf = mv.intf.(float64) + 1.0
}
}

View file

@ -107,19 +107,19 @@ func cmp_b_ss(input1, input2 *Mlrval) int {
return string_cmp(input1.printrep, input2.printrep)
}
func cmp_b_ii(input1, input2 *Mlrval) int {
return int_cmp(input1.intval, input2.intval)
return int_cmp(input1.intf.(int64), input2.intf.(int64))
}
func cmp_b_if(input1, input2 *Mlrval) int {
return float_cmp(float64(input1.intval), input2.floatval)
return float_cmp(float64(input1.intf.(int64)), input2.intf.(float64))
}
func cmp_b_fi(input1, input2 *Mlrval) int {
return float_cmp(input1.floatval, float64(input2.intval))
return float_cmp(input1.intf.(float64), float64(input2.intf.(int64)))
}
func cmp_b_ff(input1, input2 *Mlrval) int {
return float_cmp(input1.floatval, input2.floatval)
return float_cmp(input1.intf.(float64), input2.intf.(float64))
}
func cmp_b_bb(input1, input2 *Mlrval) int {
return int_cmp(int64(lib.BoolToInt(input1.boolval)), int64(lib.BoolToInt(input2.boolval)))
return int_cmp(int64(lib.BoolToInt(input1.intf.(bool))), int64(lib.BoolToInt(input2.intf.(bool))))
}
// TODO: cmp on array & map

View file

@ -86,7 +86,8 @@ func (mv *Mlrval) ArrayGet(mindex *Mlrval) Mlrval {
if !mindex.IsInt() {
return *ERROR
}
value := arrayGetAliased(&mv.x.arrayval, int(mindex.intval))
arrayval := mv.intf.([]*Mlrval)
value := arrayGetAliased(&arrayval, int(mindex.intf.(int64)))
if value == nil {
return *ABSENT
} else {
@ -116,15 +117,17 @@ func (mv *Mlrval) ArrayPut(mindex *Mlrval, value *Mlrval) {
os.Exit(1)
}
ok := arrayPutAliased(&mv.x.arrayval, int(mindex.intval), value)
arrayval := mv.intf.([]*Mlrval)
ok := arrayPutAliased(&arrayval, int(mindex.intf.(int64)), value)
if !ok {
fmt.Fprintf(
os.Stderr,
"mlr: array index %d out of bounds %d..%d\n",
mindex.intval, 1, len(mv.x.arrayval),
mindex.intf.(int64), 1, len(arrayval),
)
os.Exit(1)
}
mv.intf = arrayval
}
// ----------------------------------------------------------------
@ -213,7 +216,8 @@ func (mv *Mlrval) ArrayAppend(value *Mlrval) {
// Silent no-ops are not good UX ...
return
}
mv.x.arrayval = append(mv.x.arrayval, value)
mv.intf = append(mv.intf.([]*Mlrval), value)
}
// ================================================================
@ -222,7 +226,7 @@ func (mv *Mlrval) MapGet(key *Mlrval) Mlrval {
return *ERROR
}
mval, err := mv.x.mapval.GetWithMlrvalIndex(key)
mval, err := mv.intf.(*Mlrmap).GetWithMlrvalIndex(key)
if err != nil { // xxx maybe error-return in the API
return *ERROR
}
@ -243,9 +247,9 @@ func (mv *Mlrval) MapPut(key *Mlrval, value *Mlrval) {
}
if key.IsString() {
mv.x.mapval.PutCopy(key.printrep, value)
mv.intf.(*Mlrmap).PutCopy(key.printrep, value)
} else if key.IsInt() {
mv.x.mapval.PutCopy(key.String(), value)
mv.intf.(*Mlrmap).PutCopy(key.String(), value)
}
// TODO: need to be careful about semantics here.
// Silent no-ops are not good UX ...
@ -291,19 +295,25 @@ func (mv *Mlrval) PutIndexed(indices []*Mlrval, rvalue *Mlrval) error {
lib.InternalCodingErrorIf(len(indices) < 1)
if mv.IsMap() {
return putIndexedOnMap(mv.x.mapval, indices, rvalue)
return putIndexedOnMap(mv.intf.(*Mlrmap), indices, rvalue)
} else if mv.IsArray() {
return putIndexedOnArray(&mv.x.arrayval, indices, rvalue)
arrayval := mv.intf.([]*Mlrval)
retval := putIndexedOnArray(&arrayval, indices, rvalue)
mv.intf = arrayval
return retval
} else {
baseIndex := indices[0]
if baseIndex.IsString() {
*mv = *FromEmptyMap()
return putIndexedOnMap(mv.x.mapval, indices, rvalue)
return putIndexedOnMap(mv.intf.(*Mlrmap), indices, rvalue)
} else if baseIndex.IsInt() {
*mv = *FromEmptyArray()
return putIndexedOnArray(&mv.x.arrayval, indices, rvalue)
arrayval := mv.intf.([]*Mlrval)
retval := putIndexedOnArray(&arrayval, indices, rvalue)
mv.intf = arrayval
return retval
} else {
return errors.New(
"mlr: only maps and arrays are indexable; got " + mv.GetTypeName(),
@ -326,7 +336,7 @@ func putIndexedOnMap(baseMap *Mlrmap, indices []*Mlrval, rvalue *Mlrval) error {
".",
)
}
*baseMap = *rvalue.x.mapval.Copy()
*baseMap = *rvalue.intf.(*Mlrmap).Copy()
return nil
}
@ -379,21 +389,21 @@ func putIndexedOnArray(
".",
)
}
zindex, inBounds := UnaliasArrayIndex(baseArray, int(mindex.intval))
zindex, inBounds := UnaliasArrayIndex(baseArray, int(mindex.intf.(int64)))
if numIndices == 1 {
// If last index, then assign.
if inBounds {
(*baseArray)[zindex] = rvalue.Copy()
} else if mindex.intval == 0 {
} else if mindex.intf.(int64) == 0 {
return errors.New("mlr: zero indices are not supported. Indices are 1-up.")
} else if mindex.intval < 0 {
} else if mindex.intf.(int64) < 0 {
return errors.New("mlr: Cannot use negative indices to auto-lengthen arrays.")
} else {
// Array is [a,b,c] with mindices 1,2,3. Length is 3. Zindices are 0,1,2.
// Given mindex is 4.
LengthenMlrvalArray(baseArray, int(mindex.intval))
zindex := mindex.intval - 1
LengthenMlrvalArray(baseArray, int(mindex.intf.(int64)))
zindex := mindex.intf.(int64) - 1
(*baseArray)[zindex] = rvalue.Copy()
}
return nil
@ -420,14 +430,14 @@ func putIndexedOnArray(
return (*baseArray)[zindex].PutIndexed(indices[1:], rvalue)
} else if mindex.intval == 0 {
} else if mindex.intf.(int64) == 0 {
return errors.New("mlr: zero indices are not supported. Indices are 1-up.")
} else if mindex.intval < 0 {
} else if mindex.intf.(int64) < 0 {
return errors.New("mlr: Cannot use negative indices to auto-lengthen arrays.")
} else {
// Already allocated but needs to be longer
LengthenMlrvalArray(baseArray, int(mindex.intval))
zindex := mindex.intval - 1
LengthenMlrvalArray(baseArray, int(mindex.intf.(int64)))
zindex := mindex.intf.(int64) - 1
return (*baseArray)[zindex].PutIndexed(indices[1:], rvalue)
}
}
@ -438,10 +448,13 @@ func (mv *Mlrval) RemoveIndexed(indices []*Mlrval) error {
lib.InternalCodingErrorIf(len(indices) < 1)
if mv.IsMap() {
return removeIndexedOnMap(mv.x.mapval, indices)
return removeIndexedOnMap(mv.intf.(*Mlrmap), indices)
} else if mv.IsArray() {
return removeIndexedOnArray(&mv.x.arrayval, indices)
arrayval := mv.intf.([]*Mlrval)
retval := removeIndexedOnArray(&arrayval, indices)
mv.intf = arrayval
return retval
} else {
return errors.New(
@ -505,7 +518,7 @@ func removeIndexedOnArray(
".",
)
}
zindex, inBounds := UnaliasArrayIndex(baseArray, int(mindex.intval))
zindex, inBounds := UnaliasArrayIndex(baseArray, int(mindex.intf.(int64)))
// If last index, then unset.
if numIndices == 1 {
@ -513,7 +526,7 @@ func removeIndexedOnArray(
leftSlice := (*baseArray)[0:zindex]
rightSlice := (*baseArray)[zindex+1 : len((*baseArray))]
*baseArray = append(leftSlice, rightSlice...)
} else if mindex.intval == 0 {
} else if mindex.intf.(int64) == 0 {
return errors.New("mlr: zero indices are not supported. Indices are 1-up.")
} else {
// TODO: improve wording
@ -523,7 +536,7 @@ func removeIndexedOnArray(
// More indices remain; recurse
if inBounds {
return (*baseArray)[zindex].RemoveIndexed(indices[1:])
} else if mindex.intval == 0 {
} else if mindex.intf.(int64) == 0 {
return errors.New("mlr: zero indices are not supported. Indices are 1-up.")
} else {
// TODO: improve wording
@ -659,13 +672,13 @@ func NewMlrvalForAutoDeepen(mvtype MVType) (*Mlrval, error) {
func (mv *Mlrval) Arrayify() *Mlrval {
if mv.IsMap() {
if mv.x.mapval.IsEmpty() {
if mv.intf.(*Mlrmap).IsEmpty() {
return mv
}
convertible := true
i := 0
for pe := mv.x.mapval.Head; pe != nil; pe = pe.Next {
for pe := mv.intf.(*Mlrmap).Head; pe != nil; pe = pe.Next {
sval := strconv.Itoa(i + 1) // Miller user-space indices are 1-up
i++
if pe.Key != sval {
@ -675,9 +688,9 @@ func (mv *Mlrval) Arrayify() *Mlrval {
}
if convertible {
arrayval := make([]*Mlrval, mv.x.mapval.FieldCount)
arrayval := make([]*Mlrval, mv.intf.(*Mlrmap).FieldCount)
i := 0
for pe := mv.x.mapval.Head; pe != nil; pe = pe.Next {
for pe := mv.intf.(*Mlrmap).Head; pe != nil; pe = pe.Next {
arrayval[i] = pe.Value.Copy()
i++
}
@ -690,9 +703,11 @@ func (mv *Mlrval) Arrayify() *Mlrval {
} else if mv.IsArray() {
// TODO: comment (or rethink) that this modifies its inputs!!
output := mv.Copy()
for i := range mv.x.arrayval {
output.x.arrayval[i] = output.x.arrayval[i].Arrayify()
arrayval := mv.intf.([]*Mlrval)
for i := range arrayval {
arrayval[i] = arrayval[i].Arrayify()
}
mv.intf = arrayval
return output
} else {

View file

@ -25,13 +25,14 @@ var TRUE = &Mlrval{
mvtype: MT_BOOL,
printrep: "true",
printrepValid: true,
boolval: true,
intf: true,
}
var FALSE = &Mlrval{
mvtype: MT_BOOL,
printrep: "false",
printrepValid: true,
intf: false,
}
var VOID = &Mlrval{
@ -63,19 +64,19 @@ var MINUS_ONE = &Mlrval{
mvtype: MT_INT,
printrep: "-1",
printrepValid: true,
intval: -1,
intf: int64(-1),
}
var ZERO = &Mlrval{
mvtype: MT_INT,
printrep: "0",
printrepValid: true,
intval: 0,
intf: int64(0),
}
var ONE = &Mlrval{
mvtype: MT_INT,
printrep: "1",
printrepValid: true,
intval: 1,
intf: int64(1),
}

View file

@ -4,17 +4,9 @@ package mlrval
func (mv *Mlrval) Copy() *Mlrval {
other := *mv
if mv.mvtype == MT_MAP {
other.x = &mlrvalExtended{
mapval: mv.x.mapval.Copy(),
}
other.intf = mv.intf.(*Mlrmap).Copy()
} else if mv.mvtype == MT_ARRAY {
other.x = &mlrvalExtended{
arrayval: CopyMlrvalArray(mv.x.arrayval),
}
} else if mv.mvtype == MT_FUNC {
other.x = &mlrvalExtended{
funcval: mv.x.funcval,
}
other.intf = CopyMlrvalArray(mv.intf.([]*Mlrval))
}
return &other
}

View file

@ -25,7 +25,7 @@ func (mv *Mlrval) GetStringValue() (stringValue string, isString bool) {
func (mv *Mlrval) GetIntValue() (intValue int64, isInt bool) {
if mv.Type() == MT_INT {
return mv.intval, true
return mv.intf.(int64), true
} else {
return -999, false
}
@ -33,7 +33,7 @@ func (mv *Mlrval) GetIntValue() (intValue int64, isInt bool) {
func (mv *Mlrval) GetFloatValue() (floatValue float64, isFloat bool) {
if mv.Type() == MT_FLOAT {
return mv.floatval, true
return mv.intf.(float64), true
} else {
return -777.0, false
}
@ -41,9 +41,9 @@ func (mv *Mlrval) GetFloatValue() (floatValue float64, isFloat bool) {
func (mv *Mlrval) GetNumericToFloatValue() (floatValue float64, isFloat bool) {
if mv.Type() == MT_FLOAT {
return mv.floatval, true
return mv.intf.(float64), true
} else if mv.Type() == MT_INT {
return float64(mv.intval), true
return float64(mv.intf.(int64)), true
} else {
return -888.0, false
}
@ -57,7 +57,7 @@ func (mv *Mlrval) GetNumericNegativeorDie() bool {
func (mv *Mlrval) GetBoolValue() (boolValue bool, isBool bool) {
if mv.Type() == MT_BOOL {
return mv.boolval, true
return mv.intf.(bool), true
} else {
return false, false
}
@ -65,7 +65,7 @@ func (mv *Mlrval) GetBoolValue() (boolValue bool, isBool bool) {
func (mv *Mlrval) GetArray() []*Mlrval {
if mv.IsArray() {
return mv.x.arrayval
return mv.intf.([]*Mlrval)
} else {
return nil
}
@ -73,7 +73,7 @@ func (mv *Mlrval) GetArray() []*Mlrval {
func (mv *Mlrval) GetMap() *Mlrmap {
if mv.IsMap() {
return mv.x.mapval
return mv.intf.(*Mlrmap)
} else {
return nil
}
@ -81,7 +81,7 @@ func (mv *Mlrval) GetMap() *Mlrmap {
func (mv *Mlrval) GetFunction() interface{} {
if mv.Type() == MT_FUNC {
return mv.x.funcval
return mv.intf
} else {
return nil
}
@ -107,27 +107,27 @@ func (mv *Mlrval) AcquireStringValue() string {
func (mv *Mlrval) AcquireIntValue() int64 {
lib.InternalCodingErrorIf(mv.mvtype != MT_INT)
return mv.intval
return mv.intf.(int64)
}
func (mv *Mlrval) AcquireFloatValue() float64 {
lib.InternalCodingErrorIf(mv.mvtype != MT_FLOAT)
return mv.floatval
return mv.intf.(float64)
}
func (mv *Mlrval) AcquireBoolValue() bool {
lib.InternalCodingErrorIf(mv.mvtype != MT_BOOL)
return mv.boolval
return mv.intf.(bool)
}
func (mv *Mlrval) AcquireArrayValue() []*Mlrval {
lib.InternalCodingErrorIf(mv.mvtype != MT_ARRAY)
return mv.x.arrayval
return mv.intf.([]*Mlrval)
}
func (mv *Mlrval) AcquireMapValue() *Mlrmap {
lib.InternalCodingErrorIf(mv.mvtype != MT_MAP)
return mv.x.mapval
return mv.intf.(*Mlrmap)
}
func (mv *Mlrval) GetNumericToFloatValueOrDie() (floatValue float64) {

View file

@ -61,7 +61,7 @@ func inferWithOctalAsInt(mv *Mlrval) *Mlrval {
func inferWithIntAsFloat(mv *Mlrval) *Mlrval {
inferNormally(mv)
if mv.Type() == MT_INT {
mv.floatval = float64(mv.intval)
mv.intf = float64(mv.intf.(int64))
mv.mvtype = MT_FLOAT
}
return mv

View file

@ -96,7 +96,7 @@ func (mv *Mlrval) IsNumeric() bool {
}
func (mv *Mlrval) IsIntZero() bool {
return mv.Type() == MT_INT && mv.intval == 0
return mv.Type() == MT_INT && mv.intf.(int64) == 0
}
func (mv *Mlrval) IsBool() bool {
@ -104,10 +104,10 @@ func (mv *Mlrval) IsBool() bool {
}
func (mv *Mlrval) IsTrue() bool {
return mv.Type() == MT_BOOL && mv.boolval == true
return mv.Type() == MT_BOOL && mv.intf.(bool) == true
}
func (mv *Mlrval) IsFalse() bool {
return mv.Type() == MT_BOOL && mv.boolval == false
return mv.Type() == MT_BOOL && mv.intf.(bool) == false
}
func (mv *Mlrval) IsArray() bool {

View file

@ -411,7 +411,7 @@ func (mv *Mlrval) marshalJSONArray(
// TODO: libify
allTerminal := true
for _, element := range mv.x.arrayval {
for _, element := range mv.intf.([]*Mlrval) {
if element.IsArrayOrMap() {
allTerminal = false
break
@ -429,11 +429,11 @@ func (mv *Mlrval) marshalJSONArraySingleLine(
elementNestingDepth int,
outputIsStdout bool,
) (string, error) {
n := len(mv.x.arrayval)
n := len(mv.intf.([]*Mlrval))
var buffer bytes.Buffer
buffer.WriteByte('[')
for i, element := range mv.x.arrayval {
for i, element := range mv.intf.([]*Mlrval) {
elementString, err := element.marshalJSONAux(JSON_SINGLE_LINE, elementNestingDepth+1, outputIsStdout)
if err != nil {
return "", err
@ -466,7 +466,7 @@ func (mv *Mlrval) marshalJSONArrayMultipleLines(
elementNestingDepth int,
outputIsStdout bool,
) (string, error) {
n := len(mv.x.arrayval)
n := len(mv.intf.([]*Mlrval))
var buffer bytes.Buffer
// Write empty array as '[]'
@ -475,7 +475,7 @@ func (mv *Mlrval) marshalJSONArrayMultipleLines(
buffer.WriteByte('\n')
}
for i, element := range mv.x.arrayval {
for i, element := range mv.intf.([]*Mlrval) {
elementString, err := element.marshalJSONAux(jsonFormatting, elementNestingDepth+1, outputIsStdout)
if err != nil {
return "", err
@ -508,7 +508,7 @@ func (mv *Mlrval) marshalJSONMap(
outputIsStdout bool,
) (string, error) {
lib.InternalCodingErrorIf(mv.mvtype != MT_MAP)
s, err := mv.x.mapval.marshalJSONAux(jsonFormatting, elementNestingDepth, outputIsStdout)
s, err := mv.intf.(*Mlrmap).marshalJSONAux(jsonFormatting, elementNestingDepth, outputIsStdout)
if err != nil {
return "", err
}

View file

@ -83,7 +83,7 @@ func FromInt(input int64) *Mlrval {
return &Mlrval{
mvtype: MT_INT,
printrepValid: false,
intval: input,
intf: input,
}
}
@ -112,7 +112,7 @@ func TryFromIntString(input string) *Mlrval {
func (mv *Mlrval) SetFromPrevalidatedIntString(input string, intval int64) *Mlrval {
mv.printrep = input
mv.printrepValid = true
mv.intval = intval
mv.intf = intval
mv.mvtype = MT_INT
return mv
}
@ -128,7 +128,7 @@ func FromFloat(input float64) *Mlrval {
return &Mlrval{
mvtype: MT_FLOAT,
printrepValid: false,
floatval: input,
intf: input,
}
}
@ -157,7 +157,7 @@ func TryFromFloatString(input string) *Mlrval {
func (mv *Mlrval) SetFromPrevalidatedFloatString(input string, floatval float64) *Mlrval {
mv.printrep = input
mv.printrepValid = true
mv.floatval = floatval
mv.intf = floatval
mv.mvtype = MT_FLOAT
return mv
}
@ -192,7 +192,7 @@ func FromBoolString(input string) *Mlrval {
func (mv *Mlrval) SetFromPrevalidatedBoolString(input string, boolval bool) *Mlrval {
mv.printrep = input
mv.printrepValid = true
mv.boolval = boolval
mv.intf = boolval
mv.mvtype = MT_BOOL
return mv
}
@ -209,9 +209,7 @@ func FromFunction(funcval interface{}, name string) *Mlrval {
mvtype: MT_FUNC,
printrep: name,
printrepValid: true,
x: &mlrvalExtended{
funcval: funcval,
},
intf: funcval,
}
}
@ -220,9 +218,7 @@ func FromArray(arrayval []*Mlrval) *Mlrval {
mvtype: MT_ARRAY,
printrep: "(bug-if-you-see-this:case-4)", // INVALID_PRINTREP,
printrepValid: false,
x: &mlrvalExtended{
arrayval: CopyMlrvalArray(arrayval),
},
intf: CopyMlrvalArray(arrayval),
}
}
@ -235,9 +231,7 @@ func FromMap(mapval *Mlrmap) *Mlrval {
mvtype: MT_MAP,
printrep: "(bug-if-you-see-this:case-5)", // INVALID_PRINTREP,
printrepValid: false,
x: &mlrvalExtended{
mapval: mapval.Copy(),
},
intf: mapval.Copy(),
}
}

View file

@ -37,13 +37,13 @@ func TestFromInferredType(t *testing.T) {
assert.Equal(t, MT_INT, mv.mvtype)
assert.Equal(t, "123", mv.printrep)
assert.True(t, mv.printrepValid)
assert.Equal(t, mv.intval, int64(123))
assert.Equal(t, mv.intf.(int64), int64(123))
mv = FromInferredType("true")
assert.Equal(t, MT_BOOL, mv.mvtype)
assert.Equal(t, "true", mv.printrep)
assert.True(t, mv.printrepValid)
assert.Equal(t, mv.boolval, true)
assert.Equal(t, mv.intf.(bool), true)
mv = FromInferredType("abc")
assert.Equal(t, MT_STRING, mv.mvtype)
@ -124,17 +124,17 @@ func TestFromFunction(t *testing.T) {
mv := FromFunction("test data", "f001")
assert.Equal(t, MT_FUNC, mv.mvtype)
assert.True(t, mv.printrepValid)
assert.Equal(t, "test data", mv.x.funcval.(string))
assert.Equal(t, "test data", mv.intf.(string))
}
func TestFromArray(t *testing.T) {
mv := FromArray([]*Mlrval{FromInt(10)})
assert.Equal(t, MT_ARRAY, mv.mvtype)
assert.Equal(t, 1, len(mv.x.arrayval))
assert.Equal(t, 1, len(mv.intf.([]*Mlrval)))
}
func TestFromMap(t *testing.T) {
mv := FromMap(NewMlrmap())
assert.Equal(t, MT_MAP, mv.mvtype)
assert.True(t, mv.x.mapval.IsEmpty())
assert.True(t, mv.intf.(*Mlrmap).IsEmpty())
}

View file

@ -19,7 +19,7 @@ func (mv *Mlrval) String() string {
//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.floatval)
return floatOutputFormatter.FormatFloat(mv.intf.(float64))
}
// TODO: track dirty-flag checking / somesuch.
@ -71,13 +71,13 @@ func (mv *Mlrval) setPrintRep() {
break
case MT_INT:
mv.printrep = strconv.FormatInt(mv.intval, 10)
mv.printrep = strconv.FormatInt(mv.intf.(int64), 10)
case MT_FLOAT:
mv.printrep = strconv.FormatFloat(mv.floatval, 'f', -1, 64)
mv.printrep = strconv.FormatFloat(mv.intf.(float64), 'f', -1, 64)
case MT_BOOL:
if mv.boolval == true {
if mv.intf.(bool) == true {
mv.printrep = "true"
} else {
mv.printrep = "false"
@ -110,12 +110,12 @@ func (mv *Mlrval) StringifyValuesRecursively() {
switch mv.mvtype {
case MT_ARRAY:
for i, _ := range mv.x.arrayval {
mv.x.arrayval[i].StringifyValuesRecursively()
for i, _ := range mv.intf.([]*Mlrval) {
mv.intf.([]*Mlrval)[i].StringifyValuesRecursively()
}
case MT_MAP:
for pe := mv.x.mapval.Head; pe != nil; pe = pe.Next {
for pe := mv.intf.(*Mlrmap).Head; pe != nil; pe = pe.Next {
pe.Value.StringifyValuesRecursively()
}
@ -126,20 +126,8 @@ func (mv *Mlrval) StringifyValuesRecursively() {
func (mv *Mlrval) ShowSizes() {
fmt.Printf("TOTAL %p %d\n", mv, reflect.TypeOf(*mv).Size())
fmt.Printf("mv.intval %p %d\n", &mv.intval, reflect.TypeOf(mv.intval).Size())
fmt.Printf("mv.floatval %p %d\n", &mv.floatval, reflect.TypeOf(mv.floatval).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.TypeOf(mv.printrep).Size())
fmt.Printf("mv.x %p %d\n", &mv.mvtype, reflect.TypeOf(mv.x).Size())
if mv.x != nil {
fmt.Printf("mv.x.arrayval %p %d\n", &mv.x.arrayval, reflect.TypeOf(mv.x.arrayval).Size())
fmt.Printf("mv.x.mapval %p %d\n", &mv.x.mapval, reflect.TypeOf(mv.x.mapval).Size())
if mv.x.funcval != nil {
fmt.Printf("mv.x.funcval %p %d\n", &mv.x.funcval, reflect.TypeOf(mv.x.funcval).Size())
}
}
fmt.Printf("mv.printrepValid %p %d\n", &mv.printrepValid, reflect.TypeOf(mv.printrepValid).Size())
fmt.Printf("mv.boolval %p %d\n", &mv.boolval, reflect.TypeOf(mv.boolval).Size())
fmt.Printf("mv.mvtype %p %d\n", &mv.mvtype, reflect.TypeOf(mv.mvtype).Size())
}

View file

@ -54,30 +54,14 @@
package mlrval
type Mlrval struct {
intval int64
floatval float64
printrep string
x *mlrvalExtended
printrep string
intf interface{}
printrepValid bool
boolval bool
// Enumeration for string / int / float / boolean / etc.
// I would call this "type" not "mvtype" but "type" is a keyword in Go.
mvtype MVType
}
// The Mlrval type is a (non-union) compound type where arrayval, mapval, and funcval are (a)
// largish, and (b) not usually used.
type mlrvalExtended struct {
arrayval []*Mlrval
mapval *Mlrmap
// First-class-function literals from internal/pkg/dsl/cst.
// Interfaced here to avoid package-dependency cycles.
funcval interface{}
}
const INVALID_PRINTREP = "(bug-if-you-see-this:case-2)"
const ERROR_PRINTREP = "(error)"
const ABSENT_PRINTREP = "(absent)"
@ -108,10 +92,13 @@ const (
// optimization.
MT_PENDING MVType = -1
// intf is int64
MT_INT MVType = 0
// intf is float64
MT_FLOAT MVType = 1
// intf is bool
MT_BOOL MVType = 2
// Key present in input record with empty value, e.g. input data '$x=,$y=2'
@ -119,10 +106,13 @@ const (
MT_STRING MVType = 4
// intf is []*Mlrval
MT_ARRAY MVType = 5
// intf is *Mlrmap
MT_MAP MVType = 6
// intf is interface{} -- resolved in the cst package to avoid circular dependencies
MT_FUNC MVType = 7
// E.g. error encountered in one eval & it propagates up the AST at

View file

@ -1,5 +1,7 @@
mlrs="mlr5 ~/tmp/miller/mlr ./mlr"
#mlrs="mlr5 ./mlr"
mlrs="mlr"
if [ $# -ge 1 ]; then
mlrs="$@"
fi
#reps="1"
reps="1 2 3"

View file

@ -1,5 +1,7 @@
mlrs="mlr5 ~/tmp/miller/mlr ./mlr"
#mlrs="mlr5 ./mlr"
mlrs="mlr"
if [ $# -ge 1 ]; then
mlrs="$@"
fi
#reps="1"
reps="1 2 3"

View file

@ -2,7 +2,10 @@
ourdir=$(dirname $0)
mlrs="mlr5 ~/tmp/miller/mlr ./mlr"
mlrs="mlr"
if [ $# -ge 1 ]; then
mlrs="$@"
fi
#mlrs="mlr5 ./mlr"
#reps="1"