Performance improvement by JIT type inference (#786)

* JIT mlrval type-interfence: mlrval package

* mlrmap refactor

* complete merge from #779

* iterating

* mlrval/format.go

* mlrval/copy.go

* bifs/arithmetic_test.go

* iterate on bifs/collections_test.go

* mlrval_cmp.go

* mlrval JSON iterate

* iterate applying mlrval refactors to dependent packages

* first clean compile in a long while on this branch

* results of first post-compile profiling

* testing

* bugfix in ofmt formatting

* bugfix in octal-supporess

* go fmt

* neaten

* regression tests all passing
This commit is contained in:
John Kerl 2021-12-20 23:56:04 -05:00 committed by GitHub
parent 105a75fb30
commit 7a97c9b868
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
156 changed files with 7258 additions and 5481 deletions

8
.vimrc
View file

@ -1,2 +1,8 @@
map \d :w<C-m>:!clear;echo Building ...; echo; make mlr<C-m>
map \f :w<C-m>:!clear;echo Building ...; echo; make mall<C-m>
map \f :w<C-m>:!clear;echo Building ...; echo; make tests-in-order<C-m>
"map \r :w<C-m>:!clear;echo Building ...; echo; make mlrval-tests<C-m>
"map \r :w<C-m>:!clear;echo Building ...; echo; make mlrmap-tests<C-m>
"map \r :w<C-m>:!clear;echo Building ...; echo; make input-tests<C-m>
"map \r :w<C-m>:!clear;echo Building ...; echo; make mlrval-format-test<C-m>
"map \r :w<C-m>:!clear;echo Building ...; echo; make bifs-tests<C-m>
map \r :w<C-m>:!clear;echo Building ...; echo; make bifs-collections-test<C-m>

175
Makefile
View file

@ -1,6 +1,9 @@
PREFIX=/usr/local
INSTALLDIR=$(PREFIX)/bin
# ================================================================
# General-use targets
# This must remain the first target in this file, which is what 'make' with no
# arguments will run.
build:
@ -14,38 +17,157 @@ check: unit_test regression_test
@echo "by './configure --prefix=/your/install/path' if you wish to install to"
@echo "somewhere other than /usr/local/bin -- the default prefix is /usr/local."
# Unit tests (small number)
unit_test:
go test github.com/johnkerl/miller/internal/pkg/...
# Keystroke-savers
unbackslash_test:
go test $(ls internal/pkg/lib/*.go|grep -v test) internal/pkg/lib/unbackslash_test.go
mlrval_functions_test:
go test internal/pkg/types/mlrval_functions_test.go $(ls internal/pkg/types/*.go | grep -v test)
mlrval_format_test:
go test internal/pkg/types/mlrval_format_test.go $(ls internal/pkg/types/*.go|grep -v test)
regex_test:
go test internal/pkg/lib/regex_test.go internal/pkg/lib/regex.go
# Regression tests (large number)
#
# See ./regression_test.go for information on how to get more details
# for debugging. TL;DR is for CI jobs, we have 'go test -v'; for
# interactive use, instead of 'go test -v' simply use 'mlr regtest
# -vvv' or 'mlr regtest -s 20'. See also internal/pkg/auxents/regtest.
regression_test:
go test -v regression_test.go
# DESTDIR is for package installs; nominally blank when this is run interactively.
# See also https://www.gnu.org/prep/standards/html_node/DESTDIR.html
install: build
cp mlr $(DESTDIR)/$(INSTALLDIR)
make -C man install
fmt:
-go fmt ./...
# ================================================================
# Dev targets
# ----------------------------------------------------------------
# Unit tests (small number)
unit-test ut:
go test github.com/johnkerl/miller/internal/pkg/...
# Keystroke-savers
lib-unbackslash-test:
go test internal/pkg/lib/unbackslash_test.go internal/pkg/lib/unbackslash.go
lib_regex_test:
go test internal/pkg/lib/regex_test.go internal/pkg/lib/regex.go
lib-tests:
go test github.com/johnkerl/miller/internal/pkg/lib/...
mlrval-new-test:
go test internal/pkg/mlrval/new_test.go \
internal/pkg/mlrval/mlrval_type.go \
internal/pkg/mlrval/mlrval_constants.go \
internal/pkg/mlrval/mlrval_new.go \
internal/pkg/mlrval/mlrval_infer.go
mlrval-is-test:
go test internal/pkg/mlrval/is_test.go \
internal/pkg/mlrval/mlrval_type.go \
internal/pkg/mlrval/mlrval_constants.go \
internal/pkg/mlrval/mlrval_new.go \
internal/pkg/mlrval/mlrval_infer.go \
internal/pkg/mlrval/mlrval_is.go
mlrval-get-test:
go test internal/pkg/mlrval/get_test.go \
internal/pkg/mlrval/mlrval_type.go \
internal/pkg/mlrval/mlrval_constants.go \
internal/pkg/mlrval/mlrval_new.go \
internal/pkg/mlrval/mlrval_infer.go \
internal/pkg/mlrval/mlrval_is.go \
internal/pkg/mlrval/mlrval_get.go
mlrval-output-test:
go test internal/pkg/mlrval/output_test.go \
internal/pkg/mlrval/mlrval_type.go \
internal/pkg/mlrval/mlrval_constants.go \
internal/pkg/mlrval/mlrval_new.go \
internal/pkg/mlrval/mlrval_infer.go \
internal/pkg/mlrval/mlrval_is.go \
internal/pkg/mlrval/mlrval_get.go \
internal/pkg/mlrval/mlrval_output.go \
internal/pkg/mlrval/mlrval_format.go
mlrval-format-test:
go test internal/pkg/mlrval/format_test.go \
internal/pkg/mlrval/mlrval_type.go \
internal/pkg/mlrval/mlrval_constants.go \
internal/pkg/mlrval/mlrval_new.go \
internal/pkg/mlrval/mlrval_infer.go \
internal/pkg/mlrval/mlrval_is.go \
internal/pkg/mlrval/mlrval_get.go \
internal/pkg/mlrval/mlrval_output.go \
internal/pkg/mlrval/mlrval_format.go
mlrval-tests:
go test github.com/johnkerl/miller/internal/pkg/mlrval/...
mlrmap-new-test:
go test internal/pkg/mlrval/mlrmap_new_test.go \
internal/pkg/mlrval/mlrmap.go \
internal/pkg/mlrval/mlrval_type.go \
internal/pkg/mlrval/mlrval_constants.go \
internal/pkg/mlrval/mlrval_new.go \
internal/pkg/mlrval/mlrval_infer.go \
internal/pkg/mlrval/mlrval_is.go \
internal/pkg/mlrval/mlrval_get.go \
internal/pkg/mlrval/mlrval_output.go \
internal/pkg/mlrval/mlrval_format.go
mlrmap-accessors-test:
go test internal/pkg/mlrval/mlrmap_accessors_test.go \
internal/pkg/mlrval/mlrmap.go \
internal/pkg/mlrval/mlrmap_accessors.go \
internal/pkg/mlrval/mlrval_type.go \
internal/pkg/mlrval/mlrval_constants.go \
internal/pkg/mlrval/mlrval_new.go \
internal/pkg/mlrval/mlrval_cmp.go \
internal/pkg/mlrval/mlrval_copy.go \
internal/pkg/mlrval/mlrval_infer.go \
internal/pkg/mlrval/mlrval_is.go \
internal/pkg/mlrval/mlrval_get.go \
internal/pkg/mlrval/mlrval_output.go \
internal/pkg/mlrval/mlrval_format.go
mlrmap-tests: mlrmap-new-test mlrmap-accessors-test
input-dkvp-test:
go test internal/pkg/input/record_reader_dkvp_test.go \
internal/pkg/input/record_reader.go \
internal/pkg/input/record_reader_dkvp_nidx.go
input-tests: input-dkvp-test
bifs-arithmetic-test:
go test internal/pkg/bifs/arithmetic_test.go \
internal/pkg/bifs/base.go \
internal/pkg/bifs/arithmetic.go
bifs-bits-test:
go test internal/pkg/bifs/bits_test.go \
internal/pkg/bifs/base.go \
internal/pkg/bifs/arithmetic.go \
internal/pkg/bifs/bits.go
bifs-collections-test:
go test internal/pkg/bifs/collections_test.go \
internal/pkg/bifs/base.go \
internal/pkg/bifs/arithmetic.go \
internal/pkg/bifs/collections.go
bifs-hashing-test:
go test internal/pkg/bifs/hashing_test.go \
internal/pkg/bifs/base.go \
internal/pkg/bifs/arithmetic.go \
internal/pkg/bifs/hashing.go
bifs-sort-test:
go test internal/pkg/bifs/sort_test.go \
internal/pkg/bifs/base.go \
internal/pkg/bifs/arithmetic.go \
internal/pkg/bifs/sort.go
bifs-tests: bifs-arithmetic-test bifs-bits-test bifs-collections-test bifs-hashing-test bifs-sort-test
#mlrval_functions_test:
# go test internal/pkg/mlrval/mlrval_functions_test.go $(ls internal/pkg/types/*.go | grep -v test)
#mlrval_format_test:
# go test internal/pkg/mlrval/mlrval_format_test.go $(ls internal/pkg/types/*.go|grep -v test)
tests-in-order: mlrval-tests mlrmap-tests input-tests bifs-tests
# ----------------------------------------------------------------
# Regression tests (large number)
#
# See ./regression_test.go for information on how to get more details
# for debugging. TL;DR is for CI jobs, we have 'go test -v'; for
# interactive use, instead of 'go test -v' simply use 'mlr regtest
# -vvv' or 'mlr regtest -s 20'. See also internal/pkg/auxents/regtest.
regression-test:
go test -v regression_test.go
# go fmt ./... finds experimental C files which we want to ignore.
fmt:
-go fmt ./cmd/...
-go fmt ./internal/pkg/...
-go fmt ./regression_test.go
# ----------------------------------------------------------------
# For developers before pushing to GitHub.
#
# These steps are done in a particular order:
@ -67,6 +189,7 @@ dev:
make -C docs
@echo DONE
# ----------------------------------------------------------------
# Keystroke-savers
it: build check
so: install
@ -85,10 +208,12 @@ mprof5:
go build github.com/johnkerl/miller/cmd/mprof5
mall: mprof5 mprof4 mprof3 mprof2 mprof mlr
# ----------------------------------------------------------------
# Please see comments in ./create-release-tarball as well as
# https://miller.readthedocs.io/en/latest/build/#creating-a-new-release-for-developers
release_tarball: build check
./create-release-tarball
# ================================================================
# Go does its own dependency management, outside of make.
.PHONY: build mlr mprof mprof2 mprof3 mprof4 mprof5 check unit_test regression_test fmt dev

View file

@ -243,8 +243,8 @@ func (reader *RecordReaderDKVPNonPipelined) processHandle(
func (reader *RecordReaderDKVPNonPipelined) recordFromDKVPLine(
line string,
) *types.Mlrmap {
record := types.NewMlrmap()
) *mlrval.Mlrmap {
record := mlrval.NewMlrmap()
var pairs []string
if reader.readerOptions.IFSRegex == nil { // e.g. --no-ifs-regex
@ -268,11 +268,11 @@ func (reader *RecordReaderDKVPNonPipelined) recordFromDKVPLine(
// "a=". Here we use the positional index as the key. This way
// DKVP is a generalization of NIDX.
key := strconv.Itoa(i + 1) // Miller userspace indices are 1-up
value := types.MlrvalFromInferredTypeForDataFiles(kv[0])
value := mlrval.FromInferredTypeForDataFiles(kv[0])
record.PutReference(key, value)
} else {
key := kv[0]
value := types.MlrvalFromInferredTypeForDataFiles(kv[1])
value := mlrval.FromInferredTypeForDataFiles(kv[1])
record.PutReference(key, value)
}
}
@ -379,8 +379,8 @@ func (reader *RecordReaderDKVPListPipelined) processHandle(
func (reader *RecordReaderDKVPListPipelined) recordFromDKVPLine(
line string,
) *types.Mlrmap {
record := types.NewMlrmap()
) *mlrval.Mlrmap {
record := mlrval.NewMlrmap()
var pairs []string
if reader.readerOptions.IFSRegex == nil { // e.g. --no-ifs-regex
@ -404,11 +404,11 @@ func (reader *RecordReaderDKVPListPipelined) recordFromDKVPLine(
// "a=". Here we use the positional index as the key. This way
// DKVP is a generalization of NIDX.
key := strconv.Itoa(i + 1) // Miller userspace indices are 1-up
value := types.MlrvalFromInferredTypeForDataFiles(kv[0])
value := mlrval.FromInferredTypeForDataFiles(kv[0])
record.PutReference(key, value)
} else {
key := kv[0]
value := types.MlrvalFromInferredTypeForDataFiles(kv[1])
value := mlrval.FromInferredTypeForDataFiles(kv[1])
record.PutReference(key, value)
}
}
@ -531,8 +531,8 @@ func (reader *RecordReaderDKVPChanPipelined) processHandle(
func (reader *RecordReaderDKVPChanPipelined) recordFromDKVPLine(
line string,
) *types.Mlrmap {
record := types.NewMlrmap()
) *mlrval.Mlrmap {
record := mlrval.NewMlrmap()
var pairs []string
if reader.readerOptions.IFSRegex == nil { // e.g. --no-ifs-regex
@ -556,11 +556,11 @@ func (reader *RecordReaderDKVPChanPipelined) recordFromDKVPLine(
// "a=". Here we use the positional index as the key. This way
// DKVP is a generalization of NIDX.
key := strconv.Itoa(i + 1) // Miller userspace indices are 1-up
value := types.MlrvalFromInferredTypeForDataFiles(kv[0])
value := mlrval.FromInferredTypeForDataFiles(kv[0])
record.PutReference(key, value)
} else {
key := kv[0]
value := types.MlrvalFromInferredTypeForDataFiles(kv[1])
value := mlrval.FromInferredTypeForDataFiles(kv[1])
record.PutReference(key, value)
}
}
@ -643,7 +643,7 @@ func NewRecordWriterDKVP2(writerOptions *cli.TWriterOptions) (*RecordWriterDKVP2
}
func (writer *RecordWriterDKVP2) Write(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
ostream *bufio.Writer,
) {
// End of record stream: nothing special for this output format

View file

@ -255,8 +255,8 @@ func (reader *RecordReaderDKVPChanPipelined) processHandle(
func (reader *RecordReaderDKVPChanPipelined) recordFromDKVPLine(
line string,
) *types.Mlrmap {
record := types.NewMlrmap()
) *mlrval.Mlrmap {
record := mlrval.NewMlrmap()
var pairs []string
if reader.readerOptions.IFSRegex == nil { // e.g. --no-ifs-regex
@ -280,11 +280,11 @@ func (reader *RecordReaderDKVPChanPipelined) recordFromDKVPLine(
// "a=". Here we use the positional index as the key. This way
// DKVP is a generalization of NIDX.
key := strconv.Itoa(i + 1) // Miller userspace indices are 1-up
value := types.MlrvalFromInferredTypeForDataFiles(kv[0])
value := mlrval.FromInferredTypeForDataFiles(kv[0])
record.PutReference(key, value)
} else {
key := kv[0]
value := types.MlrvalFromInferredTypeForDataFiles(kv[1])
value := mlrval.FromInferredTypeForDataFiles(kv[1])
record.PutReference(key, value)
}
}

View file

@ -269,8 +269,8 @@ func (reader *RecordReaderDKVPChanPipelined) getRecordBatch(
func (reader *RecordReaderDKVPChanPipelined) recordFromDKVPLine(
line string,
) *types.Mlrmap {
record := types.NewMlrmapAsRecord()
) *mlrval.Mlrmap {
record := mlrval.NewMlrmapAsRecord()
var pairs []string
if reader.readerOptions.IFSRegex == nil { // e.g. --no-ifs-regex
@ -294,11 +294,11 @@ func (reader *RecordReaderDKVPChanPipelined) recordFromDKVPLine(
// "a=". Here we use the positional index as the key. This way
// DKVP is a generalization of NIDX.
key := strconv.Itoa(i + 1) // Miller userspace indices are 1-up
value := types.MlrvalFromInferredTypeForDataFiles(kv[0])
value := mlrval.FromInferredTypeForDataFiles(kv[0])
record.PutReference(key, value)
} else {
key := kv[0]
value := types.MlrvalFromInferredTypeForDataFiles(kv[1])
value := mlrval.FromInferredTypeForDataFiles(kv[1])
record.PutReference(key, value)
}
}

1
go.mod
View file

@ -18,6 +18,7 @@ require (
github.com/lestrrat-go/strftime v1.0.4
github.com/mattn/go-isatty v0.0.12
github.com/pkg/profile v1.6.0 // indirect
github.com/stretchr/testify v1.7.0 // indirect
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf
)

5
go.sum
View file

@ -19,6 +19,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -49,3 +51,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -10,11 +10,12 @@ import (
"github.com/mattn/go-isatty"
"github.com/johnkerl/miller/internal/pkg/bifs"
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/dsl/cst"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/transformers"
"github.com/johnkerl/miller/internal/pkg/types"
)
// ================================================================
@ -447,11 +448,11 @@ func helpOutputColorization() {
// ----------------------------------------------------------------
func helpTypeArithmeticInfo() {
mlrvals := []*types.Mlrval{
types.MlrvalFromInt(1),
types.MlrvalFromFloat64(2.5),
types.MLRVAL_ABSENT,
types.MLRVAL_ERROR,
mlrvals := []*mlrval.Mlrval{
mlrval.FromInt(1),
mlrval.FromFloat(2.5),
mlrval.ABSENT,
mlrval.ERROR,
}
n := len(mlrvals)
@ -470,7 +471,7 @@ func helpTypeArithmeticInfo() {
} else if i == -1 {
fmt.Printf(" %-10s", "------")
} else {
sum := types.BIF_plus_binary(mlrvals[i], mlrvals[j])
sum := bifs.BIF_plus_binary(mlrvals[i], mlrvals[j])
fmt.Printf(" %-10s", sum.String())
}
}

View file

@ -25,7 +25,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/dsl/cst"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// ----------------------------------------------------------------
@ -83,8 +83,8 @@ func (repl *Repl) handleDSLStringAux(
// The filter expression for the main Miller DSL is any non-assignment
// statment like 'true' or '$x > 0.5' etc. For the REPL, we re-use this for
// interactive expressions to be printed to the terminal. For the main DSL,
// the default is types.MlrvalFromTrue(); for the REPL, the default is
// types.MLRVAL_VOID.
// the default is mlrval.FromTrue(); for the REPL, the default is
// mlrval.VOID.
filterExpression := repl.runtimeState.FilterExpression
if filterExpression.IsVoid() {
// nothing to print
@ -93,7 +93,7 @@ func (repl *Repl) handleDSLStringAux(
} else {
fmt.Println(filterExpression.String())
}
repl.runtimeState.FilterExpression = types.MLRVAL_VOID
repl.runtimeState.FilterExpression = mlrval.VOID
}
return nil

View file

@ -29,6 +29,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl/cst"
"github.com/johnkerl/miller/internal/pkg/input"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/output"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
@ -58,7 +59,7 @@ func NewRepl(
}
// $* is the empty map {} until/unless the user opens a file and reads records from it.
inrec := types.NewMlrmapAsRecord()
inrec := mlrval.NewMlrmapAsRecord()
// NR is 0, etc until/unless the user opens a file and reads records from it.
context := types.NewContext()
@ -67,9 +68,9 @@ func NewRepl(
// The filter expression for the main Miller DSL is any non-assignment
// statment like 'true' or '$x > 0.5' etc. For the REPL, we re-use this for
// interactive expressions to be printed to the terminal. For the main DSL,
// the default is types.MlrvalFromTrue(); for the REPL, the default is
// types.MLRVAL_VOID.
runtimeState.FilterExpression = types.MLRVAL_VOID
// the default is mlrval.FromTrue(); for the REPL, the default is
// mlrval.VOID.
runtimeState.FilterExpression = mlrval.VOID
// For control-C handling
sysToSignalHandlerChannel := make(chan os.Signal, 1) // Our signal handler reads system notification here

View file

@ -14,6 +14,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/dsl/cst"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -608,7 +609,7 @@ func handleWrite(repl *Repl, args []string) bool {
return true
}
func writeRecord(repl *Repl, outrec *types.Mlrmap) {
func writeRecord(repl *Repl, outrec *mlrval.Mlrmap) {
if outrec != nil {
// E.g. '{"req": {"method": "GET", "path": "/api/check"}}' becomes
// req.method=GET,req.path=/api/check.

View file

@ -1,13 +1,15 @@
package types
package bifs
import (
"math"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// ================================================================
// Unary plus operator
var upos_dispositions = [MT_DIM]UnaryFunc{
var upos_dispositions = [mlrval.MT_DIM]UnaryFunc{
/*ERROR */ _erro1,
/*ABSENT */ _absn1,
/*NULL */ _null1,
@ -21,22 +23,22 @@ var upos_dispositions = [MT_DIM]UnaryFunc{
/*FUNC */ _erro1,
}
func BIF_plus_unary(input1 *Mlrval) *Mlrval {
return upos_dispositions[input1.mvtype](input1)
func BIF_plus_unary(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return upos_dispositions[input1.Type()](input1)
}
// ================================================================
// Unary minus operator
func uneg_i_i(input1 *Mlrval) *Mlrval {
return MlrvalFromInt(-input1.intval)
func uneg_i_i(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(-input1.AcquireIntValue())
}
func uneg_f_f(input1 *Mlrval) *Mlrval {
return MlrvalFromFloat64(-input1.floatval)
func uneg_f_f(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(-input1.AcquireFloatValue())
}
var uneg_dispositions = [MT_DIM]UnaryFunc{
var uneg_dispositions = [mlrval.MT_DIM]UnaryFunc{
/*ERROR */ _erro1,
/*ABSENT */ _absn1,
/*NULL */ _null1,
@ -50,30 +52,19 @@ var uneg_dispositions = [MT_DIM]UnaryFunc{
/*FUNC */ _erro1,
}
func BIF_minus_unary(input1 *Mlrval) *Mlrval {
return uneg_dispositions[input1.mvtype](input1)
}
// ================================================================
// Logical NOT operator
func BIF_logicalnot(input1 *Mlrval) *Mlrval {
if input1.mvtype == MT_BOOL {
return MlrvalFromBool(!input1.boolval)
} else {
return MLRVAL_ERROR
}
func BIF_minus_unary(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return uneg_dispositions[input1.Type()](input1)
}
// ================================================================
// Addition with auto-overflow from int to float when necessary. See also
// https://johnkerl.org/miller6/reference-main-arithmetic.html
// https://miller.readthedocs.io/en/latest/reference-main-arithmetic
// Auto-overflows up to float. Additions & subtractions overflow by at most
// one bit so it suffices to check sign-changes.
func plus_n_ii(input1, input2 *Mlrval) *Mlrval {
a := input1.intval
b := input2.intval
func plus_n_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
a := input1.AcquireIntValue()
b := input2.AcquireIntValue()
c := a + b
overflowed := false
@ -88,23 +79,23 @@ func plus_n_ii(input1, input2 *Mlrval) *Mlrval {
}
if overflowed {
return MlrvalFromFloat64(float64(a) + float64(b))
return mlrval.FromFloat(float64(a) + float64(b))
} else {
return MlrvalFromInt(c)
return mlrval.FromInt(c)
}
}
func plus_f_if(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(float64(input1.intval) + input2.floatval)
func plus_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(float64(input1.AcquireIntValue()) + input2.AcquireFloatValue())
}
func plus_f_fi(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval + float64(input2.intval))
func plus_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() + float64(input2.AcquireIntValue()))
}
func plus_f_ff(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval + input2.floatval)
func plus_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() + input2.AcquireFloatValue())
}
var plus_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var plus_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _2___, _erro, _absn, _absn, _erro},
@ -119,19 +110,19 @@ var plus_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_plus_binary(input1, input2 *Mlrval) *Mlrval {
return plus_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_plus_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return plus_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ================================================================
// Subtraction with auto-overflow from int to float when necessary. See also
// https://johnkerl.org/miller6/reference-main-arithmetic.html
// https://miller.readthedocs.io/en/latest/reference-main-arithmetic
// Adds & subtracts overflow by at most one bit so it suffices to check
// sign-changes.
func minus_n_ii(input1, input2 *Mlrval) *Mlrval {
a := input1.intval
b := input2.intval
func minus_n_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
a := input1.AcquireIntValue()
b := input2.AcquireIntValue()
c := a - b
overflowed := false
@ -146,23 +137,23 @@ func minus_n_ii(input1, input2 *Mlrval) *Mlrval {
}
if overflowed {
return MlrvalFromFloat64(float64(a) - float64(b))
return mlrval.FromFloat(float64(a) - float64(b))
} else {
return MlrvalFromInt(c)
return mlrval.FromInt(c)
}
}
func minus_f_if(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(float64(input1.intval) - input2.floatval)
func minus_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(float64(input1.AcquireIntValue()) - input2.AcquireFloatValue())
}
func minus_f_fi(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval - float64(input2.intval))
func minus_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() - float64(input2.AcquireIntValue()))
}
func minus_f_ff(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval - input2.floatval)
func minus_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() - input2.AcquireFloatValue())
}
var minus_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var minus_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _2___, _erro, _absn, _absn, _erro},
@ -177,13 +168,13 @@ var minus_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_minus_binary(input1, input2 *Mlrval) *Mlrval {
return minus_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_minus_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return minus_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ================================================================
// Multiplication with auto-overflow from int to float when necessary. See
// https://johnkerl.org/miller6/reference-main-arithmetic.html
// https://miller.readthedocs.io/en/latest/reference-main-arithmetic
// Auto-overflows up to float.
//
@ -214,29 +205,29 @@ func BIF_minus_binary(input1, input2 *Mlrval) *Mlrval {
// double less than 2**63. (An alterative would be to do all integer multiplies
// using handcrafted multi-word 128-bit arithmetic).
func times_n_ii(input1, input2 *Mlrval) *Mlrval {
a := input1.intval
b := input2.intval
func times_n_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
a := input1.AcquireIntValue()
b := input2.AcquireIntValue()
c := float64(a) * float64(b)
if math.Abs(c) > 9223372036854774784.0 {
return MlrvalFromFloat64(c)
return mlrval.FromFloat(c)
} else {
return MlrvalFromInt(a * b)
return mlrval.FromInt(a * b)
}
}
func times_f_if(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(float64(input1.intval) * input2.floatval)
func times_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(float64(input1.AcquireIntValue()) * input2.AcquireFloatValue())
}
func times_f_fi(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval * float64(input2.intval))
func times_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() * float64(input2.AcquireIntValue()))
}
func times_f_ff(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval * input2.floatval)
func times_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() * input2.AcquireFloatValue())
}
var times_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var times_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _2___, _erro, _absn, _absn, _erro},
@ -251,13 +242,13 @@ var times_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_times(input1, input2 *Mlrval) *Mlrval {
return times_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_times(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return times_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ================================================================
// Pythonic division. See also
// https://johnkerl.org/miller6/reference-main-arithmetic.html
// https://miller.readthedocs.io/en/latest/reference-main-arithmetic
//
// Int/int pairings don't produce overflow.
//
@ -272,42 +263,42 @@ func BIF_times(input1, input2 *Mlrval) *Mlrval {
// $ echo 'x=1e-300,y=1e300' | mlr put '$z=$y/$x'
// x=1e-300,y=1e300,z=+Inf
func divide_n_ii(input1, input2 *Mlrval) *Mlrval {
a := input1.intval
b := input2.intval
func divide_n_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
a := input1.AcquireIntValue()
b := input2.AcquireIntValue()
if b == 0 {
// Compute inf/nan as with floats rather than fatal runtime FPE on integer divide by zero
return MlrvalFromFloat64(float64(a) / float64(b))
return mlrval.FromFloat(float64(a) / float64(b))
}
// Pythonic division, not C division.
if a%b == 0 {
return MlrvalFromInt(a / b)
return mlrval.FromInt(a / b)
} else {
return MlrvalFromFloat64(float64(a) / float64(b))
return mlrval.FromFloat(float64(a) / float64(b))
}
c := float64(a) * float64(b)
if math.Abs(c) > 9223372036854774784.0 {
return MlrvalFromFloat64(c)
return mlrval.FromFloat(c)
} else {
return MlrvalFromInt(a * b)
return mlrval.FromInt(a * b)
}
}
func divide_f_if(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(float64(input1.intval) / input2.floatval)
func divide_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(float64(input1.AcquireIntValue()) / input2.AcquireFloatValue())
}
func divide_f_fi(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval / float64(input2.intval))
func divide_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() / float64(input2.AcquireIntValue()))
}
func divide_f_ff(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval / input2.floatval)
func divide_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() / input2.AcquireFloatValue())
}
var divide_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var divide_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _i0__, _f0__, _erro, _absn, _absn, _erro},
@ -322,21 +313,21 @@ var divide_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_divide(input1, input2 *Mlrval) *Mlrval {
return divide_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_divide(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return divide_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ================================================================
// Integer division: DSL operator '//' as in Python. See also
// https://johnkerl.org/miller6/reference-main-arithmetic.html
// https://miller.readthedocs.io/en/latest/reference-main-arithmetic
func int_divide_n_ii(input1, input2 *Mlrval) *Mlrval {
a := input1.intval
b := input2.intval
func int_divide_n_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
a := input1.AcquireIntValue()
b := input2.AcquireIntValue()
if b == 0 {
// Compute inf/nan as with floats rather than fatal runtime FPE on integer divide by zero
return MlrvalFromFloat64(float64(a) / float64(b))
return mlrval.FromFloat(float64(a) / float64(b))
}
// Pythonic division, not C division.
@ -355,20 +346,20 @@ func int_divide_n_ii(input1, input2 *Mlrval) *Mlrval {
}
}
}
return MlrvalFromInt(q)
return mlrval.FromInt(q)
}
func int_divide_f_if(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(math.Floor(float64(input1.intval) / input2.floatval))
func int_divide_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Floor(float64(input1.AcquireIntValue()) / input2.AcquireFloatValue()))
}
func int_divide_f_fi(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(math.Floor(input1.floatval / float64(input2.intval)))
func int_divide_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Floor(input1.AcquireFloatValue() / float64(input2.AcquireIntValue())))
}
func int_divide_f_ff(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(math.Floor(input1.floatval / input2.floatval))
func int_divide_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Floor(input1.AcquireFloatValue() / input2.AcquireFloatValue()))
}
var int_divide_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var int_divide_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _i0__, _f0__, _erro, _absn, _absn, _erro},
@ -383,28 +374,28 @@ var int_divide_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_int_divide(input1, input2 *Mlrval) *Mlrval {
return int_divide_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_int_divide(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return int_divide_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ================================================================
// Non-auto-overflowing addition: DSL operator '.+'. See also
// https://johnkerl.org/miller6/reference-main-arithmetic.html
// https://miller.readthedocs.io/en/latest/reference-main-arithmetic
func dotplus_i_ii(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromInt(input1.intval + input2.intval)
func dotplus_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(input1.AcquireIntValue() + input2.AcquireIntValue())
}
func dotplus_f_if(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(float64(input1.intval) + input2.floatval)
func dotplus_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(float64(input1.AcquireIntValue()) + input2.AcquireFloatValue())
}
func dotplus_f_fi(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval + float64(input2.intval))
func dotplus_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() + float64(input2.AcquireIntValue()))
}
func dotplus_f_ff(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval + input2.floatval)
func dotplus_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() + input2.AcquireFloatValue())
}
var dot_plus_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var dot_plus_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _2___, _erro, _absn, _absn, _erro},
@ -419,28 +410,28 @@ var dot_plus_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_dot_plus(input1, input2 *Mlrval) *Mlrval {
return dot_plus_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_dot_plus(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return dot_plus_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ================================================================
// Non-auto-overflowing subtraction: DSL operator '.-'. See also
// https://johnkerl.org/miller6/reference-main-arithmetic.html
// https://miller.readthedocs.io/en/latest/reference-main-arithmetic
func dotminus_i_ii(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromInt(input1.intval - input2.intval)
func dotminus_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(input1.AcquireIntValue() - input2.AcquireIntValue())
}
func dotminus_f_if(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(float64(input1.intval) - input2.floatval)
func dotminus_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(float64(input1.AcquireIntValue()) - input2.AcquireFloatValue())
}
func dotminus_f_fi(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval - float64(input2.intval))
func dotminus_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() - float64(input2.AcquireIntValue()))
}
func dotminus_f_ff(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval - input2.floatval)
func dotminus_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() - input2.AcquireFloatValue())
}
var dotminus_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var dotminus_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _n2__, _n2__, _erro, _absn, _absn, _erro},
@ -455,28 +446,28 @@ var dotminus_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_dot_minus(input1, input2 *Mlrval) *Mlrval {
return dotminus_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_dot_minus(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return dotminus_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ----------------------------------------------------------------
// Non-auto-overflowing multiplication: DSL operator '.*'. See also
// https://johnkerl.org/miller6/reference-main-arithmetic.html
// https://miller.readthedocs.io/en/latest/reference-main-arithmetic
func dottimes_i_ii(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromInt(input1.intval * input2.intval)
func dottimes_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(input1.AcquireIntValue() * input2.AcquireIntValue())
}
func dottimes_f_if(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(float64(input1.intval) * input2.floatval)
func dottimes_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(float64(input1.AcquireIntValue()) * input2.AcquireFloatValue())
}
func dottimes_f_fi(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval * float64(input2.intval))
func dottimes_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() * float64(input2.AcquireIntValue()))
}
func dottimes_f_ff(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval * input2.floatval)
func dottimes_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() * input2.AcquireFloatValue())
}
var dottimes_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var dottimes_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _2___, _erro, _absn, _absn, _erro},
@ -491,28 +482,28 @@ var dottimes_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_dot_times(input1, input2 *Mlrval) *Mlrval {
return dottimes_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_dot_times(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return dottimes_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ----------------------------------------------------------------
// 64-bit integer division: DSL operator './'. See also
// https://johnkerl.org/miller6/reference-main-arithmetic.html
// https://miller.readthedocs.io/en/latest/reference-main-arithmetic
func dotdivide_i_ii(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromInt(input1.intval / input2.intval)
func dotdivide_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(input1.AcquireIntValue() / input2.AcquireIntValue())
}
func dotdivide_f_if(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(float64(input1.intval) / input2.floatval)
func dotdivide_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(float64(input1.AcquireIntValue()) / input2.AcquireFloatValue())
}
func dotdivide_f_fi(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval / float64(input2.intval))
func dotdivide_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() / float64(input2.AcquireIntValue()))
}
func dotdivide_f_ff(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(input1.floatval / input2.floatval)
func dotdivide_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(input1.AcquireFloatValue() / input2.AcquireFloatValue())
}
var dotdivide_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var dotdivide_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _2___, _erro, _absn, _absn, _erro},
@ -527,21 +518,21 @@ var dotdivide_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_dot_divide(input1, input2 *Mlrval) *Mlrval {
return dotdivide_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_dot_divide(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return dotdivide_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ----------------------------------------------------------------
// 64-bit integer division: DSL operator './/'. See also
// https://johnkerl.org/miller6/reference-main-arithmetic.html
// https://miller.readthedocs.io/en/latest/reference-main-arithmetic
func dotidivide_i_ii(input1, input2 *Mlrval) *Mlrval {
a := input1.intval
b := input2.intval
func dotidivide_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
a := input1.AcquireIntValue()
b := input2.AcquireIntValue()
if b == 0 {
// Compute inf/nan as with floats rather than fatal runtime FPE on integer divide by zero
return MlrvalFromFloat64(float64(a) / float64(b))
return mlrval.FromFloat(float64(a) / float64(b))
}
// Pythonic division, not C division.
@ -560,20 +551,20 @@ func dotidivide_i_ii(input1, input2 *Mlrval) *Mlrval {
}
}
}
return MlrvalFromInt(q)
return mlrval.FromInt(q)
}
func dotidivide_f_if(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(math.Floor(float64(input1.intval) / input2.floatval))
func dotidivide_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Floor(float64(input1.AcquireIntValue()) / input2.AcquireFloatValue()))
}
func dotidivide_f_fi(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(math.Floor(input1.floatval / float64(input2.intval)))
func dotidivide_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Floor(input1.AcquireFloatValue() / float64(input2.AcquireIntValue())))
}
func dotidivide_f_ff(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(math.Floor(input1.floatval / input2.floatval))
func dotidivide_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Floor(input1.AcquireFloatValue() / input2.AcquireFloatValue()))
}
var dotidivide_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var dotidivide_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _erro, _absn, _erro, _2___, _2___, _erro, _absn, _absn, _erro},
@ -588,20 +579,20 @@ var dotidivide_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func MlrvalDotIntDivide(input1, input2 *Mlrval) *Mlrval {
return dotidivide_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_dot_int_divide(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return dotidivide_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ----------------------------------------------------------------
// Modulus
func modulus_i_ii(input1, input2 *Mlrval) *Mlrval {
a := input1.intval
b := input2.intval
func modulus_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
a := input1.AcquireIntValue()
b := input2.AcquireIntValue()
if b == 0 {
// Compute inf/nan as with floats rather than fatal runtime FPE on integer divide by zero
return MlrvalFromFloat64(float64(a) / float64(b))
return mlrval.FromFloat(float64(a) / float64(b))
}
// Pythonic division, not C division.
@ -616,28 +607,28 @@ func modulus_i_ii(input1, input2 *Mlrval) *Mlrval {
}
}
return MlrvalFromInt(m)
return mlrval.FromInt(m)
}
func modulus_f_fi(input1, input2 *Mlrval) *Mlrval {
a := input1.floatval
b := float64(input2.intval)
return MlrvalFromFloat64(a - b*math.Floor(a/b))
func modulus_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
a := input1.AcquireFloatValue()
b := float64(input2.AcquireIntValue())
return mlrval.FromFloat(a - b*math.Floor(a/b))
}
func modulus_f_if(input1, input2 *Mlrval) *Mlrval {
a := float64(input1.intval)
b := input2.floatval
return MlrvalFromFloat64(a - b*math.Floor(a/b))
func modulus_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
a := float64(input1.AcquireIntValue())
b := input2.AcquireFloatValue()
return mlrval.FromFloat(a - b*math.Floor(a/b))
}
func modulus_f_ff(input1, input2 *Mlrval) *Mlrval {
a := input1.floatval
b := input2.floatval
return MlrvalFromFloat64(a - b*math.Floor(a/b))
func modulus_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
a := input1.AcquireFloatValue()
b := input2.AcquireFloatValue()
return mlrval.FromFloat(a - b*math.Floor(a/b))
}
var modulus_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var modulus_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _i0__, _f0__, _erro, _absn, _absn, _erro},
@ -652,8 +643,8 @@ var modulus_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_modulus(input1, input2 *Mlrval) *Mlrval {
return modulus_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_modulus(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return modulus_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ================================================================
@ -701,7 +692,7 @@ func imodexp(a, e, m int) int {
return c
}
func imodop(input1, input2, input3 *Mlrval, iop i_iii_func) *Mlrval {
func imodop(input1, input2, input3 *mlrval.Mlrval, iop i_iii_func) *mlrval.Mlrval {
if !input1.IsLegit() {
return input1
}
@ -712,34 +703,34 @@ func imodop(input1, input2, input3 *Mlrval, iop i_iii_func) *Mlrval {
return input3
}
if !input1.IsInt() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input2.IsInt() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input3.IsInt() {
return MLRVAL_ERROR
return mlrval.ERROR
}
return MlrvalFromInt(iop(input1.intval, input2.intval, input3.intval))
return mlrval.FromInt(iop(input1.AcquireIntValue(), input2.AcquireIntValue(), input3.AcquireIntValue()))
}
func BIF_mod_add(input1, input2, input3 *Mlrval) *Mlrval {
func BIF_mod_add(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
return imodop(input1, input2, input3, imodadd)
}
func BIF_mod_sub(input1, input2, input3 *Mlrval) *Mlrval {
func BIF_mod_sub(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
return imodop(input1, input2, input3, imodsub)
}
func BIF_mod_mul(input1, input2, input3 *Mlrval) *Mlrval {
func BIF_mod_mul(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
return imodop(input1, input2, input3, imodmul)
}
func BIF_mod_exp(input1, input2, input3 *Mlrval) *Mlrval {
func BIF_mod_exp(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
// Pre-check for negative exponent
if input2.mvtype == MT_INT && input2.intval < 0 {
return MLRVAL_ERROR
if input2.IsInt() && input2.AcquireIntValue() < 0 {
return mlrval.ERROR
}
return imodop(input1, input2, input3, imodexp)
}
@ -759,27 +750,27 @@ func BIF_mod_exp(input1, input2, input3 *Mlrval) *Mlrval {
// * empty-null always loses against numbers
// ----------------------------------------------------------------
func min_f_ff(input1, input2 *Mlrval) *Mlrval {
var a float64 = input1.floatval
var b float64 = input2.floatval
return MlrvalFromFloat64(math.Min(a, b))
func min_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var a float64 = input1.AcquireFloatValue()
var b float64 = input2.AcquireFloatValue()
return mlrval.FromFloat(math.Min(a, b))
}
func min_f_fi(input1, input2 *Mlrval) *Mlrval {
var a float64 = input1.floatval
var b float64 = float64(input2.intval)
return MlrvalFromFloat64(math.Min(a, b))
func min_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var a float64 = input1.AcquireFloatValue()
var b float64 = float64(input2.AcquireIntValue())
return mlrval.FromFloat(math.Min(a, b))
}
func min_f_if(input1, input2 *Mlrval) *Mlrval {
var a float64 = float64(input1.intval)
var b float64 = input2.floatval
return MlrvalFromFloat64(math.Min(a, b))
func min_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var a float64 = float64(input1.AcquireIntValue())
var b float64 = input2.AcquireFloatValue()
return mlrval.FromFloat(math.Min(a, b))
}
func min_i_ii(input1, input2 *Mlrval) *Mlrval {
var a int = input1.intval
var b int = input2.intval
func min_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var a int = input1.AcquireIntValue()
var b int = input2.AcquireIntValue()
if a < b {
return input1
} else {
@ -791,17 +782,17 @@ func min_i_ii(input1, input2 *Mlrval) *Mlrval {
// --- + ----- -----
// a=F | min=a min=a
// a=T | min=b min=b
func min_b_bb(input1, input2 *Mlrval) *Mlrval {
if input1.boolval == false {
func min_b_bb(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.AcquireBoolValue() == false {
return input1
} else {
return input2
}
}
func min_s_ss(input1, input2 *Mlrval) *Mlrval {
var a string = input1.printrep
var b string = input2.printrep
func min_s_ss(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var a string = input1.AcquireStringValue()
var b string = input2.AcquireStringValue()
if a < b {
return input1
} else {
@ -809,7 +800,7 @@ func min_s_ss(input1, input2 *Mlrval) *Mlrval {
}
}
var min_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var min_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _null, _2___, _2___, _2___, _2___, _2___, _absn, _absn, _erro},
@ -824,18 +815,18 @@ var min_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func MlrvalBinaryMin(input1, input2 *Mlrval) *Mlrval {
return (min_dispositions[input1.mvtype][input2.mvtype])(input1, input2)
func BIF_min_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return (min_dispositions[input1.Type()][input2.Type()])(input1, input2)
}
func BIF_min_variadic(mlrvals []*Mlrval) *Mlrval {
func BIF_min_variadic(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval {
if len(mlrvals) == 0 {
return MLRVAL_VOID
return mlrval.VOID
} else {
retval := mlrvals[0]
for i := range mlrvals {
if i > 0 {
retval = MlrvalBinaryMin(retval, mlrvals[i])
retval = BIF_min_binary(retval, mlrvals[i])
}
}
return retval
@ -843,27 +834,27 @@ func BIF_min_variadic(mlrvals []*Mlrval) *Mlrval {
}
// ----------------------------------------------------------------
func max_f_ff(input1, input2 *Mlrval) *Mlrval {
var a float64 = input1.floatval
var b float64 = input2.floatval
return MlrvalFromFloat64(math.Max(a, b))
func max_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var a float64 = input1.AcquireFloatValue()
var b float64 = input2.AcquireFloatValue()
return mlrval.FromFloat(math.Max(a, b))
}
func max_f_fi(input1, input2 *Mlrval) *Mlrval {
var a float64 = input1.floatval
var b float64 = float64(input2.intval)
return MlrvalFromFloat64(math.Max(a, b))
func max_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var a float64 = input1.AcquireFloatValue()
var b float64 = float64(input2.AcquireIntValue())
return mlrval.FromFloat(math.Max(a, b))
}
func max_f_if(input1, input2 *Mlrval) *Mlrval {
var a float64 = float64(input1.intval)
var b float64 = input2.floatval
return MlrvalFromFloat64(math.Max(a, b))
func max_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var a float64 = float64(input1.AcquireIntValue())
var b float64 = input2.AcquireFloatValue()
return mlrval.FromFloat(math.Max(a, b))
}
func max_i_ii(input1, input2 *Mlrval) *Mlrval {
var a int = input1.intval
var b int = input2.intval
func max_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var a int = input1.AcquireIntValue()
var b int = input2.AcquireIntValue()
if a > b {
return input1
} else {
@ -875,17 +866,17 @@ func max_i_ii(input1, input2 *Mlrval) *Mlrval {
// --- + ----- -----
// a=F | max=a max=b
// a=T | max=a max=b
func max_b_bb(input1, input2 *Mlrval) *Mlrval {
if input2.boolval == false {
func max_b_bb(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if input2.AcquireBoolValue() == false {
return input1
} else {
return input2
}
}
func max_s_ss(input1, input2 *Mlrval) *Mlrval {
var a string = input1.printrep
var b string = input2.printrep
func max_s_ss(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var a string = input1.AcquireStringValue()
var b string = input2.AcquireStringValue()
if a > b {
return input1
} else {
@ -893,7 +884,7 @@ func max_s_ss(input1, input2 *Mlrval) *Mlrval {
}
}
var max_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var max_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _null, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _2___, _2___, _2___, _2___, _2___, _absn, _absn, _erro},
@ -908,18 +899,18 @@ var max_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func MlrvalBinaryMax(input1, input2 *Mlrval) *Mlrval {
return (max_dispositions[input1.mvtype][input2.mvtype])(input1, input2)
func BIF_max_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return (max_dispositions[input1.Type()][input2.Type()])(input1, input2)
}
func BIF_max_variadic(mlrvals []*Mlrval) *Mlrval {
func BIF_max_variadic(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval {
if len(mlrvals) == 0 {
return MLRVAL_VOID
return mlrval.VOID
} else {
retval := mlrvals[0]
for i := range mlrvals {
if i > 0 {
retval = MlrvalBinaryMax(retval, mlrvals[i])
retval = BIF_max_binary(retval, mlrvals[i])
}
}
return retval

View file

@ -0,0 +1,90 @@
package bifs
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
func TestBIF_plus_unary(t *testing.T) {
input := mlrval.FromDeferredType("123")
output := BIF_plus_unary(input)
intval, ok := output.GetIntValue()
assert.True(t, ok)
assert.Equal(t, 123, intval)
input = mlrval.FromDeferredType("-123.5")
output = BIF_plus_unary(input)
floatval, ok := output.GetFloatValue()
assert.True(t, ok)
assert.Equal(t, -123.5, floatval)
}
func TestBIF_minus_unary(t *testing.T) {
input := mlrval.FromDeferredType("123")
output := BIF_minus_unary(input)
intval, ok := output.GetIntValue()
assert.True(t, ok)
assert.Equal(t, -123, intval)
input = mlrval.FromDeferredType("-123.5")
output = BIF_minus_unary(input)
floatval, ok := output.GetFloatValue()
assert.True(t, ok)
assert.Equal(t, 123.5, floatval)
}
func TestBIF_plus_binary(t *testing.T) {
input1 := mlrval.FromDeferredType("123")
input2 := mlrval.FromDeferredType("456")
output := BIF_plus_binary(input1, input2)
intval, ok := output.GetIntValue()
assert.True(t, ok)
assert.Equal(t, 579, intval)
input1 = mlrval.FromDeferredType("123.5")
input2 = mlrval.FromDeferredType("456")
output = BIF_plus_binary(input1, input2)
floatval, ok := output.GetFloatValue()
assert.True(t, ok)
assert.Equal(t, 579.5, floatval)
}
func TestBIF_plus_binary_overflow(t *testing.T) {
input1 := mlrval.FromInt(0x07ffffffffffffff)
input2 := mlrval.FromInt(0x07fffffffffffffe)
output := BIF_plus_binary(input1, input2)
intval, ok := output.GetIntValue()
assert.True(t, ok)
assert.Equal(t, 0x0ffffffffffffffd, intval)
input1 = mlrval.FromInt(0x7fffffffffffffff)
input2 = mlrval.FromInt(0x7ffffffffffffffe)
output = BIF_plus_binary(input1, input2)
floatval, ok := output.GetFloatValue()
assert.True(t, ok)
assert.Equal(t, 18446744073709552000.0, floatval)
}
// TODO: copy in more unit-test cases from existing regression-test data
//func BIF_minus_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_times(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_divide(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_int_divide(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_dot_plus(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_dot_minus(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_dot_times(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_dot_divide(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_dot_int_divide(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_modulus(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_mod_add(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_mod_sub(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_mod_mul(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_mod_exp(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_min_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_min_variadic(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval
//func BIF_max_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
//func BIF_max_variadic(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval

View file

@ -12,7 +12,7 @@
// example: adding two ints, or an int and a float, or int and boolean (the
// latter being an error).
//
// The next-past-highest mlrval type enum is called MT_DIM and that is the
// The next-past-highest mlrval type enum is called mlrval.MT_DIM and that is the
// dimension of the binary-operator disposition matrices and unary-operator
// disposition vectors.
//
@ -45,38 +45,43 @@
// ('s') to anything else ('x').
// ================================================================
package types
package bifs
import (
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
// Function-pointer type for zary functions.
type ZaryFunc func() *Mlrval
type ZaryFunc func() *mlrval.Mlrval
// Function-pointer type for unary-operator disposition vectors.
type UnaryFunc func(input1 *Mlrval) *Mlrval
type UnaryFunc func(input1 *mlrval.Mlrval) *mlrval.Mlrval
// The asserting_{type} need access to the context to say things like 'Assertion ... failed
// at filename {FILENAME} record number {NR}'.
type UnaryFuncWithContext func(input1 *Mlrval, context *Context) *Mlrval
type UnaryFuncWithContext func(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval
// Returns nil, or one-up captures array as array slots 1..9 of 10-element
// array for "\1".."\9".
type RegexCaptureBinaryFunc func(input *Mlrval, sregex *Mlrval) (*Mlrval, []string)
type RegexCaptureBinaryFunc func(input *mlrval.Mlrval, sregex *mlrval.Mlrval) (*mlrval.Mlrval, []string)
// Helps keystroke-saving for wrapping Go math-library functions
// Examples: cos, sin, etc.
type mathLibUnaryFunc func(float64) float64
type mathLibUnaryFuncWrapper func(input1 *Mlrval, f mathLibUnaryFunc) *Mlrval
type mathLibUnaryFuncWrapper func(input1 *mlrval.Mlrval, f mathLibUnaryFunc) *mlrval.Mlrval
// Function-pointer type for binary-operator disposition matrices.
type BinaryFunc func(input1, input2 *Mlrval) *Mlrval
type BinaryFunc func(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// Function-pointer type for ternary functions
type TernaryFunc func(input1, input2, input3 *Mlrval) *Mlrval
type TernaryFunc func(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval
// Function-pointer type for variadic functions.
type VariadicFunc func(inputs []*Mlrval) *Mlrval
type VariadicFunc func(inputs []*mlrval.Mlrval) *mlrval.Mlrval
// Function-pointer type for sorting. Returns < 0 if a < b, 0 if a == b, > 0 if a > b.
type ComparatorFunc func(*Mlrval, *Mlrval) int
type ComparatorFunc func(*mlrval.Mlrval, *mlrval.Mlrval) int
// ================================================================
// The following are frequently used in disposition matrices for various
@ -86,102 +91,102 @@ type ComparatorFunc func(*Mlrval, *Mlrval) int
// ----------------------------------------------------------------
// Return error (unary)
func _erro1(input1 *Mlrval) *Mlrval {
return MLRVAL_ERROR
func _erro1(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.ERROR
}
// Return absent (unary)
func _absn1(input1 *Mlrval) *Mlrval {
return MLRVAL_ABSENT
func _absn1(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.ABSENT
}
// Return zero (unary)
func _zero1(input1 *Mlrval) *Mlrval {
return MlrvalFromInt(0)
func _zero1(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(0)
}
// Return null (unary)
func _null1(input1 *Mlrval) *Mlrval {
return MLRVAL_NULL
func _null1(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.NULL
}
// Return void (unary)
func _void1(input1 *Mlrval) *Mlrval {
return MLRVAL_VOID
func _void1(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.VOID
}
// Return argument (unary)
func _1u___(input1 *Mlrval) *Mlrval {
func _1u___(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return input1
}
// ----------------------------------------------------------------
// Return error (binary)
func _erro(input1, input2 *Mlrval) *Mlrval {
return MLRVAL_ERROR
func _erro(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.ERROR
}
// Return absent (binary)
func _absn(input1, input2 *Mlrval) *Mlrval {
return MLRVAL_ABSENT
func _absn(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.ABSENT
}
// Return null (binary)
func _null(input1, input2 *Mlrval) *Mlrval {
return MLRVAL_NULL
func _null(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.NULL
}
// Return void (binary)
func _void(input1, input2 *Mlrval) *Mlrval {
return MLRVAL_VOID
func _void(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.VOID
}
// Return 0 (binary)
func _zero2(input1 *Mlrval) *Mlrval {
return MlrvalFromInt(0)
func _zero2(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(0)
}
// Return first argument (binary)
func _1___(input1, input2 *Mlrval) *Mlrval {
func _1___(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return input1
}
// Return second argument (binary)
func _2___(input1, input2 *Mlrval) *Mlrval {
func _2___(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return input2
}
// Return negative second argument (binary)
func _n2__(input1, input2 *Mlrval) *Mlrval {
func _n2__(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return BIF_minus_unary(input2)
}
// Return first argument, as string (binary)
func _s1__(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromString(input1.String())
func _s1__(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromString(input1.String())
}
// Return second argument, as string (binary)
func _s2__(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromString(input2.String())
func _s2__(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromString(input2.String())
}
// Return integer zero (binary)
func _i0__(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromInt(0)
func _i0__(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(0)
}
// Return float zero (binary)
func _f0__(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromFloat64(0)
func _f0__(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(0)
}
// Return boolean true (binary)
func _true(input1, input2 *Mlrval) *Mlrval {
return MLRVAL_TRUE
func _true(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.TRUE
}
// Return boolean false (binary)
func _fals(input1, input2 *Mlrval) *Mlrval {
return MLRVAL_FALSE
func _fals(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FALSE
}

View file

@ -1,13 +1,17 @@
package types
package bifs
import (
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// ================================================================
// Bitwise NOT
func bitwise_not_i_i(input1 *Mlrval) *Mlrval {
return MlrvalFromInt(^input1.intval)
func bitwise_not_i_i(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(^input1.AcquireIntValue())
}
var bitwise_not_dispositions = [MT_DIM]UnaryFunc{
var bitwise_not_dispositions = [mlrval.MT_DIM]UnaryFunc{
/*ERROR */ _erro1,
/*ABSENT */ _absn1,
/*NULL */ _null1,
@ -21,8 +25,8 @@ var bitwise_not_dispositions = [MT_DIM]UnaryFunc{
/*FUNC */ _erro1,
}
func BIF_bitwise_not(input1 *Mlrval) *Mlrval {
return bitwise_not_dispositions[input1.mvtype](input1)
func BIF_bitwise_not(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return bitwise_not_dispositions[input1.Type()](input1)
}
// ================================================================
@ -36,18 +40,18 @@ const _m08 uint64 = 0x00ff00ff00ff00ff
const _m16 uint64 = 0x0000ffff0000ffff
const _m32 uint64 = 0x00000000ffffffff
func bitcount_i_i(input1 *Mlrval) *Mlrval {
a := uint64(input1.intval)
func bitcount_i_i(input1 *mlrval.Mlrval) *mlrval.Mlrval {
a := uint64(input1.AcquireIntValue())
a = (a & _m01) + ((a >> 1) & _m01)
a = (a & _m02) + ((a >> 2) & _m02)
a = (a & _m04) + ((a >> 4) & _m04)
a = (a & _m08) + ((a >> 8) & _m08)
a = (a & _m16) + ((a >> 16) & _m16)
a = (a & _m32) + ((a >> 32) & _m32)
return MlrvalFromInt(int(a))
return mlrval.FromInt(int(a))
}
var bitcount_dispositions = [MT_DIM]UnaryFunc{
var bitcount_dispositions = [mlrval.MT_DIM]UnaryFunc{
/*ERROR */ _erro1,
/*ABSENT */ _absn1,
/*NULL */ _zero1,
@ -61,18 +65,18 @@ var bitcount_dispositions = [MT_DIM]UnaryFunc{
/*FUNC */ _erro1,
}
func BIF_bitcount(input1 *Mlrval) *Mlrval {
return bitcount_dispositions[input1.mvtype](input1)
func BIF_bitcount(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return bitcount_dispositions[input1.Type()](input1)
}
// ================================================================
// Bitwise AND
func bitwise_and_i_ii(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromInt(input1.intval & input2.intval)
func bitwise_and_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(input1.AcquireIntValue() & input2.AcquireIntValue())
}
var bitwise_and_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var bitwise_and_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _erro, _erro, _absn, _absn, _erro},
@ -87,18 +91,18 @@ var bitwise_and_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_bitwise_and(input1, input2 *Mlrval) *Mlrval {
return bitwise_and_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_bitwise_and(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return bitwise_and_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ----------------------------------------------------------------
// Bitwise OR
func bitwise_or_i_ii(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromInt(input1.intval | input2.intval)
func bitwise_or_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(input1.AcquireIntValue() | input2.AcquireIntValue())
}
var bitwise_or_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var bitwise_or_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _erro, _erro, _absn, _absn, _erro},
@ -113,18 +117,18 @@ var bitwise_or_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_bitwise_or(input1, input2 *Mlrval) *Mlrval {
return bitwise_or_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_bitwise_or(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return bitwise_or_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ----------------------------------------------------------------
// Bitwise XOR
func bitwise_xor_i_ii(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromInt(input1.intval ^ input2.intval)
func bitwise_xor_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(input1.AcquireIntValue() ^ input2.AcquireIntValue())
}
var bitwise_xor_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var bitwise_xor_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _erro, _erro, _absn, _absn, _erro},
@ -139,18 +143,18 @@ var bitwise_xor_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_bitwise_xor(input1, input2 *Mlrval) *Mlrval {
return bitwise_xor_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_bitwise_xor(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return bitwise_xor_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ----------------------------------------------------------------
// Left shift
func lsh_i_ii(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromInt(input1.intval << uint64(input2.intval))
func lsh_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(input1.AcquireIntValue() << uint64(input2.AcquireIntValue()))
}
var left_shift_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var left_shift_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _erro, _erro, _absn, _absn, _erro},
@ -165,18 +169,18 @@ var left_shift_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_left_shift(input1, input2 *Mlrval) *Mlrval {
return left_shift_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_left_shift(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return left_shift_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ----------------------------------------------------------------
// Signed right shift
func srsh_i_ii(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromInt(input1.intval >> uint64(input2.intval))
func srsh_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(input1.AcquireIntValue() >> uint64(input2.AcquireIntValue()))
}
var signed_right_shift_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var signed_right_shift_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _erro, _erro, _absn, _absn, _erro},
@ -191,21 +195,21 @@ var signed_right_shift_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_signed_right_shift(input1, input2 *Mlrval) *Mlrval {
return signed_right_shift_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_signed_right_shift(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return signed_right_shift_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ----------------------------------------------------------------
// Unsigned right shift
func ursh_i_ii(input1, input2 *Mlrval) *Mlrval {
var ua uint64 = uint64(input1.intval)
var ub uint64 = uint64(input2.intval)
func ursh_i_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var ua uint64 = uint64(input1.AcquireIntValue())
var ub uint64 = uint64(input2.AcquireIntValue())
var uc = ua >> ub
return MlrvalFromInt(int(uc))
return mlrval.FromInt(int(uc))
}
var unsigned_right_shift_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var unsigned_right_shift_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _2___, _erro, _erro, _absn, _absn, _erro},
@ -220,6 +224,6 @@ var unsigned_right_shift_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_unsigned_right_shift(input1, input2 *Mlrval) *Mlrval {
return unsigned_right_shift_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_unsigned_right_shift(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return unsigned_right_shift_dispositions[input1.Type()][input2.Type()](input1, input2)
}

View file

@ -0,0 +1,19 @@
package bifs
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
func TestBIF_bitcount(t *testing.T) {
input1 := mlrval.FromDeferredType("0xcafe")
output := BIF_bitcount(input1)
intval, ok := output.GetIntValue()
assert.True(t, ok)
assert.Equal(t, 11, intval)
}
// TODO: copy in more unit-test cases from existing regression-test data

View file

@ -0,0 +1,480 @@
// ================================================================
// Boolean expressions for ==, !=, >, >=, <, <=
// ================================================================
package bifs
import (
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// string_cmp implements the spaceship operator for strings.
func string_cmp(a, b string) int {
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}
// int_cmp implements the spaceship operator for ints.
func int_cmp(a, b int) int {
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}
// float_cmp implements the spaceship operator for floats.
func float_cmp(a, b float64) int {
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_ss(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() == input2.AcquireStringValue())
}
func ne_b_ss(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() != input2.AcquireStringValue())
}
func gt_b_ss(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() > input2.AcquireStringValue())
}
func ge_b_ss(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() >= input2.AcquireStringValue())
}
func lt_b_ss(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() < input2.AcquireStringValue())
}
func le_b_ss(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() <= input2.AcquireStringValue())
}
func cmp_b_ss(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(string_cmp(input1.AcquireStringValue(), input2.AcquireStringValue()))
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_xs(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.String() == input2.AcquireStringValue())
}
func ne_b_xs(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.String() != input2.AcquireStringValue())
}
func gt_b_xs(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.String() > input2.AcquireStringValue())
}
func ge_b_xs(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.String() >= input2.AcquireStringValue())
}
func lt_b_xs(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.String() < input2.AcquireStringValue())
}
func le_b_xs(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.String() <= input2.AcquireStringValue())
}
func cmp_b_xs(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(string_cmp(input1.String(), input2.AcquireStringValue()))
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_sx(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() == input2.String())
}
func ne_b_sx(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() != input2.String())
}
func gt_b_sx(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() > input2.String())
}
func ge_b_sx(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() >= input2.String())
}
func lt_b_sx(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() < input2.String())
}
func le_b_sx(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireStringValue() <= input2.String())
}
func cmp_b_sx(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(string_cmp(input1.AcquireStringValue(), input2.String()))
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireIntValue() == input2.AcquireIntValue())
}
func ne_b_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireIntValue() != input2.AcquireIntValue())
}
func gt_b_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireIntValue() > input2.AcquireIntValue())
}
func ge_b_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireIntValue() >= input2.AcquireIntValue())
}
func lt_b_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireIntValue() < input2.AcquireIntValue())
}
func le_b_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireIntValue() <= input2.AcquireIntValue())
}
func cmp_b_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(int_cmp(input1.AcquireIntValue(), input2.AcquireIntValue()))
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(float64(input1.AcquireIntValue()) == input2.AcquireFloatValue())
}
func ne_b_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(float64(input1.AcquireIntValue()) != input2.AcquireFloatValue())
}
func gt_b_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(float64(input1.AcquireIntValue()) > input2.AcquireFloatValue())
}
func ge_b_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(float64(input1.AcquireIntValue()) >= input2.AcquireFloatValue())
}
func lt_b_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(float64(input1.AcquireIntValue()) < input2.AcquireFloatValue())
}
func le_b_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(float64(input1.AcquireIntValue()) <= input2.AcquireFloatValue())
}
func cmp_b_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(float_cmp(float64(input1.AcquireIntValue()), input2.AcquireFloatValue()))
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() == float64(input2.AcquireIntValue()))
}
func ne_b_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() != float64(input2.AcquireIntValue()))
}
func gt_b_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() > float64(input2.AcquireIntValue()))
}
func ge_b_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() >= float64(input2.AcquireIntValue()))
}
func lt_b_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() < float64(input2.AcquireIntValue()))
}
func le_b_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() <= float64(input2.AcquireIntValue()))
}
func cmp_b_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(float_cmp(input1.AcquireFloatValue(), float64(input2.AcquireIntValue())))
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() == input2.AcquireFloatValue())
}
func ne_b_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() != input2.AcquireFloatValue())
}
func gt_b_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() > input2.AcquireFloatValue())
}
func ge_b_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() >= input2.AcquireFloatValue())
}
func lt_b_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() < input2.AcquireFloatValue())
}
func le_b_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() <= input2.AcquireFloatValue())
}
func cmp_b_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(float_cmp(input1.AcquireFloatValue(), input2.AcquireFloatValue()))
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_bb(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireBoolValue() == input2.AcquireBoolValue())
}
func ne_b_bb(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireBoolValue() != input2.AcquireBoolValue())
}
// We could say ordering on bool is error, but, Miller allows
// sorting on bool so it should allow ordering on bool.
func gt_b_bb(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(lib.BoolToInt(input1.AcquireBoolValue()) > lib.BoolToInt(input2.AcquireBoolValue()))
}
func ge_b_bb(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(lib.BoolToInt(input1.AcquireBoolValue()) >= lib.BoolToInt(input2.AcquireBoolValue()))
}
func lt_b_bb(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(lib.BoolToInt(input1.AcquireBoolValue()) < lib.BoolToInt(input2.AcquireBoolValue()))
}
func le_b_bb(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(lib.BoolToInt(input1.AcquireBoolValue()) <= lib.BoolToInt(input2.AcquireBoolValue()))
}
func cmp_b_bb(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(int_cmp(lib.BoolToInt(input1.AcquireBoolValue()), lib.BoolToInt(input2.AcquireBoolValue())))
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_aa(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
a := input1.AcquireArrayValue()
b := input2.AcquireArrayValue()
// Different-length arrays are not equal
if len(a) != len(b) {
return mlrval.FALSE
}
// Same-length arrays: return false if any slot is not equal, else true.
for i := range a {
eq := BIF_equals(&a[i], &b[i])
lib.InternalCodingErrorIf(eq.Type() != mlrval.MT_BOOL)
if eq.AcquireBoolValue() == false {
return mlrval.FALSE
}
}
return mlrval.TRUE
}
func ne_b_aa(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
output := eq_b_aa(input1, input2)
return mlrval.FromBool(!output.AcquireBoolValue())
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_mm(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireMapValue().Equals(input2.AcquireMapValue()))
}
func ne_b_mm(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(!input1.AcquireMapValue().Equals(input2.AcquireMapValue()))
}
// We get a Golang "initialization loop" due to recursive depth computation
// if this is defined statically. So, we use a "package init" function.
var eq_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{}
func init() {
eq_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*NULL */ {_erro, _absn, _true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _erro},
/*VOID */ {_erro, _absn, _fals, eq_b_ss, eq_b_ss, eq_b_sx, eq_b_sx, _fals, _fals, _fals, _erro},
/*STRING */ {_erro, _absn, _fals, eq_b_ss, eq_b_ss, eq_b_sx, eq_b_sx, _fals, _fals, _fals, _erro},
/*INT */ {_erro, _absn, _fals, eq_b_xs, eq_b_xs, eq_b_ii, eq_b_if, _fals, _fals, _fals, _erro},
/*FLOAT */ {_erro, _absn, _fals, eq_b_xs, eq_b_xs, eq_b_fi, eq_b_ff, _fals, _fals, _fals, _erro},
/*BOOL */ {_erro, _absn, _fals, _fals, _fals, _fals, _fals, eq_b_bb, _fals, _fals, _erro},
/*ARRAY */ {_erro, _absn, _fals, _fals, _fals, _fals, _fals, _fals, eq_b_aa, _fals, _erro},
/*MAP */ {_erro, _absn, _fals, _fals, _fals, _fals, _fals, _fals, _fals, eq_b_mm, _erro},
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
}
var ne_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*NULL */ {_erro, _absn, _fals, _true, _true, _true, _true, _true, _true, _true, _erro},
/*VOID */ {_erro, _absn, _true, ne_b_ss, ne_b_ss, ne_b_sx, ne_b_sx, _true, _true, _true, _erro},
/*STRING */ {_erro, _absn, _true, ne_b_ss, ne_b_ss, ne_b_sx, ne_b_sx, _true, _true, _true, _erro},
/*INT */ {_erro, _absn, _true, ne_b_xs, ne_b_xs, ne_b_ii, ne_b_if, _true, _true, _true, _erro},
/*FLOAT */ {_erro, _absn, _true, ne_b_xs, ne_b_xs, ne_b_fi, ne_b_ff, _true, _true, _true, _erro},
/*BOOL */ {_erro, _absn, _true, _true, _true, _true, _true, ne_b_bb, _true, _true, _erro},
/*ARRAY */ {_erro, _absn, _true, _true, _true, _true, _true, _true, ne_b_aa, _true, _erro},
/*MAP */ {_erro, _absn, _true, _true, _true, _true, _true, _true, _true, ne_b_mm, _erro},
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
var gt_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _fals, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
/*ABSENT */ {_erro, _absn, _true, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*NULL */ {_true, _fals, _fals, _true, _true, _true, _true, _true, _absn, _absn, _erro},
/*VOID */ {_erro, _absn, _fals, gt_b_ss, gt_b_ss, gt_b_sx, gt_b_sx, _fals, _fals, _fals, _erro},
/*STRING */ {_erro, _absn, _fals, gt_b_ss, gt_b_ss, gt_b_sx, gt_b_sx, _fals, _fals, _fals, _erro},
/*INT */ {_erro, _absn, _fals, gt_b_xs, gt_b_xs, gt_b_ii, gt_b_if, _fals, _fals, _fals, _erro},
/*FLOAT */ {_erro, _absn, _fals, gt_b_xs, gt_b_xs, gt_b_fi, gt_b_ff, _fals, _fals, _fals, _erro},
/*BOOL */ {_erro, _absn, _fals, _fals, _fals, _fals, _fals, gt_b_bb, _fals, _fals, _erro},
/*ARRAY */ {_erro, _absn, _fals, _fals, _fals, _fals, _fals, _fals, _erro, _fals, _erro},
/*MAP */ {_erro, _absn, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _erro, _erro},
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
var ge_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _fals, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
/*ABSENT */ {_erro, _absn, _true, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*NULL */ {_true, _fals, _true, _true, _true, _true, _true, _true, _absn, _absn, _erro},
/*VOID */ {_erro, _absn, _fals, ge_b_ss, ge_b_ss, ge_b_sx, ge_b_sx, _fals, _fals, _fals, _erro},
/*STRING */ {_erro, _absn, _fals, ge_b_ss, ge_b_ss, ge_b_sx, ge_b_sx, _fals, _fals, _fals, _erro},
/*INT */ {_erro, _absn, _fals, ge_b_xs, ge_b_xs, ge_b_ii, ge_b_if, _fals, _fals, _fals, _erro},
/*FLOAT */ {_erro, _absn, _fals, ge_b_xs, ge_b_xs, ge_b_fi, ge_b_ff, _fals, _fals, _fals, _erro},
/*BOOL */ {_erro, _absn, _fals, _fals, _fals, _fals, _fals, ge_b_bb, _fals, _fals, _erro},
/*ARRAY */ {_erro, _absn, _fals, _fals, _fals, _fals, _fals, _fals, _erro, _fals, _erro},
/*MAP */ {_erro, _absn, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _erro, _erro},
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
var lt_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _true, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
/*ABSENT */ {_erro, _absn, _fals, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*NULL */ {_fals, _true, _fals, _fals, _fals, _fals, _fals, _fals, _absn, _absn, _erro},
/*VOID */ {_erro, _absn, _true, lt_b_ss, lt_b_ss, lt_b_sx, lt_b_sx, _fals, _fals, _fals, _erro},
/*STRING */ {_erro, _absn, _true, lt_b_ss, lt_b_ss, lt_b_sx, lt_b_sx, _fals, _fals, _fals, _erro},
/*INT */ {_erro, _absn, _true, lt_b_xs, lt_b_xs, lt_b_ii, lt_b_if, _fals, _fals, _fals, _erro},
/*FLOAT */ {_erro, _absn, _true, lt_b_xs, lt_b_xs, lt_b_fi, lt_b_ff, _fals, _fals, _fals, _erro},
/*BOOL */ {_erro, _absn, _true, _fals, _fals, _fals, _fals, lt_b_bb, _fals, _fals, _erro},
/*ARRAY */ {_erro, _absn, _absn, _fals, _fals, _fals, _fals, _fals, _erro, _fals, _erro},
/*MAP */ {_erro, _absn, _absn, _fals, _fals, _fals, _fals, _fals, _fals, _erro, _erro},
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
var le_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _true, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
/*ABSENT */ {_erro, _absn, _fals, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*NULL */ {_fals, _true, _true, _fals, _fals, _fals, _fals, _fals, _absn, _absn, _erro},
/*VOID */ {_erro, _absn, _true, le_b_ss, le_b_ss, le_b_sx, le_b_sx, _fals, _fals, _fals, _erro},
/*STRING */ {_erro, _absn, _true, le_b_ss, le_b_ss, le_b_sx, le_b_sx, _fals, _fals, _fals, _erro},
/*INT */ {_erro, _absn, _true, le_b_xs, le_b_xs, le_b_ii, le_b_if, _fals, _fals, _fals, _erro},
/*FLOAT */ {_erro, _absn, _true, le_b_xs, le_b_xs, le_b_fi, le_b_ff, _fals, _fals, _fals, _erro},
/*BOOL */ {_erro, _absn, _true, _fals, _fals, _fals, _fals, le_b_bb, _fals, _fals, _erro},
/*ARRAY */ {_erro, _absn, _absn, _fals, _fals, _fals, _fals, _fals, _erro, _fals, _erro},
/*MAP */ {_erro, _absn, _absn, _fals, _fals, _fals, _fals, _fals, _fals, _erro, _erro},
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
var cmp_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _true, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
/*ABSENT */ {_erro, _absn, _fals, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*NULL */ {_fals, _true, _true, _fals, _fals, _fals, _fals, _fals, _absn, _absn, _erro},
/*VOID */ {_erro, _absn, _true, cmp_b_ss, cmp_b_ss, cmp_b_sx, cmp_b_sx, _fals, _fals, _fals, _erro},
/*STRING */ {_erro, _absn, _true, cmp_b_ss, cmp_b_ss, cmp_b_sx, cmp_b_sx, _fals, _fals, _fals, _erro},
/*INT */ {_erro, _absn, _true, cmp_b_xs, cmp_b_xs, cmp_b_ii, cmp_b_if, _fals, _fals, _fals, _erro},
/*FLOAT */ {_erro, _absn, _true, cmp_b_xs, cmp_b_xs, cmp_b_fi, cmp_b_ff, _fals, _fals, _fals, _erro},
/*BOOL */ {_erro, _absn, _true, _fals, _fals, _fals, _fals, cmp_b_bb, _fals, _fals, _erro},
/*ARRAY */ {_erro, _absn, _absn, _fals, _fals, _fals, _fals, _fals, _erro, _fals, _erro},
/*MAP */ {_erro, _absn, _absn, _fals, _fals, _fals, _fals, _fals, _fals, _erro, _erro},
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_equals(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return eq_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func BIF_not_equals(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return ne_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func BIF_greater_than(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return gt_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func BIF_greater_than_or_equals(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return ge_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func BIF_less_than(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return lt_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func BIF_less_than_or_equals(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return le_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func BIF_cmp(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return cmp_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// For Go's sort.Slice.
func BIF_less_than_as_bool(input1, input2 *mlrval.Mlrval) bool {
// TODO refactor to avoid copy
// This is a hot path for sort GC and is worth significant hand-optimization
mretval := lt_dispositions[input1.Type()][input2.Type()](input1, input2)
retval, ok := mretval.GetBoolValue()
lib.InternalCodingErrorIf(!ok)
return retval
}
// For Go's sort.Slice.
func BIF_less_than_or_equals_as_bool(input1, input2 *mlrval.Mlrval) bool {
// TODO refactor to avoid copy
// This is a hot path for sort GC and is worth significant hand-optimization
mretval := le_dispositions[input1.Type()][input2.Type()](input1, input2)
retval, ok := mretval.GetBoolValue()
lib.InternalCodingErrorIf(!ok)
return retval
}
// For top-keeper
func BIF_greater_than_as_bool(input1, input2 *mlrval.Mlrval) bool {
// TODO refactor to avoid copy
// This is a hot path for sort GC and is worth significant hand-optimization
mretval := gt_dispositions[input1.Type()][input2.Type()](input1, input2)
retval, ok := mretval.GetBoolValue()
lib.InternalCodingErrorIf(!ok)
return retval
}
// For top-keeper
func BIF_greater_than_or_equals_as_bool(input1, input2 *mlrval.Mlrval) bool {
// TODO refactor to avoid copy
// This is a hot path for sort GC and is worth significant hand-optimization
mretval := ge_dispositions[input1.Type()][input2.Type()](input1, input2)
retval, ok := mretval.GetBoolValue()
lib.InternalCodingErrorIf(!ok)
return retval
}
// Convenience wrapper for non-DSL callsites that just want a bool
func BIF_equals_as_bool(input1, input2 *mlrval.Mlrval) bool {
mretval := eq_dispositions[input1.Type()][input2.Type()](input1, input2)
retval, ok := mretval.GetBoolValue()
lib.InternalCodingErrorIf(!ok)
return retval
}
// ----------------------------------------------------------------
func BIF_logical_NOT(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsBool() {
return mlrval.FromBool(!input1.AcquireBoolValue())
} else {
return mlrval.ERROR
}
}
func BIF_logical_AND(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsBool() && input2.IsBool() {
return mlrval.FromBool(input1.AcquireBoolValue() && input2.AcquireBoolValue())
} else {
return mlrval.ERROR
}
}
func BIF_logical_OR(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsBool() && input2.IsBool() {
return mlrval.FromBool(input1.AcquireBoolValue() || input2.AcquireBoolValue())
} else {
return mlrval.ERROR
}
}
func BIF_logical_XOR(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsBool() && input2.IsBool() {
return mlrval.FromBool(input1.AcquireBoolValue() != input2.AcquireBoolValue())
} else {
return mlrval.ERROR
}
}

View file

@ -0,0 +1,852 @@
package bifs
import (
"bytes"
"strconv"
"strings"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// ================================================================
// Map/array count. Scalars (including strings) have length 1; strlen is for string length.
func BIF_length(input1 *mlrval.Mlrval) *mlrval.Mlrval {
switch input1.Type() {
case mlrval.MT_ERROR:
return mlrval.FromInt(0)
break
case mlrval.MT_ABSENT:
return mlrval.FromInt(0)
break
case mlrval.MT_ARRAY:
arrayval := input1.AcquireArrayValue()
return mlrval.FromInt(int(len(arrayval)))
break
case mlrval.MT_MAP:
mapval := input1.AcquireMapValue()
return mlrval.FromInt(int(mapval.FieldCount))
break
}
return mlrval.FromInt(1)
}
// ================================================================
func depth_from_array(input1 *mlrval.Mlrval) *mlrval.Mlrval {
maxChildDepth := 0
arrayval := input1.AcquireArrayValue()
for _, child := range arrayval {
childDepth := BIF_depth(&child)
lib.InternalCodingErrorIf(!childDepth.IsInt())
iChildDepth := int(childDepth.AcquireIntValue())
if iChildDepth > maxChildDepth {
maxChildDepth = iChildDepth
}
}
return mlrval.FromInt(int(1 + maxChildDepth))
}
func depth_from_map(input1 *mlrval.Mlrval) *mlrval.Mlrval {
maxChildDepth := 0
mapval := input1.AcquireMapValue()
for pe := mapval.Head; pe != nil; pe = pe.Next {
child := pe.Value
childDepth := BIF_depth(child)
lib.InternalCodingErrorIf(!childDepth.IsInt())
iChildDepth := int(childDepth.AcquireIntValue())
if iChildDepth > maxChildDepth {
maxChildDepth = iChildDepth
}
}
return mlrval.FromInt(int(1 + maxChildDepth))
}
func depth_from_scalar(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(0)
}
// We get a Golang "initialization loop" due to recursive depth computation
// if this is defined statically. So, we use a "package init" function.
var depth_dispositions = [mlrval.MT_DIM]UnaryFunc{}
func init() {
depth_dispositions = [mlrval.MT_DIM]UnaryFunc{
/*ERROR */ _erro1,
/*ABSENT */ _absn1,
/*NULL */ _zero1,
/*VOID */ depth_from_scalar,
/*STRING */ depth_from_scalar,
/*INT */ depth_from_scalar,
/*FLOAT */ depth_from_scalar,
/*BOOL */ depth_from_scalar,
/*ARRAY */ depth_from_array,
/*MAP */ depth_from_map,
/*FUNC */ _erro1,
}
}
func BIF_depth(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return depth_dispositions[input1.Type()](input1)
}
// ================================================================
func leafcount_from_array(input1 *mlrval.Mlrval) *mlrval.Mlrval {
sumChildLeafCount := 0
arrayval := input1.AcquireArrayValue()
for _, child := range arrayval {
// Golang initialization loop if we do this :(
// childLeafCount := BIF_leafcount(&child)
childLeafCount := mlrval.FromInt(1)
if child.IsArray() {
childLeafCount = leafcount_from_array(&child)
} else if child.IsMap() {
childLeafCount = leafcount_from_map(&child)
}
lib.InternalCodingErrorIf(!childLeafCount.IsInt())
iChildLeafCount := int(childLeafCount.AcquireIntValue())
sumChildLeafCount += iChildLeafCount
}
return mlrval.FromInt(int(sumChildLeafCount))
}
func leafcount_from_map(input1 *mlrval.Mlrval) *mlrval.Mlrval {
sumChildLeafCount := 0
mapval := input1.AcquireMapValue()
for pe := mapval.Head; pe != nil; pe = pe.Next {
child := pe.Value
// Golang initialization loop if we do this :(
// childLeafCount := BIF_leafcount(child)
childLeafCount := mlrval.FromInt(1)
if child.IsArray() {
childLeafCount = leafcount_from_array(child)
} else if child.IsMap() {
childLeafCount = leafcount_from_map(child)
}
lib.InternalCodingErrorIf(!childLeafCount.IsInt())
iChildLeafCount := int(childLeafCount.AcquireIntValue())
sumChildLeafCount += iChildLeafCount
}
return mlrval.FromInt(int(sumChildLeafCount))
}
func leafcount_from_scalar(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(1)
}
var leafcount_dispositions = [mlrval.MT_DIM]UnaryFunc{
/*ERROR */ _erro1,
/*ABSENT */ _absn1,
/*NULL */ _zero1,
/*VOID */ leafcount_from_scalar,
/*STRING */ leafcount_from_scalar,
/*INT */ leafcount_from_scalar,
/*FLOAT */ leafcount_from_scalar,
/*BOOL */ leafcount_from_scalar,
/*ARRAY */ leafcount_from_array,
/*MAP */ leafcount_from_map,
/*FUNC */ _erro1,
}
func BIF_leafcount(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return leafcount_dispositions[input1.Type()](input1)
}
// ----------------------------------------------------------------
func has_key_in_array(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if input2.IsString() {
return mlrval.FALSE
}
if !input2.IsInt() {
return mlrval.ERROR
}
arrayval := input1.AcquireArrayValue()
_, ok := unaliasArrayIndex(&arrayval, input2.AcquireIntValue())
return mlrval.FromBool(ok)
}
func has_key_in_map(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if input2.IsString() || input2.IsInt() {
return mlrval.FromBool(input1.AcquireMapValue().Has(input2.String()))
} else {
return mlrval.ERROR
}
}
func BIF_haskey(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsArray() {
return has_key_in_array(input1, input2)
} else if input1.IsMap() {
return has_key_in_map(input1, input2)
} else {
return mlrval.ERROR
}
}
// ================================================================
func BIF_mapselect(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval {
if len(mlrvals) < 1 {
return mlrval.ERROR
}
if !mlrvals[0].IsMap() {
return mlrval.ERROR
}
oldmap := mlrvals[0].AcquireMapValue()
newMap := mlrval.NewMlrmap()
newKeys := make(map[string]bool)
for _, selectArg := range mlrvals[1:] {
if selectArg.IsString() {
newKeys[selectArg.AcquireStringValue()] = true
} else if selectArg.IsInt() {
newKeys[selectArg.String()] = true
} else if selectArg.IsArray() {
for _, element := range selectArg.AcquireArrayValue() {
if element.IsString() {
newKeys[element.AcquireStringValue()] = true
} else {
return mlrval.ERROR
}
}
} else {
return mlrval.ERROR
}
}
for pe := oldmap.Head; pe != nil; pe = pe.Next {
oldKey := pe.Key
_, present := newKeys[oldKey]
if present {
newMap.PutCopy(oldKey, oldmap.Get(oldKey))
}
}
return mlrval.FromMap(newMap)
}
// ----------------------------------------------------------------
func BIF_mapexcept(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval {
if len(mlrvals) < 1 {
return mlrval.ERROR
}
if !mlrvals[0].IsMap() {
return mlrval.ERROR
}
newMap := mlrvals[0].AcquireMapValue().Copy()
for _, exceptArg := range mlrvals[1:] {
if exceptArg.IsString() {
newMap.Remove(exceptArg.AcquireStringValue())
} else if exceptArg.IsInt() {
newMap.Remove(exceptArg.String())
} else if exceptArg.IsArray() {
for _, element := range exceptArg.AcquireArrayValue() {
if element.IsString() {
newMap.Remove(element.AcquireStringValue())
} else {
return mlrval.ERROR
}
}
} else {
return mlrval.ERROR
}
}
return mlrval.FromMap(newMap)
}
// ----------------------------------------------------------------
func BIF_mapsum(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval {
if len(mlrvals) == 0 {
return mlrval.FromEmptyMap()
}
if len(mlrvals) == 1 {
return mlrvals[0]
}
if mlrvals[0].Type() != mlrval.MT_MAP {
return mlrval.ERROR
}
newMap := mlrvals[0].AcquireMapValue().Copy()
for _, otherMapArg := range mlrvals[1:] {
if otherMapArg.Type() != mlrval.MT_MAP {
return mlrval.ERROR
}
for pe := otherMapArg.AcquireMapValue().Head; pe != nil; pe = pe.Next {
newMap.PutCopy(pe.Key, pe.Value)
}
}
return mlrval.FromMap(newMap)
}
// ----------------------------------------------------------------
func BIF_mapdiff(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval {
if len(mlrvals) == 0 {
return mlrval.FromEmptyMap()
}
if len(mlrvals) == 1 {
return mlrvals[0]
}
if !mlrvals[0].IsMap() {
return mlrval.ERROR
}
newMap := mlrvals[0].AcquireMapValue().Copy()
for _, otherMapArg := range mlrvals[1:] {
if !otherMapArg.IsMap() {
return mlrval.ERROR
}
for pe := otherMapArg.AcquireMapValue().Head; pe != nil; pe = pe.Next {
newMap.Remove(pe.Key)
}
}
return mlrval.FromMap(newMap)
}
// ================================================================
// joink([1,2,3], ",") -> "1,2,3"
// joink({"a":3,"b":4,"c":5}, ",") -> "a,b,c"
func BIF_joink(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input2.IsString() {
return mlrval.ERROR
}
fieldSeparator := input2.AcquireStringValue()
if input1.IsMap() {
var buffer bytes.Buffer
for pe := input1.AcquireMapValue().Head; pe != nil; pe = pe.Next {
buffer.WriteString(pe.Key)
if pe.Next != nil {
buffer.WriteString(fieldSeparator)
}
}
return mlrval.FromString(buffer.String())
} else if input1.IsArray() {
var buffer bytes.Buffer
for i := range input1.AcquireArrayValue() {
if i > 0 {
buffer.WriteString(fieldSeparator)
}
// Miller userspace array indices are 1-up
buffer.WriteString(strconv.Itoa(i + 1))
}
return mlrval.FromString(buffer.String())
} else {
return mlrval.ERROR
}
}
// ----------------------------------------------------------------
// joinv([3,4,5], ",") -> "3,4,5"
// joinv({"a":3,"b":4,"c":5}, ",") -> "3,4,5"
func BIF_joinv(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input2.IsString() {
return mlrval.ERROR
}
fieldSeparator := input2.AcquireStringValue()
if input1.IsMap() {
var buffer bytes.Buffer
for pe := input1.AcquireMapValue().Head; pe != nil; pe = pe.Next {
buffer.WriteString(pe.Value.String())
if pe.Next != nil {
buffer.WriteString(fieldSeparator)
}
}
return mlrval.FromString(buffer.String())
} else if input1.IsArray() {
var buffer bytes.Buffer
for i, element := range input1.AcquireArrayValue() {
if i > 0 {
buffer.WriteString(fieldSeparator)
}
buffer.WriteString(element.String())
}
return mlrval.FromString(buffer.String())
} else {
return mlrval.ERROR
}
}
// ----------------------------------------------------------------
// joinkv([3,4,5], "=", ",") -> "1=3,2=4,3=5"
// joinkv({"a":3,"b":4,"c":5}, "=", ",") -> "a=3,b=4,c=5"
func BIF_joinkv(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if !input2.IsString() {
return mlrval.ERROR
}
pairSeparator := input2.AcquireStringValue()
if !input3.IsString() {
return mlrval.ERROR
}
fieldSeparator := input3.AcquireStringValue()
if input1.IsMap() {
var buffer bytes.Buffer
for pe := input1.AcquireMapValue().Head; pe != nil; pe = pe.Next {
buffer.WriteString(pe.Key)
buffer.WriteString(pairSeparator)
buffer.WriteString(pe.Value.String())
if pe.Next != nil {
buffer.WriteString(fieldSeparator)
}
}
return mlrval.FromString(buffer.String())
} else if input1.IsArray() {
var buffer bytes.Buffer
for i, element := range input1.AcquireArrayValue() {
if i > 0 {
buffer.WriteString(fieldSeparator)
}
// Miller userspace array indices are 1-up
buffer.WriteString(strconv.Itoa(i + 1))
buffer.WriteString(pairSeparator)
buffer.WriteString(element.String())
}
return mlrval.FromString(buffer.String())
} else {
return mlrval.ERROR
}
}
// ================================================================
// splitkv("a=3,b=4,c=5", "=", ",") -> {"a":3,"b":4,"c":5}
func BIF_splitkv(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return mlrval.ERROR
}
if !input2.IsString() {
return mlrval.ERROR
}
pairSeparator := input2.AcquireStringValue()
if !input3.IsString() {
return mlrval.ERROR
}
fieldSeparator := input3.AcquireStringValue()
output := mlrval.FromMap(mlrval.NewMlrmap())
fields := lib.SplitString(input1.AcquireStringValue(), fieldSeparator)
for i, field := range fields {
pair := strings.SplitN(field, pairSeparator, 2)
if len(pair) == 1 {
key := strconv.Itoa(i + 1) // Miller user-space indices are 1-up
value := mlrval.FromInferredType(pair[0])
output.AcquireMapValue().PutReference(key, value)
} else if len(pair) == 2 {
key := pair[0]
value := mlrval.FromInferredType(pair[1])
output.AcquireMapValue().PutReference(key, value)
} else {
lib.InternalCodingErrorIf(true)
}
}
return output
}
// ----------------------------------------------------------------
// splitkvx("a=3,b=4,c=5", "=", ",") -> {"a":"3","b":"4","c":"5"}
func BIF_splitkvx(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return mlrval.ERROR
}
if !input2.IsString() {
return mlrval.ERROR
}
pairSeparator := input2.AcquireStringValue()
if !input3.IsString() {
return mlrval.ERROR
}
fieldSeparator := input3.AcquireStringValue()
output := mlrval.FromMap(mlrval.NewMlrmap())
fields := lib.SplitString(input1.AcquireStringValue(), fieldSeparator)
for i, field := range fields {
pair := strings.SplitN(field, pairSeparator, 2)
if len(pair) == 1 {
key := strconv.Itoa(i + 1) // Miller user-space indices are 1-up
value := mlrval.FromString(pair[0])
output.AcquireMapValue().PutReference(key, value)
} else if len(pair) == 2 {
key := pair[0]
value := mlrval.FromString(pair[1])
output.AcquireMapValue().PutReference(key, value)
} else {
lib.InternalCodingErrorIf(true)
}
}
return output
}
// ----------------------------------------------------------------
// splitnv("a,b,c", ",") -> {"1":"a","2":"b","3":"c"}
func BIF_splitnv(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return mlrval.ERROR
}
if !input2.IsString() {
return mlrval.ERROR
}
output := mlrval.FromMap(mlrval.NewMlrmap())
fields := lib.SplitString(input1.AcquireStringValue(), input2.AcquireStringValue())
for i, field := range fields {
key := strconv.Itoa(i + 1) // Miller user-space indices are 1-up
value := mlrval.FromInferredType(field)
output.AcquireMapValue().PutReference(key, value)
}
return output
}
// ----------------------------------------------------------------
// splitnvx("3,4,5", ",") -> {"1":"3","2":"4","3":"5"}
func BIF_splitnvx(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return mlrval.ERROR
}
if !input2.IsString() {
return mlrval.ERROR
}
output := mlrval.FromMap(mlrval.NewMlrmap())
fields := lib.SplitString(input1.AcquireStringValue(), input2.AcquireStringValue())
for i, field := range fields {
key := strconv.Itoa(i + 1) // Miller user-space indices are 1-up
value := mlrval.FromString(field)
output.AcquireMapValue().PutReference(key, value)
}
return output
}
// ----------------------------------------------------------------
// splita("3,4,5", ",") -> [3,4,5]
func BIF_splita(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return mlrval.ERROR
}
if !input2.IsString() {
return mlrval.ERROR
}
fieldSeparator := input2.AcquireStringValue()
fields := lib.SplitString(input1.AcquireStringValue(), fieldSeparator)
arrayval := make([]mlrval.Mlrval, len(fields))
for i, field := range fields {
value := mlrval.FromInferredType(field)
arrayval[i] = *value
}
return mlrval.FromArray(arrayval)
}
// ----------------------------------------------------------------
// BIF_splitax splits a string to an array, without type-inference:
// e.g. splitax("3,4,5", ",") -> ["3","4","5"]
func BIF_splitax(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return mlrval.ERROR
}
if !input2.IsString() {
return mlrval.ERROR
}
input := input1.AcquireStringValue()
fieldSeparator := input2.AcquireStringValue()
return bif_splitax_helper(input, fieldSeparator)
}
// bif_splitax_helper is split out for the benefit of BIF_splitax and
// BIF_unflatten.
func bif_splitax_helper(input string, separator string) *mlrval.Mlrval {
fields := lib.SplitString(input, separator)
arrayval := make([]mlrval.Mlrval, len(fields))
for i, field := range fields {
arrayval[i] = *mlrval.FromString(field)
}
return mlrval.FromArray(arrayval)
}
// ----------------------------------------------------------------
func BIF_get_keys(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsMap() {
// TODO: make a ReferenceFrom with comments
mapval := input1.AcquireMapValue()
arrayval := make([]mlrval.Mlrval, mapval.FieldCount)
i := 0
for pe := mapval.Head; pe != nil; pe = pe.Next {
arrayval[i] = *mlrval.FromString(pe.Key)
i++
}
return mlrval.FromArray(arrayval)
} else if input1.IsArray() {
inputarrayval := input1.AcquireArrayValue()
arrayval := make([]mlrval.Mlrval, len(inputarrayval))
for i := range inputarrayval {
arrayval[i] = *mlrval.FromInt(int(i + 1)) // Miller user-space indices are 1-up
}
return mlrval.FromArray(arrayval)
} else {
return mlrval.ERROR
}
}
// ----------------------------------------------------------------
func BIF_get_values(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsMap() {
mapval := input1.AcquireMapValue()
arrayval := make([]mlrval.Mlrval, mapval.FieldCount)
i := 0
for pe := mapval.Head; pe != nil; pe = pe.Next {
arrayval[i] = *pe.Value.Copy()
i++
}
return mlrval.FromArray(arrayval)
} else if input1.IsArray() {
inputarrayval := input1.AcquireArrayValue()
arrayval := make([]mlrval.Mlrval, len(inputarrayval))
for i, value := range inputarrayval {
arrayval[i] = *value.Copy()
}
return mlrval.FromArray(arrayval)
} else {
return mlrval.ERROR
}
}
// ----------------------------------------------------------------
func BIF_append(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsArray() {
return mlrval.ERROR
}
output := input1.Copy()
output.ArrayAppend(input2.Copy())
return output
}
// ----------------------------------------------------------------
// First argumemnt is prefix.
// Second argument is delimiter.
// Third argument is map or array.
// flatten("a", ".", {"b": { "c": 4 }}) is {"a.b.c" : 4}.
// flatten("", ".", {"a": { "b": 3 }}) is {"a.b" : 3}.
func BIF_flatten(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if input3.IsMap() || input3.IsArray() {
if !input1.IsString() && input1.Type() != mlrval.MT_VOID {
return mlrval.ERROR
}
prefix := input1.AcquireStringValue()
if !input2.IsString() {
return mlrval.ERROR
}
delimiter := input2.AcquireStringValue()
retval := input3.FlattenToMap(prefix, delimiter)
return &retval
} else {
return input3
}
}
// flatten($*, ".") is the same as flatten("", ".", $*)
func BIF_flatten_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return BIF_flatten(mlrval.VOID, input2, input1)
}
// ----------------------------------------------------------------
// First argument is a map.
// Second argument is a delimiter string.
// unflatten({"a.b.c", ".") is {"a": { "b": { "c": 4}}}.
func BIF_unflatten(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input2.IsString() {
return mlrval.ERROR
}
if input1.Type() != mlrval.MT_MAP {
return input1
}
oldmap := input1.AcquireMapValue()
separator := input2.AcquireStringValue()
newmap := oldmap.CopyUnflattened(separator)
return mlrval.FromMap(newmap)
}
// ----------------------------------------------------------------
// Converts maps with "1", "2", ... keys into arrays. Recurses nested data structures.
func BIF_arrayify(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsMap() {
if input1.AcquireMapValue().IsEmpty() {
return input1
}
convertible := true
i := 0
for pe := input1.AcquireMapValue().Head; pe != nil; pe = pe.Next {
sval := strconv.Itoa(i + 1) // Miller user-space indices are 1-up
i++
if pe.Key != sval {
convertible = false
}
pe.Value = BIF_arrayify(pe.Value)
}
if convertible {
mapval := input1.AcquireMapValue()
arrayval := make([]mlrval.Mlrval, input1.AcquireMapValue().FieldCount)
i := 0
for pe := mapval.Head; pe != nil; pe = pe.Next {
arrayval[i] = *pe.Value.Copy()
i++
}
return mlrval.FromArray(arrayval)
} else {
return input1
}
} else if input1.IsArray() {
// TODO: comment (or rethink) that this modifies its inputs!!
output := input1.Copy()
for i := range input1.AcquireArrayValue() {
output.AcquireArrayValue()[i] = *BIF_arrayify(&output.AcquireArrayValue()[i])
}
return output
} else {
return input1
}
}
// ----------------------------------------------------------------
func BIF_json_parse(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsVoid() {
return input1
} else if !input1.IsString() {
return mlrval.ERROR
} else {
output := mlrval.FromPending()
err := output.UnmarshalJSON([]byte(input1.AcquireStringValue()))
if err != nil {
return mlrval.ERROR
}
return output
}
}
func BIF_json_stringify_unary(input1 *mlrval.Mlrval) *mlrval.Mlrval {
outputBytes, err := input1.MarshalJSON(mlrval.JSON_SINGLE_LINE, false)
if err != nil {
return mlrval.ERROR
} else {
return mlrval.FromString(string(outputBytes))
}
}
func BIF_json_stringify_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
var jsonFormatting mlrval.TJSONFormatting = mlrval.JSON_SINGLE_LINE
useMultiline, ok := input2.GetBoolValue()
if !ok {
return mlrval.ERROR
}
if useMultiline {
jsonFormatting = mlrval.JSON_MULTILINE
}
outputBytes, err := input1.MarshalJSON(jsonFormatting, false)
if err != nil {
return mlrval.ERROR
} else {
return mlrval.FromString(string(outputBytes))
}
}
func unaliasArrayIndex(array *[]mlrval.Mlrval, mindex int) (int, bool) {
n := int(len(*array))
return unaliasArrayLengthIndex(n, mindex)
}
// Input "mindex" is a Miller DSL array index. These are 1-up, so 1..n where n
// is the length of the array. Also, -n..-1 are aliases to 1..n. 0 is never a
// valid index.
//
// Output "zindex" is a Golang array index. These are 0-up, so 0..(n-1).
//
// The second return value indicates whether the Miller index is in-bounds.
// Even if it's out of bounds, while the second return value is false, the
// first return is correctly de-aliased. E.g. if the array has length 5 and the
// mindex is 8, zindex is 7 and valid=false. This is so in array-slice
// operations like 'v = myarray[2:8]' the callsite can hand back slots 2-5 of
// the array (which is the same way Python handles beyond-the-end indexing).
// Examples with n = 5:
//
// mindex zindex ok
// -7 -2 false
// -6 -1 false
// -5 0 true
// -4 1 true
// -3 2 true
// -2 3 true
// -1 4 true
// 0 -1 false
// 1 0 true
// 2 1 true
// 3 2 true
// 4 3 true
// 5 4 true
// 6 5 false
// 7 6 false
func unaliasArrayLengthIndex(n int, mindex int) (int, bool) {
if 1 <= mindex {
zindex := mindex - 1
if mindex <= n { // in bounds
return zindex, true
} else { // out of bounds
return zindex, false
}
} else if mindex <= -1 {
zindex := mindex + n
if -n <= mindex { // in bounds
return zindex, true
} else { // out of bounds
return zindex, false
}
} else {
// mindex is 0
return -1, false
}
}

View file

@ -0,0 +1,75 @@
package bifs
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
func TestBIF_length(t *testing.T) {
input1 := mlrval.FromInt(123)
output := BIF_length(input1)
intval, ok := output.GetIntValue()
assert.True(t, ok)
assert.Equal(t, 1, intval)
}
func TestBIF_depth(t *testing.T) {
input1 := mlrval.FromInt(123)
output := BIF_depth(input1)
intval, ok := output.GetIntValue()
assert.True(t, ok)
assert.Equal(t, 0, intval)
mapval := mlrval.NewMlrmap()
mapval.PutReference("key", mlrval.FromString("value"))
input1 = mlrval.FromMap(mapval)
output = BIF_depth(input1)
intval, ok = output.GetIntValue()
assert.True(t, ok)
assert.Equal(t, 1, intval)
arrayval := make([]mlrval.Mlrval, 1)
arrayval[0] = *mlrval.FromString("value")
input1 = mlrval.FromArray(arrayval)
output = BIF_depth(input1)
intval, ok = output.GetIntValue()
assert.True(t, ok)
assert.Equal(t, 1, intval)
}
// TODO: copy in more unit-test cases from existing regression-test data
// func leafcount_from_array(input1 *mlrval.Mlrval) *mlrval.Mlrval
// func leafcount_from_map(input1 *mlrval.Mlrval) *mlrval.Mlrval
// func leafcount_from_scalar(input1 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_leafcount(input1 *mlrval.Mlrval) *mlrval.Mlrval
// func has_key_in_array(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func has_key_in_map(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_haskey(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_mapselect(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval
// func BIF_mapexcept(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval
// func BIF_mapsum(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval
// func BIF_mapdiff(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval
// func BIF_joink(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_joinv(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_joinkv(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_splitkv(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_splitkvx(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_splitnv(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_splitnvx(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_splita(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_splitax(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func mlrvalSplitAXHelper(input string, separator string) *mlrval.Mlrval
// func BIF_get_keys(input1 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_get_values(input1 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_append(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_flatten(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_flatten_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_unflatten(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_arrayify(input1 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_json_parse(input1 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_json_stringify_unary(input1 *mlrval.Mlrval) *mlrval.Mlrval
// func BIF_json_stringify_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval

View file

@ -1,4 +1,4 @@
package types
package bifs
import (
"fmt"
@ -9,22 +9,23 @@ import (
"github.com/lestrrat-go/strftime"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
const ISO8601_TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
var ptr_ISO8601_TIME_FORMAT = MlrvalFromString("%Y-%m-%dT%H:%M:%SZ")
var ptr_ISO8601_LOCAL_TIME_FORMAT = MlrvalFromString("%Y-%m-%d %H:%M:%S")
var ptr_YMD_FORMAT = MlrvalFromString("%Y-%m-%d")
var ptr_ISO8601_TIME_FORMAT = mlrval.FromString("%Y-%m-%dT%H:%M:%SZ")
var ptr_ISO8601_LOCAL_TIME_FORMAT = mlrval.FromString("%Y-%m-%d %H:%M:%S")
var ptr_YMD_FORMAT = mlrval.FromString("%Y-%m-%d")
// ================================================================
func BIF_systime() *Mlrval {
return MlrvalFromFloat64(
func BIF_systime() *mlrval.Mlrval {
return mlrval.FromFloat(
float64(time.Now().UnixNano()) / 1.0e9,
)
}
func BIF_systimeint() *Mlrval {
return MlrvalFromInt(int(time.Now().Unix()))
func BIF_systimeint() *mlrval.Mlrval {
return mlrval.FromInt(int(time.Now().Unix()))
}
var startTime float64
@ -32,15 +33,15 @@ var startTime float64
func init() {
startTime = float64(time.Now().UnixNano()) / 1.0e9
}
func BIF_uptime() *Mlrval {
return MlrvalFromFloat64(
func BIF_uptime() *mlrval.Mlrval {
return mlrval.FromFloat(
float64(time.Now().UnixNano())/1.0e9 - startTime,
)
}
// ================================================================
func BIF_sec2gmt_unary(input1 *Mlrval) *Mlrval {
func BIF_sec2gmt_unary(input1 *mlrval.Mlrval) *mlrval.Mlrval {
floatValue, isNumeric := input1.GetNumericToFloatValue()
if !isNumeric {
return input1
@ -48,10 +49,10 @@ func BIF_sec2gmt_unary(input1 *Mlrval) *Mlrval {
numDecimalPlaces := 0
return MlrvalFromString(lib.Sec2GMT(floatValue, numDecimalPlaces))
return mlrval.FromString(lib.Sec2GMT(floatValue, numDecimalPlaces))
}
func BIF_sec2gmt_binary(input1, input2 *Mlrval) *Mlrval {
func BIF_sec2gmt_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
floatValue, isNumeric := input1.GetNumericToFloatValue()
if !isNumeric {
return input1
@ -59,13 +60,13 @@ func BIF_sec2gmt_binary(input1, input2 *Mlrval) *Mlrval {
numDecimalPlaces, isInt := input2.GetIntValue()
if !isInt {
return MLRVAL_ERROR
return mlrval.ERROR
}
return MlrvalFromString(lib.Sec2GMT(floatValue, numDecimalPlaces))
return mlrval.FromString(lib.Sec2GMT(floatValue, numDecimalPlaces))
}
func BIF_sec2localtime_unary(input1 *Mlrval) *Mlrval {
func BIF_sec2localtime_unary(input1 *mlrval.Mlrval) *mlrval.Mlrval {
floatValue, isNumeric := input1.GetNumericToFloatValue()
if !isNumeric {
return input1
@ -73,10 +74,10 @@ func BIF_sec2localtime_unary(input1 *Mlrval) *Mlrval {
numDecimalPlaces := 0
return MlrvalFromString(lib.Sec2LocalTime(floatValue, numDecimalPlaces))
return mlrval.FromString(lib.Sec2LocalTime(floatValue, numDecimalPlaces))
}
func BIF_sec2localtime_binary(input1, input2 *Mlrval) *Mlrval {
func BIF_sec2localtime_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
floatValue, isNumeric := input1.GetNumericToFloatValue()
if !isNumeric {
return input1
@ -84,13 +85,13 @@ func BIF_sec2localtime_binary(input1, input2 *Mlrval) *Mlrval {
numDecimalPlaces, isInt := input2.GetIntValue()
if !isInt {
return MLRVAL_ERROR
return mlrval.ERROR
}
return MlrvalFromString(lib.Sec2LocalTime(floatValue, numDecimalPlaces))
return mlrval.FromString(lib.Sec2LocalTime(floatValue, numDecimalPlaces))
}
func BIF_sec2localtime_ternary(input1, input2, input3 *Mlrval) *Mlrval {
func BIF_sec2localtime_ternary(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
floatValue, isNumeric := input1.GetNumericToFloatValue()
if !isNumeric {
return input1
@ -98,37 +99,37 @@ func BIF_sec2localtime_ternary(input1, input2, input3 *Mlrval) *Mlrval {
numDecimalPlaces, isInt := input2.GetIntValue()
if !isInt {
return MLRVAL_ERROR
return mlrval.ERROR
}
locationString, isString := input3.GetString()
locationString, isString := input3.GetStringValue()
if !isString {
return MLRVAL_ERROR
return mlrval.ERROR
}
location, err := time.LoadLocation(locationString)
if err != nil {
return MLRVAL_ERROR
return mlrval.ERROR
}
return MlrvalFromString(lib.Sec2LocationTime(floatValue, numDecimalPlaces, location))
return mlrval.FromString(lib.Sec2LocationTime(floatValue, numDecimalPlaces, location))
}
func BIF_sec2gmtdate(input1 *Mlrval) *Mlrval {
func BIF_sec2gmtdate(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsNumeric() {
return input1
}
return BIF_strftime(input1, ptr_YMD_FORMAT)
}
func BIF_sec2localdate_unary(input1 *Mlrval) *Mlrval {
func BIF_sec2localdate_unary(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsNumeric() {
return input1
}
return BIF_strftime_local_binary(input1, ptr_YMD_FORMAT)
}
func BIF_sec2localdate_binary(input1, input2 *Mlrval) *Mlrval {
func BIF_sec2localdate_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsNumeric() {
return input1
}
@ -137,32 +138,32 @@ func BIF_sec2localdate_binary(input1, input2 *Mlrval) *Mlrval {
// ----------------------------------------------------------------
func BIF_localtime2gmt_unary(input1 *Mlrval) *Mlrval {
func BIF_localtime2gmt_unary(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return MLRVAL_ERROR
return mlrval.ERROR
}
return BIF_sec2gmt_unary(BIF_localtime2sec_unary(input1))
}
func BIF_localtime2gmt_binary(input1, input2 *Mlrval) *Mlrval {
func BIF_localtime2gmt_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return MLRVAL_ERROR
return mlrval.ERROR
}
return BIF_sec2gmt_unary(BIF_localtime2sec_binary(input1, input2))
}
func BIF_gmt2localtime_unary(input1 *Mlrval) *Mlrval {
func BIF_gmt2localtime_unary(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return MLRVAL_ERROR
return mlrval.ERROR
}
return BIF_sec2localtime_unary(BIF_gmt2sec(input1))
}
func BIF_gmt2localtime_binary(input1, input2 *Mlrval) *Mlrval {
func BIF_gmt2localtime_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return MLRVAL_ERROR
return mlrval.ERROR
}
return BIF_sec2localtime_ternary(BIF_gmt2sec(input1), MlrvalFromInt(0), input2)
return BIF_sec2localtime_ternary(BIF_gmt2sec(input1), mlrval.FromInt(0), input2)
}
// ================================================================
@ -171,38 +172,38 @@ func BIF_gmt2localtime_binary(input1, input2 *Mlrval) *Mlrval {
var extensionRegex = regexp.MustCompile("([1-9])S")
func BIF_strftime(input1, input2 *Mlrval) *Mlrval {
func BIF_strftime(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return strftimeHelper(input1, input2, false, nil)
}
func BIF_strftime_local_binary(input1, input2 *Mlrval) *Mlrval {
func BIF_strftime_local_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return strftimeHelper(input1, input2, true, nil)
}
func BIF_strftime_local_ternary(input1, input2, input3 *Mlrval) *Mlrval {
locationString, isString := input3.GetString()
func BIF_strftime_local_ternary(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
locationString, isString := input3.GetStringValue()
if !isString {
return MLRVAL_ERROR
return mlrval.ERROR
}
location, err := time.LoadLocation(locationString)
if err != nil {
return MLRVAL_ERROR
return mlrval.ERROR
}
return strftimeHelper(input1, input2, true, location)
}
func strftimeHelper(input1, input2 *Mlrval, doLocal bool, location *time.Location) *Mlrval {
if input1.mvtype == MT_VOID {
func strftimeHelper(input1, input2 *mlrval.Mlrval, doLocal bool, location *time.Location) *mlrval.Mlrval {
if input1.IsVoid() {
return input1
}
epochSeconds, ok := input1.GetNumericToFloatValue()
if !ok {
return MLRVAL_ERROR
return mlrval.ERROR
}
if input2.mvtype != MT_STRING {
return MLRVAL_ERROR
if !input2.IsString() {
return mlrval.ERROR
}
// Convert argument1 from float seconds since the epoch to a Go time.
@ -223,16 +224,16 @@ func strftimeHelper(input1, input2 *Mlrval, doLocal bool, location *time.Locatio
// implementation. However, in the strftime package we're using in the Go
// port, extension-formats are only a single byte so we need to rewrite
// them to "%6".
formatString := extensionRegex.ReplaceAllString(input2.printrep, "$1")
formatString := extensionRegex.ReplaceAllString(input2.AcquireStringValue(), "$1")
formatter, err := strftime.New(formatString, strftimeExtensions)
if err != nil {
return MLRVAL_ERROR
return mlrval.ERROR
}
outputString := formatter.FormatString(inputTime)
return MlrvalFromString(outputString)
return mlrval.FromString(outputString)
}
// ----------------------------------------------------------------
@ -299,82 +300,82 @@ func init() {
// ================================================================
// Argument 1 is formatted date string like "2021-03-04 02:59:50".
// Argument 2 is format string like "%Y-%m-%d %H:%M:%S".
func BIF_strptime(input1, input2 *Mlrval) *Mlrval {
if input1.mvtype != MT_STRING {
return MLRVAL_ERROR
func BIF_strptime(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return mlrval.ERROR
}
if input2.mvtype != MT_STRING {
return MLRVAL_ERROR
if !input2.IsString() {
return mlrval.ERROR
}
timeString := input1.printrep
formatString := input2.printrep
timeString := input1.AcquireStringValue()
formatString := input2.AcquireStringValue()
t, err := strptime.Parse(timeString, formatString)
if err != nil {
return MLRVAL_ERROR
return mlrval.ERROR
}
return MlrvalFromFloat64(float64(t.UnixNano()) / 1.0e9)
return mlrval.FromFloat(float64(t.UnixNano()) / 1.0e9)
}
func BIF_strptime_local_binary(input1, input2 *Mlrval) *Mlrval {
if input1.mvtype != MT_STRING {
return MLRVAL_ERROR
func BIF_strptime_local_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return mlrval.ERROR
}
if input2.mvtype != MT_STRING {
return MLRVAL_ERROR
if !input2.IsString() {
return mlrval.ERROR
}
timeString := input1.printrep
formatString := input2.printrep
timeString := input1.AcquireStringValue()
formatString := input2.AcquireStringValue()
t, err := strptime.ParseLocal(timeString, formatString)
if err != nil {
return MLRVAL_ERROR
return mlrval.ERROR
}
return MlrvalFromFloat64(float64(t.UnixNano()) / 1.0e9)
return mlrval.FromFloat(float64(t.UnixNano()) / 1.0e9)
}
func BIF_strptime_local_ternary(input1, input2, input3 *Mlrval) *Mlrval {
if input1.mvtype != MT_STRING {
return MLRVAL_ERROR
func BIF_strptime_local_ternary(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return mlrval.ERROR
}
if input2.mvtype != MT_STRING {
return MLRVAL_ERROR
if !input2.IsString() {
return mlrval.ERROR
}
if input3.mvtype != MT_STRING {
return MLRVAL_ERROR
if !input3.IsString() {
return mlrval.ERROR
}
timeString := input1.printrep
formatString := input2.printrep
locationString := input3.printrep
timeString := input1.AcquireStringValue()
formatString := input2.AcquireStringValue()
locationString := input3.AcquireStringValue()
location, err := time.LoadLocation(locationString)
if err != nil {
return MLRVAL_ERROR
return mlrval.ERROR
}
// TODO: use location
t, err := strptime.ParseLocation(timeString, formatString, location)
if err != nil {
return MLRVAL_ERROR
return mlrval.ERROR
}
return MlrvalFromFloat64(float64(t.UnixNano()) / 1.0e9)
return mlrval.FromFloat(float64(t.UnixNano()) / 1.0e9)
}
// ================================================================
// Argument 1 is formatted date string like "2021-03-04T02:59:50Z".
func BIF_gmt2sec(input1 *Mlrval) *Mlrval {
func BIF_gmt2sec(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return BIF_strptime(input1, ptr_ISO8601_TIME_FORMAT)
}
func BIF_localtime2sec_unary(input1 *Mlrval) *Mlrval {
func BIF_localtime2sec_unary(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return BIF_strptime_local_binary(input1, ptr_ISO8601_LOCAL_TIME_FORMAT)
}
func BIF_localtime2sec_binary(input1, input2 *Mlrval) *Mlrval {
func BIF_localtime2sec_binary(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return BIF_strptime_local_ternary(input1, ptr_ISO8601_LOCAL_TIME_FORMAT, input2)
}

View file

@ -0,0 +1,63 @@
package bifs
import (
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"fmt"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
func BIF_md5(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return mlrval.ERROR
} else {
return mlrval.FromString(
fmt.Sprintf(
"%x",
md5.Sum([]byte(input1.AcquireStringValue())),
),
)
}
}
func BIF_sha1(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return mlrval.ERROR
} else {
return mlrval.FromString(
fmt.Sprintf(
"%x",
sha1.Sum([]byte(input1.AcquireStringValue())),
),
)
}
}
func BIF_sha256(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return mlrval.ERROR
} else {
return mlrval.FromString(
fmt.Sprintf(
"%x",
sha256.Sum256([]byte(input1.AcquireStringValue())),
),
)
}
}
func BIF_sha512(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return mlrval.ERROR
} else {
return mlrval.FromString(
fmt.Sprintf(
"%x",
sha512.Sum512([]byte(input1.AcquireStringValue())),
),
)
}
}

View file

@ -0,0 +1,25 @@
package bifs
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
func TestBIF_md5(t *testing.T) {
input1 := mlrval.FromDeferredType("")
output := BIF_md5(input1)
stringval, ok := output.GetStringValue()
assert.True(t, ok)
assert.Equal(t, "d41d8cd98f00b204e9800998ecf8427e", stringval)
input1 = mlrval.FromDeferredType("miller")
output = BIF_md5(input1)
stringval, ok = output.GetStringValue()
assert.True(t, ok)
assert.Equal(t, "f0af962ddbc82430e947390b2f3f6e49", stringval)
}
// TODO: copy in more unit-test cases from existing regression-test data

View file

@ -0,0 +1,269 @@
// ================================================================
// Go math-library functions
// ================================================================
package bifs
import (
"math"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// ----------------------------------------------------------------
// Return error (unary math-library func)
func _math_unary_erro1(input1 *mlrval.Mlrval, f mathLibUnaryFunc) *mlrval.Mlrval {
return mlrval.ERROR
}
// Return absent (unary math-library func)
func _math_unary_absn1(input1 *mlrval.Mlrval, f mathLibUnaryFunc) *mlrval.Mlrval {
return mlrval.ABSENT
}
// Return null (unary math-library func)
func _math_unary_null1(input1 *mlrval.Mlrval, f mathLibUnaryFunc) *mlrval.Mlrval {
return mlrval.NULL
}
// Return void (unary math-library func)
func _math_unary_void1(input1 *mlrval.Mlrval, f mathLibUnaryFunc) *mlrval.Mlrval {
return mlrval.VOID
}
// ----------------------------------------------------------------
func math_unary_f_i(input1 *mlrval.Mlrval, f mathLibUnaryFunc) *mlrval.Mlrval {
return mlrval.FromFloat(f(float64(input1.AcquireIntValue())))
}
func math_unary_i_i(input1 *mlrval.Mlrval, f mathLibUnaryFunc) *mlrval.Mlrval {
return mlrval.FromInt(int(f(float64(input1.AcquireIntValue()))))
}
func math_unary_f_f(input1 *mlrval.Mlrval, f mathLibUnaryFunc) *mlrval.Mlrval {
return mlrval.FromFloat(f(input1.AcquireFloatValue()))
}
// Disposition vector for unary mathlib functions
var mudispo = [mlrval.MT_DIM]mathLibUnaryFuncWrapper{
/*ERROR */ _math_unary_erro1,
/*ABSENT */ _math_unary_absn1,
/*NULL */ _math_unary_null1,
/*VOID */ _math_unary_void1,
/*STRING */ _math_unary_erro1,
/*INT */ math_unary_f_i,
/*FLOAT */ math_unary_f_f,
/*BOOL */ _math_unary_erro1,
/*ARRAY */ _math_unary_absn1,
/*MAP */ _math_unary_absn1,
/*FUNC */ _math_unary_erro1,
}
func BIF_acos(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Acos) }
func BIF_acosh(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mudispo[input1.Type()](input1, math.Acosh)
}
func BIF_asin(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Asin) }
func BIF_asinh(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mudispo[input1.Type()](input1, math.Asinh)
}
func BIF_atan(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Atan) }
func BIF_atanh(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mudispo[input1.Type()](input1, math.Atanh)
}
func BIF_cbrt(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Cbrt) }
func BIF_cos(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Cos) }
func BIF_cosh(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Cosh) }
func BIF_erf(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Erf) }
func BIF_erfc(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Erfc) }
func BIF_exp(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Exp) }
func BIF_expm1(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mudispo[input1.Type()](input1, math.Expm1)
}
func BIF_invqnorm(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mudispo[input1.Type()](input1, lib.Invqnorm)
}
func BIF_log(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Log) }
func BIF_log10(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mudispo[input1.Type()](input1, math.Log10)
}
func BIF_log1p(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mudispo[input1.Type()](input1, math.Log1p)
}
func BIF_qnorm(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mudispo[input1.Type()](input1, lib.Qnorm)
}
func BIF_sin(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Sin) }
func BIF_sinh(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Sinh) }
func BIF_sqrt(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Sqrt) }
func BIF_tan(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Tan) }
func BIF_tanh(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mudispo[input1.Type()](input1, math.Tanh) }
// Disposition vector for unary mathlib functions which are int-preserving
var imudispo = [mlrval.MT_DIM]mathLibUnaryFuncWrapper{
/*ERROR */ _math_unary_erro1,
/*ABSENT */ _math_unary_absn1,
/*NULL */ _math_unary_null1,
/*VOID */ _math_unary_void1,
/*STRING */ _math_unary_erro1,
/*INT */ math_unary_i_i,
/*FLOAT */ math_unary_f_f,
/*BOOL */ _math_unary_erro1,
/*ARRAY */ _math_unary_absn1,
/*MAP */ _math_unary_absn1,
/*FUNC */ _math_unary_erro1,
}
// Int-preserving
func BIF_abs(input1 *mlrval.Mlrval) *mlrval.Mlrval { return imudispo[input1.Type()](input1, math.Abs) } // xxx
func BIF_ceil(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return imudispo[input1.Type()](input1, math.Ceil)
} // xxx
func BIF_floor(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return imudispo[input1.Type()](input1, math.Floor)
} // xxx
func BIF_round(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return imudispo[input1.Type()](input1, math.Round)
} // xxx
func BIF_sgn(input1 *mlrval.Mlrval) *mlrval.Mlrval { return imudispo[input1.Type()](input1, lib.Sgn) } // xxx
// ================================================================
// Exponentiation: DSL operator '**'. See also
// https://johnkerl.org/miller6/reference-main-arithmetic.html
func pow_f_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
foutput := math.Pow(float64(input1.AcquireIntValue()), float64(input2.AcquireIntValue()))
ioutput := int(foutput)
// Int raised to int power should be float if it can be (i.e. unless overflow)
if float64(ioutput) == foutput {
return mlrval.FromInt(ioutput)
} else {
return mlrval.FromFloat(foutput)
}
}
func pow_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Pow(float64(input1.AcquireIntValue()), input2.AcquireFloatValue()))
}
func pow_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Pow(input1.AcquireFloatValue(), float64(input2.AcquireIntValue())))
}
func pow_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Pow(input1.AcquireFloatValue(), input2.AcquireFloatValue()))
}
var pow_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _i0__, _f0__, _erro, _absn, _absn, _erro},
/*NULL */ {_erro, _absn, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
/*VOID */ {_erro, _absn, _erro, _void, _erro, _void, _void, _erro, _absn, _absn, _erro},
/*STRING */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*INT */ {_erro, _1___, _erro, _void, _erro, pow_f_ii, pow_f_if, _erro, _absn, _absn, _erro},
/*FLOAT */ {_erro, _1___, _erro, _void, _erro, pow_f_fi, pow_f_ff, _erro, _absn, _absn, _erro},
/*BOOL */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ARRAY */ {_absn, _absn, _erro, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*MAP */ {_absn, _absn, _erro, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_pow(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return pow_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ================================================================
func atan2_f_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Atan2(float64(input1.AcquireIntValue()), float64(input2.AcquireIntValue())))
}
func atan2_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Atan2(float64(input1.AcquireIntValue()), input2.AcquireFloatValue()))
}
func atan2_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Atan2(input1.AcquireFloatValue(), float64(input2.AcquireIntValue())))
}
func atan2_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(math.Atan2(input1.AcquireFloatValue(), input2.AcquireFloatValue()))
}
var atan2_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _i0__, _f0__, _erro, _absn, _absn, _erro},
/*NULL */ {_erro, _absn, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
/*VOID */ {_erro, _absn, _erro, _void, _erro, _void, _void, _erro, _absn, _absn, _erro},
/*STRING */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*INT */ {_erro, _1___, _erro, _void, _erro, atan2_f_ii, atan2_f_if, _erro, _absn, _absn, _erro},
/*FLOAT */ {_erro, _1___, _erro, _void, _erro, atan2_f_fi, atan2_f_ff, _erro, _absn, _absn, _erro},
/*BOOL */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ARRAY */ {_absn, _absn, _erro, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*MAP */ {_absn, _absn, _erro, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_atan2(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return atan2_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ================================================================
func mlr_roundm(x, m float64) float64 {
return math.Round(x/m) * m
}
func roundm_f_ii(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(int(mlr_roundm(float64(input1.AcquireIntValue()), float64(input2.AcquireIntValue()))))
}
func roundm_f_if(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(mlr_roundm(float64(input1.AcquireIntValue()), input2.AcquireFloatValue()))
}
func roundm_f_fi(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(mlr_roundm(input1.AcquireFloatValue(), float64(input2.AcquireIntValue())))
}
func roundm_f_ff(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(mlr_roundm(input1.AcquireFloatValue(), input2.AcquireFloatValue()))
}
var roundm_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _erro, _i0__, _f0__, _erro, _absn, _absn, _erro},
/*NULL */ {_erro, _absn, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
/*VOID */ {_erro, _absn, _erro, _void, _erro, _void, _void, _erro, _absn, _absn, _erro},
/*STRING */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*INT */ {_erro, _1___, _erro, _void, _erro, roundm_f_ii, roundm_f_if, _erro, _absn, _absn, _erro},
/*FLOAT */ {_erro, _1___, _erro, _void, _erro, roundm_f_fi, roundm_f_ff, _erro, _absn, _absn, _erro},
/*BOOL */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ARRAY */ {_absn, _absn, _erro, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*MAP */ {_absn, _absn, _erro, _absn, _absn, _absn, _absn, _absn, _absn, _absn, _erro},
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_roundm(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return roundm_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ================================================================
func BIF_logifit(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsLegit() {
return input1
}
if !input2.IsLegit() {
return input2
}
if !input3.IsLegit() {
return input3
}
// int/float OK; rest not
x, xok := input1.GetNumericToFloatValue()
if !xok {
return mlrval.ERROR
}
m, mok := input2.GetNumericToFloatValue()
if !mok {
return mlrval.ERROR
}
b, bok := input3.GetNumericToFloatValue()
if !bok {
return mlrval.ERROR
}
return mlrval.FromFloat(1.0 / (1.0 + math.Exp(-m*x-b)))
}

View file

@ -1,19 +1,20 @@
package types
package bifs
import (
"math"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
func BIF_urand() *Mlrval {
return MlrvalFromFloat64(
func BIF_urand() *mlrval.Mlrval {
return mlrval.FromFloat(
lib.RandFloat64(),
)
}
func BIF_urand32() *Mlrval {
return MlrvalFromInt(
func BIF_urand32() *mlrval.Mlrval {
return mlrval.FromInt(
int(
lib.RandUint32(),
),
@ -21,7 +22,7 @@ func BIF_urand32() *Mlrval {
}
// TODO: use a disposition matrix
func BIF_urandint(input1, input2 *Mlrval) *Mlrval {
func BIF_urandint(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsLegit() {
return input1
}
@ -29,14 +30,14 @@ func BIF_urandint(input1, input2 *Mlrval) *Mlrval {
return input2
}
if !input1.IsInt() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input2.IsInt() {
return MLRVAL_ERROR
return mlrval.ERROR
}
a := input1.intval
b := input2.intval
a := input1.AcquireIntValue()
b := input2.AcquireIntValue()
var lo int = 0
var hi int = 0
@ -48,10 +49,10 @@ func BIF_urandint(input1, input2 *Mlrval) *Mlrval {
hi = a + 1
}
u := int(math.Floor(float64(lo) + float64((hi-lo))*lib.RandFloat64()))
return MlrvalFromInt(u)
return mlrval.FromInt(u)
}
func BIF_urandrange(input1, input2 *Mlrval) *Mlrval {
func BIF_urandrange(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsLegit() {
return input1
}
@ -61,12 +62,12 @@ func BIF_urandrange(input1, input2 *Mlrval) *Mlrval {
a, aok := input1.GetNumericToFloatValue()
b, bok := input2.GetNumericToFloatValue()
if !aok {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !bok {
return MLRVAL_ERROR
return mlrval.ERROR
}
return MlrvalFromFloat64(
return mlrval.FromFloat(
a + (b-a)*lib.RandFloat64(),
)
}

View file

@ -1,14 +1,15 @@
package types
package bifs
import (
"strings"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// BIF_ssub implements the ssub function -- no-frills string-replace, no
// regexes, no escape sequences.
func BIF_ssub(input1, input2, input3 *Mlrval) *Mlrval {
func BIF_ssub(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsErrorOrAbsent() {
return input1
}
@ -19,16 +20,16 @@ func BIF_ssub(input1, input2, input3 *Mlrval) *Mlrval {
return input3
}
if !input1.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input2.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input3.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
return MlrvalFromString(
strings.Replace(input1.printrep, input2.printrep, input3.printrep, 1),
return mlrval.FromString(
strings.Replace(input1.AcquireStringValue(), input2.AcquireStringValue(), input3.AcquireStringValue(), 1),
)
}
@ -39,7 +40,7 @@ func BIF_ssub(input1, input2, input3 *Mlrval) *Mlrval {
// on each record. Likewise for other regex-using functions in this file. But
// first, do a profiling run to see how much time would be saved, and if this
// precomputing+caching would be worthwhile.
func BIF_sub(input1, input2, input3 *Mlrval) *Mlrval {
func BIF_sub(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsErrorOrAbsent() {
return input1
}
@ -50,26 +51,26 @@ func BIF_sub(input1, input2, input3 *Mlrval) *Mlrval {
return input3
}
if !input1.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input2.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input3.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
input := input1.printrep
sregex := input2.printrep
replacement := input3.printrep
input := input1.AcquireStringValue()
sregex := input2.AcquireStringValue()
replacement := input3.AcquireStringValue()
stringOutput := lib.RegexSub(input, sregex, replacement)
return MlrvalFromString(stringOutput)
return mlrval.FromString(stringOutput)
}
// BIF_gsub implements the gsub function, with support for regexes and regex captures
// of the form "\1" .. "\9".
func BIF_gsub(input1, input2, input3 *Mlrval) *Mlrval {
func BIF_gsub(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsErrorOrAbsent() {
return input1
}
@ -80,26 +81,26 @@ func BIF_gsub(input1, input2, input3 *Mlrval) *Mlrval {
return input3
}
if !input1.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input2.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input3.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
input := input1.printrep
sregex := input2.printrep
replacement := input3.printrep
input := input1.AcquireStringValue()
sregex := input2.AcquireStringValue()
replacement := input3.AcquireStringValue()
stringOutput := lib.RegexGsub(input, sregex, replacement)
return MlrvalFromString(stringOutput)
return mlrval.FromString(stringOutput)
}
// BIF_string_matches_regexp implements the =~ operator, with support for
// setting regex-captures for later expressions to access using "\1" .. "\9".
func BIF_string_matches_regexp(input1, input2 *Mlrval) (retval *Mlrval, captures []string) {
func BIF_string_matches_regexp(input1, input2 *mlrval.Mlrval) (retval *mlrval.Mlrval, captures []string) {
if !input1.IsLegit() {
return input1, nil
}
@ -108,51 +109,51 @@ func BIF_string_matches_regexp(input1, input2 *Mlrval) (retval *Mlrval, captures
}
input1string := input1.String()
if !input2.IsStringOrVoid() {
return MLRVAL_ERROR, nil
return mlrval.ERROR, nil
}
boolOutput, captures := lib.RegexMatches(input1string, input2.printrep)
return MlrvalFromBool(boolOutput), captures
boolOutput, captures := lib.RegexMatches(input1string, input2.AcquireStringValue())
return mlrval.FromBool(boolOutput), captures
}
// BIF_string_matches_regexp implements the !=~ operator.
func BIF_string_does_not_match_regexp(input1, input2 *Mlrval) (retval *Mlrval, captures []string) {
func BIF_string_does_not_match_regexp(input1, input2 *mlrval.Mlrval) (retval *mlrval.Mlrval, captures []string) {
output, captures := BIF_string_matches_regexp(input1, input2)
if output.mvtype == MT_BOOL {
return MlrvalFromBool(!output.boolval), captures
if output.IsBool() {
return mlrval.FromBool(!output.AcquireBoolValue()), captures
} else {
// else leave it as error, absent, etc.
return output, captures
}
}
func BIF_regextract(input1, input2 *Mlrval) *Mlrval {
func BIF_regextract(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input2.IsString() {
return MLRVAL_ERROR
return mlrval.ERROR
}
regex := lib.CompileMillerRegexOrDie(input2.printrep)
match := regex.FindStringIndex(input1.printrep)
regex := lib.CompileMillerRegexOrDie(input2.AcquireStringValue())
match := regex.FindStringIndex(input1.AcquireStringValue())
if match != nil {
return MlrvalFromString(input1.printrep[match[0]:match[1]])
return mlrval.FromString(input1.AcquireStringValue()[match[0]:match[1]])
} else {
return MLRVAL_ABSENT
return mlrval.ABSENT
}
}
func BIF_regextract_or_else(input1, input2, input3 *Mlrval) *Mlrval {
func BIF_regextract_or_else(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input2.IsString() {
return MLRVAL_ERROR
return mlrval.ERROR
}
regex := lib.CompileMillerRegexOrDie(input2.printrep)
match := regex.FindStringIndex(input1.printrep)
regex := lib.CompileMillerRegexOrDie(input2.AcquireStringValue())
match := regex.FindStringIndex(input1.AcquireStringValue())
if match != nil {
return MlrvalFromString(input1.printrep[match[0]:match[1]])
return mlrval.FromString(input1.AcquireStringValue()[match[0]:match[1]])
} else {
return input3
}

View file

@ -0,0 +1,326 @@
package bifs
import (
"fmt"
"math"
"strings"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
func BIF_dhms2sec(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return mlrval.ERROR
}
var d, h, m, s int
if strings.HasPrefix(input1.AcquireStringValue(), "-") {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "-%dd%dh%dm%ds", &d, &h, &m, &s)
if n == 4 && err == nil {
return mlrval.FromInt(-(s + m*60 + h*60*60 + d*60*60*24))
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "-%dh%dm%ds", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromInt(-(s + m*60 + h*60*60))
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "-%dm%ds", &m, &s)
if n == 2 && err == nil {
return mlrval.FromInt(-(s + m*60))
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "-%ds", &s)
if n == 1 && err == nil {
return mlrval.FromInt(-(s))
}
} else {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "%dd%dh%dm%ds", &d, &h, &m, &s)
if n == 4 && err == nil {
return mlrval.FromInt(s + m*60 + h*60*60 + d*60*60*24)
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "%dh%dm%ds", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromInt(s + m*60 + h*60*60)
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "%dm%ds", &m, &s)
if n == 2 && err == nil {
return mlrval.FromInt(s + m*60)
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "%ds", &s)
if n == 1 && err == nil {
return mlrval.FromInt(s)
}
}
return mlrval.ERROR
}
func BIF_dhms2fsec(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return mlrval.ERROR
}
var d, h, m int
var s float64
if strings.HasPrefix(input1.AcquireStringValue(), "-") {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "-%dd%dh%dm%fs", &d, &h, &m, &s)
if n == 4 && err == nil {
return mlrval.FromFloat(-(s + float64(m*60+h*60*60+d*60*60*24)))
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "-%dh%dm%fs", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromFloat(-(s + float64(m*60+h*60*60)))
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "-%dm%fs", &m, &s)
if n == 2 && err == nil {
return mlrval.FromFloat(-(s + float64(m*60)))
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "-%fs", &s)
if n == 1 && err == nil {
return mlrval.FromFloat(-(s))
}
} else {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "%dd%dh%dm%fs", &d, &h, &m, &s)
if n == 4 && err == nil {
return mlrval.FromFloat(s + float64(m*60+h*60*60+d*60*60*24))
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "%dh%dm%fs", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromFloat(s + float64(m*60+h*60*60))
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "%dm%fs", &m, &s)
if n == 2 && err == nil {
return mlrval.FromFloat(s + float64(m*60))
}
n, err = fmt.Sscanf(input1.AcquireStringValue(), "%fs", &s)
if n == 1 && err == nil {
return mlrval.FromFloat(s)
}
}
return mlrval.ERROR
}
func BIF_hms2sec(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return mlrval.ERROR
}
if input1.AcquireStringValue() == "" {
return mlrval.ERROR
}
var h, m, s int
if strings.HasPrefix(input1.AcquireStringValue(), "-") {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "-%d:%d:%d", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromInt(-(s + m*60 + h*60*60))
}
} else {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "%d:%d:%d", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromInt(s + m*60 + h*60*60)
}
}
return mlrval.ERROR
}
func BIF_hms2fsec(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return mlrval.ERROR
}
var h, m int
var s float64
if strings.HasPrefix(input1.AcquireStringValue(), "-") {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "-%d:%d:%f", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromFloat(-(s + float64(m*60+h*60*60)))
}
} else {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "%d:%d:%f", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromFloat(s + float64(m*60+h*60*60))
}
}
return mlrval.ERROR
}
func BIF_sec2dhms(input1 *mlrval.Mlrval) *mlrval.Mlrval {
isec, ok := input1.GetIntValue()
if !ok {
return mlrval.ERROR
}
var d, h, m, s int
splitIntToDHMS(isec, &d, &h, &m, &s)
if d != 0 {
return mlrval.FromString(
fmt.Sprintf("%dd%02dh%02dm%02ds", d, h, m, s),
)
} else if h != 0 {
return mlrval.FromString(
fmt.Sprintf("%dh%02dm%02ds", h, m, s),
)
} else if m != 0 {
return mlrval.FromString(
fmt.Sprintf("%dm%02ds", m, s),
)
} else {
return mlrval.FromString(
fmt.Sprintf("%ds", s),
)
}
return mlrval.ERROR
}
func BIF_sec2hms(input1 *mlrval.Mlrval) *mlrval.Mlrval {
isec, ok := input1.GetIntValue()
if !ok {
return mlrval.ERROR
}
sign := ""
if isec < 0 {
sign = "-"
isec = -isec
}
var d, h, m, s int
splitIntToDHMS(isec, &d, &h, &m, &s)
h += d * 24
return mlrval.FromString(
fmt.Sprintf("%s%02d:%02d:%02d", sign, h, m, s),
)
return mlrval.ERROR
}
func BIF_fsec2dhms(input1 *mlrval.Mlrval) *mlrval.Mlrval {
fsec, ok := input1.GetNumericToFloatValue()
if !ok {
return mlrval.ERROR
}
sign := 1
if fsec < 0 {
sign = -1
fsec = -fsec
}
isec := int(math.Trunc(fsec))
fractional := fsec - float64(isec)
var d, h, m, s int
splitIntToDHMS(isec, &d, &h, &m, &s)
if d != 0 {
d = sign * d
return mlrval.FromString(
fmt.Sprintf(
"%dd%02dh%02dm%09.6fs",
d, h, m, float64(s)+fractional),
)
} else if h != 0 {
h = sign * h
return mlrval.FromString(
fmt.Sprintf(
"%dh%02dm%09.6fs",
h, m, float64(s)+fractional),
)
} else if m != 0 {
m = sign * m
return mlrval.FromString(
fmt.Sprintf(
"%dm%09.6fs",
m, float64(s)+fractional),
)
} else {
s = sign * s
fractional = float64(sign) * fractional
return mlrval.FromString(
fmt.Sprintf(
"%.6fs",
float64(s)+fractional),
)
}
}
func BIF_fsec2hms(input1 *mlrval.Mlrval) *mlrval.Mlrval {
fsec, ok := input1.GetNumericToFloatValue()
if !ok {
return mlrval.ERROR
}
sign := ""
if fsec < 0 {
sign = "-"
fsec = -fsec
}
isec := int(math.Trunc(fsec))
fractional := fsec - float64(isec)
var d, h, m, s int
splitIntToDHMS(isec, &d, &h, &m, &s)
h += d * 24
// "%02.6f" does not exist so we have to do our own zero-pad
if s < 10 {
return mlrval.FromString(
fmt.Sprintf("%s%02d:%02d:0%.6f", sign, h, m, float64(s)+fractional),
)
} else {
return mlrval.FromString(
fmt.Sprintf("%s%02d:%02d:%.6f", sign, h, m, float64(s)+fractional),
)
}
return mlrval.ERROR
}
// Helper function
func splitIntToDHMS(u int, pd, ph, pm, ps *int) {
d := 0
h := 0
m := 0
s := 0
sign := 1
if u < 0 {
u = -u
sign = -1
}
s = u % 60
u = u / 60
if u == 0 {
s = s * sign
} else {
m = u % 60
u = u / 60
if u == 0 {
m = m * sign
} else {
h = u % 24
u = u / 24
if u == 0 {
h = h * sign
} else {
d = u * sign
}
}
}
*pd = d
*ph = h
*pm = m
*ps = s
}

View file

@ -2,17 +2,19 @@
// For sorting
// ================================================================
package types
package bifs
import (
"fmt"
"os"
"strings"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// LexicalAscendingComparator is for lexical sort: it stringifies
// everything.
func LexicalAscendingComparator(input1 *Mlrval, input2 *Mlrval) int {
func LexicalAscendingComparator(input1 *mlrval.Mlrval, input2 *mlrval.Mlrval) int {
sa := input1.String()
sb := input2.String()
if sa < sb {
@ -26,19 +28,19 @@ func LexicalAscendingComparator(input1 *Mlrval, input2 *Mlrval) int {
// LexicalDescendingComparator is for reverse-lexical sort: it stringifies
// everything.
func LexicalDescendingComparator(input1 *Mlrval, input2 *Mlrval) int {
func LexicalDescendingComparator(input1 *mlrval.Mlrval, input2 *mlrval.Mlrval) int {
return LexicalAscendingComparator(input2, input1)
}
// CaseFoldAscendingComparator is for case-folded lexical sort: it stringifies
// everything.
func CaseFoldAscendingComparator(input1 *Mlrval, input2 *Mlrval) int {
func CaseFoldAscendingComparator(input1 *mlrval.Mlrval, input2 *mlrval.Mlrval) int {
sa := input1.String()
sb := input2.String()
if input1.mvtype == MT_STRING {
if input1.IsString() {
sa = strings.ToLower(sa)
}
if input2.mvtype == MT_STRING {
if input2.IsString() {
sb = strings.ToLower(sb)
}
if sa < sb {
@ -52,7 +54,7 @@ func CaseFoldAscendingComparator(input1 *Mlrval, input2 *Mlrval) int {
// CaseFoldDescendingComparator is for case-folded lexical sort: it stringifies
// everything.
func CaseFoldDescendingComparator(input1 *Mlrval, input2 *Mlrval) int {
func CaseFoldDescendingComparator(input1 *mlrval.Mlrval, input2 *mlrval.Mlrval) int {
return CaseFoldAscendingComparator(input2, input1)
}
@ -65,29 +67,29 @@ func CaseFoldDescendingComparator(input1 *Mlrval, input2 *Mlrval) int {
// * numeric compares on numbers
// * false < true
func _neg1(input1, input2 *Mlrval) int {
func _neg1(input1, input2 *mlrval.Mlrval) int {
return -1
}
func _zero(input1, input2 *Mlrval) int {
func _zero(input1, input2 *mlrval.Mlrval) int {
return 0
}
func _pos1(input1, input2 *Mlrval) int {
func _pos1(input1, input2 *mlrval.Mlrval) int {
return 1
}
func _scmp(input1, input2 *Mlrval) int {
if input1.printrep < input2.printrep {
func _scmp(input1, input2 *mlrval.Mlrval) int {
if input1.AcquireStringValue() < input2.AcquireStringValue() {
return -1
} else if input1.printrep > input2.printrep {
} else if input1.AcquireStringValue() > input2.AcquireStringValue() {
return 1
} else {
return 0
}
}
func iicmp(input1, input2 *Mlrval) int {
ca := input1.intval
cb := input2.intval
func iicmp(input1, input2 *mlrval.Mlrval) int {
ca := input1.AcquireIntValue()
cb := input2.AcquireIntValue()
if ca < cb {
return -1
} else if ca > cb {
@ -96,9 +98,9 @@ func iicmp(input1, input2 *Mlrval) int {
return 0
}
}
func ifcmp(input1, input2 *Mlrval) int {
ca := float64(input1.intval)
cb := input2.floatval
func ifcmp(input1, input2 *mlrval.Mlrval) int {
ca := float64(input1.AcquireIntValue())
cb := input2.AcquireFloatValue()
if ca < cb {
return -1
} else if ca > cb {
@ -107,9 +109,9 @@ func ifcmp(input1, input2 *Mlrval) int {
return 0
}
}
func ficmp(input1, input2 *Mlrval) int {
ca := input1.floatval
cb := float64(input2.intval)
func ficmp(input1, input2 *mlrval.Mlrval) int {
ca := input1.AcquireFloatValue()
cb := float64(input2.AcquireIntValue())
if ca < cb {
return -1
} else if ca > cb {
@ -118,9 +120,9 @@ func ficmp(input1, input2 *Mlrval) int {
return 0
}
}
func ffcmp(input1, input2 *Mlrval) int {
ca := input1.floatval
cb := input2.floatval
func ffcmp(input1, input2 *mlrval.Mlrval) int {
ca := input1.AcquireFloatValue()
cb := input2.AcquireFloatValue()
if ca < cb {
return -1
} else if ca > cb {
@ -130,9 +132,9 @@ func ffcmp(input1, input2 *Mlrval) int {
}
}
func bbcmp(input1, input2 *Mlrval) int {
a := input1.boolval
b := input2.boolval
func bbcmp(input1, input2 *mlrval.Mlrval) int {
a := input1.AcquireBoolValue()
b := input2.AcquireBoolValue()
if a == false {
if b == false {
return 0
@ -148,7 +150,7 @@ func bbcmp(input1, input2 *Mlrval) int {
}
}
func _xcmp(input1, input2 *Mlrval) int {
func _xcmp(input1, input2 *mlrval.Mlrval) int {
fmt.Fprintf(os.Stderr, "mlr: functions cannot be sorted.\n")
os.Exit(1)
return 0
@ -165,7 +167,7 @@ func _xcmp(input1, input2 *Mlrval) int {
// * false < true
// typed_cmp_dispositions is the disposition matrix for numerical sorting of Mlrvals.
var typed_cmp_typedpositions = [MT_DIM][MT_DIM]ComparatorFunc{
var typed_cmp_typedpositions = [mlrval.MT_DIM][mlrval.MT_DIM]ComparatorFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_zero, _neg1, _neg1, _pos1, _pos1, _pos1, _pos1, _pos1, _zero, _zero, _xcmp},
/*ABSENT */ {_pos1, _zero, _pos1, _pos1, _pos1, _pos1, _pos1, _pos1, _zero, _zero, _xcmp},
@ -182,12 +184,12 @@ var typed_cmp_typedpositions = [MT_DIM][MT_DIM]ComparatorFunc{
// NumericAscendingComparator is for "numerical" sort: it uses Mlrval sorting
// rules by type, including numeric sort for numeric types.
func NumericAscendingComparator(input1 *Mlrval, input2 *Mlrval) int {
return typed_cmp_typedpositions[input1.mvtype][input2.mvtype](input1, input2)
func NumericAscendingComparator(input1 *mlrval.Mlrval, input2 *mlrval.Mlrval) int {
return typed_cmp_typedpositions[input1.Type()][input2.Type()](input1, input2)
}
// NumericDescendingComparator is for "numerical" sort: it uses Mlrval sorting
// rules by type, including numeric sort for numeric types.
func NumericDescendingComparator(input1 *Mlrval, input2 *Mlrval) int {
func NumericDescendingComparator(input1 *mlrval.Mlrval, input2 *mlrval.Mlrval) int {
return NumericAscendingComparator(input2, input1)
}

View file

@ -1,12 +1,9 @@
// ================================================================
// Most Miller tests (thousands of them) are command-line-driven via
// mlr regtest. Here are some cases needing special focus.
// ================================================================
package types
package bifs
import (
"testing"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// ----------------------------------------------------------------
@ -25,18 +22,18 @@ import (
func TestComparators(t *testing.T) {
i10 := MlrvalFromInt(10)
i2 := MlrvalFromInt(2)
i10 := mlrval.FromInt(10)
i2 := mlrval.FromInt(2)
bfalse := MlrvalFromBool(false)
btrue := MlrvalFromBool(true)
bfalse := mlrval.FromBool(false)
btrue := mlrval.FromBool(true)
sabc := MlrvalFromString("abc")
sdef := MlrvalFromString("def")
sabc := mlrval.FromString("abc")
sdef := mlrval.FromString("def")
e := *MLRVAL_ERROR
e := *mlrval.ERROR
a := *MLRVAL_ABSENT
a := *mlrval.ABSENT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Within-type lexical comparisons

View file

@ -1,9 +1,10 @@
package types
package bifs
import (
"math"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// ----------------------------------------------------------------
@ -23,7 +24,7 @@ import (
// output = [m, b, math.sqrt(var_m), math.sqrt(var_b)]
// ----------------------------------------------------------------
func MlrvalGetVar(mn, msum, msum2 *Mlrval) *Mlrval {
func BIF_get_var(mn, msum, msum2 *mlrval.Mlrval) *mlrval.Mlrval {
n, isInt := mn.GetIntValue()
lib.InternalCodingErrorIf(!isInt)
sum, isNumber := msum.GetNumericToFloatValue()
@ -32,7 +33,7 @@ func MlrvalGetVar(mn, msum, msum2 *Mlrval) *Mlrval {
lib.InternalCodingErrorIf(!isNumber)
if n < 2 {
return MLRVAL_VOID
return mlrval.VOID
}
mean := float64(sum) / float64(n)
@ -41,12 +42,12 @@ func MlrvalGetVar(mn, msum, msum2 *Mlrval) *Mlrval {
numerator = 0.0
}
denominator := float64(n - 1)
return MlrvalFromFloat64(numerator / denominator)
return mlrval.FromFloat(numerator / denominator)
}
// ----------------------------------------------------------------
func MlrvalGetStddev(mn, msum, msum2 *Mlrval) *Mlrval {
mvar := MlrvalGetVar(mn, msum, msum2)
func BIF_get_stddev(mn, msum, msum2 *mlrval.Mlrval) *mlrval.Mlrval {
mvar := BIF_get_var(mn, msum, msum2)
if mvar.IsVoid() {
return mvar
}
@ -54,8 +55,8 @@ func MlrvalGetStddev(mn, msum, msum2 *Mlrval) *Mlrval {
}
// ----------------------------------------------------------------
func MlrvalGetMeanEB(mn, msum, msum2 *Mlrval) *Mlrval {
mvar := MlrvalGetVar(mn, msum, msum2)
func BIF_get_mean_EB(mn, msum, msum2 *mlrval.Mlrval) *mlrval.Mlrval {
mvar := BIF_get_var(mn, msum, msum2)
if mvar.IsVoid() {
return mvar
}
@ -86,11 +87,11 @@ func MlrvalGetMeanEB(mn, msum, msum2 *Mlrval) *Mlrval {
// = sumx2 - n mean^2
// ----------------------------------------------------------------
func MlrvalGetSkewness(mn, msum, msum2, msum3 *Mlrval) *Mlrval {
func BIF_get_skewness(mn, msum, msum2, msum3 *mlrval.Mlrval) *mlrval.Mlrval {
n, isInt := mn.GetIntValue()
lib.InternalCodingErrorIf(!isInt)
if n < 2 {
return MLRVAL_VOID
return mlrval.VOID
}
fn := float64(n)
sum, isNumber := msum.GetNumericToFloatValue()
@ -105,7 +106,7 @@ func MlrvalGetSkewness(mn, msum, msum2, msum3 *Mlrval) *Mlrval {
numerator = numerator / fn
denominator := (sum2 - fn*mean*mean) / (fn - 1.0)
denominator = math.Pow(denominator, 1.5)
return MlrvalFromFloat64(numerator / denominator)
return mlrval.FromFloat(numerator / denominator)
}
// Unbiased:
@ -123,11 +124,11 @@ func MlrvalGetSkewness(mn, msum, msum2, msum3 *Mlrval) *Mlrval {
// = sumx4 - mean*(4 sumx3 - mean*(6 sumx2 - 3 n mean^2))
// ----------------------------------------------------------------
func MlrvalGetKurtosis(mn, msum, msum2, msum3, msum4 *Mlrval) *Mlrval {
func BIF_get_kurtosis(mn, msum, msum2, msum3, msum4 *mlrval.Mlrval) *mlrval.Mlrval {
n, isInt := mn.GetIntValue()
lib.InternalCodingErrorIf(!isInt)
if n < 2 {
return MLRVAL_VOID
return mlrval.VOID
}
fn := float64(n)
sum, isNumber := msum.GetNumericToFloatValue()
@ -145,6 +146,6 @@ func MlrvalGetKurtosis(mn, msum, msum2, msum3, msum4 *Mlrval) *Mlrval {
numerator = numerator / fn
denominator := (sum2 - fn*mean*mean) / fn
denominator = denominator * denominator
return MlrvalFromFloat64(numerator/denominator - 3.0)
return mlrval.FromFloat(numerator/denominator - 3.0)
}

View file

@ -1,4 +1,4 @@
package types
package bifs
import (
"regexp"
@ -7,20 +7,21 @@ import (
"unicode/utf8"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// ================================================================
func BIF_strlen(input1 *Mlrval) *Mlrval {
func BIF_strlen(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
} else {
return MlrvalFromInt(int(utf8.RuneCountInString(input1.printrep)))
return mlrval.FromInt(int(utf8.RuneCountInString(input1.AcquireStringValue())))
}
}
// ================================================================
func BIF_string(input1 *Mlrval) *Mlrval {
return MlrvalFromString(input1.String())
func BIF_string(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromString(input1.String())
}
// ================================================================
@ -37,11 +38,11 @@ func BIF_string(input1 *Mlrval) *Mlrval {
// should be: always the string concatenation of the string representations of
// the two arguments. So, we do the string-cast for the user.
func dot_s_xx(input1, input2 *Mlrval) *Mlrval {
return MlrvalFromString(input1.String() + input2.String())
func dot_s_xx(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromString(input1.String() + input2.String())
}
var dot_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var dot_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _absn, _absn, _erro},
/*ABSENT */ {_erro, _absn, _null, _void, _2___, _s2__, _s2__, _s2__, _absn, _absn, _erro},
@ -56,53 +57,53 @@ var dot_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_dot(input1, input2 *Mlrval) *Mlrval {
return dot_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_dot(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return dot_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ================================================================
// substr1(s,m,n) gives substring of s from 1-up position m to n inclusive.
// Negative indices -len .. -1 alias to 0 .. len-1.
func BIF_substr_1_up(input1, input2, input3 *Mlrval) *Mlrval {
func BIF_substr_1_up(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
// Handle UTF-8 correctly: len(input1.printrep) will count bytes, not runes.
runes := []rune(input1.printrep)
// Handle UTF-8 correctly: len(input1.AcquireStringValue()) will count bytes, not runes.
runes := []rune(input1.AcquireStringValue())
strlen := int(len(runes))
// For array slices like s[1:2], s[:2], s[1:], when the lower index is
// empty in the DSL expression it comes in here as a 1. But when the upper
// index is empty in the DSL expression it comes in here as "".
if !input2.IsInt() {
return MLRVAL_ERROR
return mlrval.ERROR
}
lowerMindex := input2.intval
lowerMindex := input2.AcquireIntValue()
upperMindex := strlen
if input3.IsEmpty() {
if input3.IsVoid() {
// Keep strlen
} else if !input3.IsInt() {
return MLRVAL_ERROR
return mlrval.ERROR
} else {
upperMindex = input3.intval
upperMindex = input3.AcquireIntValue()
}
// Convert from negative-aliased 1-up to positive-only 0-up
m, mok := UnaliasArrayLengthIndex(strlen, lowerMindex)
n, nok := UnaliasArrayLengthIndex(strlen, upperMindex)
m, mok := unaliasArrayLengthIndex(strlen, lowerMindex)
n, nok := unaliasArrayLengthIndex(strlen, upperMindex)
if !mok || !nok {
return MLRVAL_VOID
return mlrval.VOID
} else if m > n {
return MLRVAL_VOID
return mlrval.VOID
} else {
// Note Golang slice indices are 0-up, and the 1st index is inclusive
// while the 2nd is exclusive. For Miller, indices are 1-up and both
// are inclusive.
return MlrvalFromString(string(runes[m : n+1]))
return mlrval.FromString(string(runes[m : n+1]))
}
}
@ -110,34 +111,34 @@ func BIF_substr_1_up(input1, input2, input3 *Mlrval) *Mlrval {
// substr0(s,m,n) gives substring of s from 0-up position m to n inclusive.
// Negative indices -len .. -1 alias to 0 .. len-1.
func BIF_substr_0_up(input1, input2, input3 *Mlrval) *Mlrval {
func BIF_substr_0_up(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
// Handle UTF-8 correctly: len(input1.printrep) will count bytes, not runes.
runes := []rune(input1.printrep)
// Handle UTF-8 correctly: len(input1.AcquireStringValue()) will count bytes, not runes.
runes := []rune(input1.AcquireStringValue())
strlen := int(len(runes))
// For array slices like s[1:2], s[:2], s[1:], when the lower index is
// empty in the DSL expression it comes in here as a 1. But when the upper
// index is empty in the DSL expression it comes in here as "".
if !input2.IsInt() {
return MLRVAL_ERROR
return mlrval.ERROR
}
lowerMindex := input2.intval
lowerMindex := input2.AcquireIntValue()
if lowerMindex >= 0 {
// Make 1-up
lowerMindex += 1
}
upperMindex := strlen
if input3.IsEmpty() {
if input3.IsVoid() {
// Keep strlen
} else if !input3.IsInt() {
return MLRVAL_ERROR
return mlrval.ERROR
} else {
upperMindex = input3.intval
upperMindex = input3.AcquireIntValue()
if upperMindex >= 0 {
// Make 1-up
upperMindex += 1
@ -145,23 +146,23 @@ func BIF_substr_0_up(input1, input2, input3 *Mlrval) *Mlrval {
}
// Convert from negative-aliased 1-up to positive-only 0-up
m, mok := UnaliasArrayLengthIndex(strlen, lowerMindex)
n, nok := UnaliasArrayLengthIndex(strlen, upperMindex)
m, mok := unaliasArrayLengthIndex(strlen, lowerMindex)
n, nok := unaliasArrayLengthIndex(strlen, upperMindex)
if !mok || !nok {
return MLRVAL_VOID
return mlrval.VOID
} else if m > n {
return MLRVAL_VOID
return mlrval.VOID
} else {
// Note Golang slice indices are 0-up, and the 1st index is inclusive
// while the 2nd is exclusive. For Miller, indices are 1-up and both
// are inclusive.
return MlrvalFromString(string(runes[m : n+1]))
return mlrval.FromString(string(runes[m : n+1]))
}
}
// ================================================================
func BIF_truncate(input1, input2 *Mlrval) *Mlrval {
func BIF_truncate(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsErrorOrAbsent() {
return input1
}
@ -169,59 +170,59 @@ func BIF_truncate(input1, input2 *Mlrval) *Mlrval {
return input2
}
if !input1.IsStringOrVoid() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if !input2.IsInt() {
return MLRVAL_ERROR
return mlrval.ERROR
}
if input2.intval < 0 {
return MLRVAL_ERROR
if input2.AcquireIntValue() < 0 {
return mlrval.ERROR
}
// Handle UTF-8 correctly: len(input1.printrep) will count bytes, not runes.
runes := []rune(input1.printrep)
// Handle UTF-8 correctly: len(input1.AcquireStringValue()) will count bytes, not runes.
runes := []rune(input1.AcquireStringValue())
oldLength := int(len(runes))
maxLength := input2.intval
maxLength := input2.AcquireIntValue()
if oldLength <= maxLength {
return input1
} else {
return MlrvalFromString(string(runes[0:maxLength]))
return mlrval.FromString(string(runes[0:maxLength]))
}
}
// ================================================================
func BIF_lstrip(input1 *Mlrval) *Mlrval {
if input1.mvtype == MT_STRING {
return MlrvalFromString(strings.TrimLeft(input1.printrep, " \t"))
func BIF_lstrip(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsString() {
return mlrval.FromString(strings.TrimLeft(input1.AcquireStringValue(), " \t"))
} else {
return input1
}
}
func BIF_rstrip(input1 *Mlrval) *Mlrval {
if input1.mvtype == MT_STRING {
return MlrvalFromString(strings.TrimRight(input1.printrep, " \t"))
func BIF_rstrip(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsString() {
return mlrval.FromString(strings.TrimRight(input1.AcquireStringValue(), " \t"))
} else {
return input1
}
}
func BIF_strip(input1 *Mlrval) *Mlrval {
if input1.mvtype == MT_STRING {
return MlrvalFromString(strings.Trim(input1.printrep, " \t"))
func BIF_strip(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsString() {
return mlrval.FromString(strings.Trim(input1.AcquireStringValue(), " \t"))
} else {
return input1
}
}
// ----------------------------------------------------------------
func BIF_collapse_whitespace(input1 *Mlrval) *Mlrval {
return MlrvalCollapseWhitespaceRegexp(input1, WhitespaceRegexp())
func BIF_collapse_whitespace(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return BIF_collapse_whitespace_regexp(input1, WhitespaceRegexp())
}
func MlrvalCollapseWhitespaceRegexp(input1 *Mlrval, whitespaceRegexp *regexp.Regexp) *Mlrval {
if input1.mvtype == MT_STRING {
return MlrvalFromString(whitespaceRegexp.ReplaceAllString(input1.printrep, " "))
func BIF_collapse_whitespace_regexp(input1 *mlrval.Mlrval, whitespaceRegexp *regexp.Regexp) *mlrval.Mlrval {
if input1.IsString() {
return mlrval.FromString(whitespaceRegexp.ReplaceAllString(input1.AcquireStringValue(), " "))
} else {
return input1
}
@ -232,37 +233,37 @@ func WhitespaceRegexp() *regexp.Regexp {
}
// ================================================================
func BIF_toupper(input1 *Mlrval) *Mlrval {
if input1.mvtype == MT_STRING {
return MlrvalFromString(strings.ToUpper(input1.printrep))
} else if input1.mvtype == MT_VOID {
func BIF_toupper(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsString() {
return mlrval.FromString(strings.ToUpper(input1.AcquireStringValue()))
} else if input1.IsVoid() {
return input1
} else {
return input1
}
}
func BIF_tolower(input1 *Mlrval) *Mlrval {
if input1.mvtype == MT_STRING {
return MlrvalFromString(strings.ToLower(input1.printrep))
} else if input1.mvtype == MT_VOID {
func BIF_tolower(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsString() {
return mlrval.FromString(strings.ToLower(input1.AcquireStringValue()))
} else if input1.IsVoid() {
return input1
} else {
return input1
}
}
func BIF_capitalize(input1 *Mlrval) *Mlrval {
if input1.mvtype == MT_STRING {
if input1.printrep == "" {
func BIF_capitalize(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsString() {
if input1.AcquireStringValue() == "" {
return input1
} else {
runes := []rune(input1.printrep)
runes := []rune(input1.AcquireStringValue())
rfirst := runes[0]
rrest := runes[1:]
sfirst := strings.ToUpper(string(rfirst))
srest := string(rrest)
return MlrvalFromString(sfirst + srest)
return mlrval.FromString(sfirst + srest)
}
} else {
return input1
@ -270,66 +271,66 @@ func BIF_capitalize(input1 *Mlrval) *Mlrval {
}
// ----------------------------------------------------------------
func BIF_clean_whitespace(input1 *Mlrval) *Mlrval {
func BIF_clean_whitespace(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return BIF_strip(
MlrvalCollapseWhitespaceRegexp(
BIF_collapse_whitespace_regexp(
input1, WhitespaceRegexp(),
),
)
}
// ================================================================
func BIF_hexfmt(input1 *Mlrval) *Mlrval {
if input1.mvtype == MT_INT {
return MlrvalFromString("0x" + strconv.FormatUint(uint64(input1.intval), 16))
func BIF_hexfmt(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsInt() {
return mlrval.FromString("0x" + strconv.FormatUint(uint64(input1.AcquireIntValue()), 16))
} else {
return input1
}
}
// ----------------------------------------------------------------
func fmtnum_is(input1, input2 *Mlrval) *Mlrval {
func fmtnum_is(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input2.IsString() {
return MLRVAL_ERROR
return mlrval.ERROR
}
formatString := input2.printrep
formatter, err := GetMlrvalFormatter(formatString)
formatString := input2.AcquireStringValue()
formatter, err := mlrval.GetFormatter(formatString)
if err != nil {
return MLRVAL_ERROR
return mlrval.ERROR
}
return formatter.Format(input1)
}
func fmtnum_fs(input1, input2 *Mlrval) *Mlrval {
func fmtnum_fs(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input2.IsString() {
return MLRVAL_ERROR
return mlrval.ERROR
}
formatString := input2.printrep
formatter, err := GetMlrvalFormatter(formatString)
formatString := input2.AcquireStringValue()
formatter, err := mlrval.GetFormatter(formatString)
if err != nil {
return MLRVAL_ERROR
return mlrval.ERROR
}
return formatter.Format(input1)
}
func fmtnum_bs(input1, input2 *Mlrval) *Mlrval {
func fmtnum_bs(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input2.IsString() {
return MLRVAL_ERROR
return mlrval.ERROR
}
formatString := input2.printrep
formatter, err := GetMlrvalFormatter(formatString)
formatString := input2.AcquireStringValue()
formatter, err := mlrval.GetFormatter(formatString)
if err != nil {
return MLRVAL_ERROR
return mlrval.ERROR
}
intMv := MlrvalFromInt(lib.BoolToInt(input1.boolval))
intMv := mlrval.FromInt(lib.BoolToInt(input1.AcquireBoolValue()))
return formatter.Format(intMv)
}
var fmtnum_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
var fmtnum_dispositions = [mlrval.MT_DIM][mlrval.MT_DIM]BinaryFunc{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
/*ABSENT */ {_erro, _absn, _absn, _absn, _absn, _absn, _absn, _erro, _erro, _erro, _erro},
@ -344,6 +345,6 @@ var fmtnum_dispositions = [MT_DIM][MT_DIM]BinaryFunc{
/*FUNC */ {_erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro, _erro},
}
func BIF_fmtnum(input1, input2 *Mlrval) *Mlrval {
return fmtnum_dispositions[input1.mvtype][input2.mvtype](input1, input2)
func BIF_fmtnum(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return fmtnum_dispositions[input1.Type()][input2.Type()](input1, input2)
}

View file

@ -0,0 +1,46 @@
package bifs
import (
"os"
"os/exec"
"runtime"
"strings"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/platform"
"github.com/johnkerl/miller/internal/pkg/version"
)
func BIF_version() *mlrval.Mlrval {
return mlrval.FromString(version.STRING)
}
func BIF_os() *mlrval.Mlrval {
return mlrval.FromString(runtime.GOOS)
}
func BIF_hostname() *mlrval.Mlrval {
hostname, err := os.Hostname()
if err != nil {
return mlrval.ERROR
} else {
return mlrval.FromString(hostname)
}
}
func BIF_system(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsStringOrVoid() {
return mlrval.ERROR
}
commandString := input1.AcquireStringValue()
shellRunArray := platform.GetShellRunArray(commandString)
outputBytes, err := exec.Command(shellRunArray[0], shellRunArray[1:]...).Output()
if err != nil {
return mlrval.ERROR
}
outputString := strings.TrimRight(string(outputBytes), "\n")
return mlrval.FromString(outputString)
}

288
internal/pkg/bifs/types.go Normal file
View file

@ -0,0 +1,288 @@
package bifs
import (
"fmt"
"os"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
// ================================================================
func BIF_typeof(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromString(input1.GetTypeName())
}
// ----------------------------------------------------------------
func string_to_int(input1 *mlrval.Mlrval) *mlrval.Mlrval {
i, ok := lib.TryIntFromString(input1.AcquireStringValue())
if ok {
return mlrval.FromInt(i)
} else {
return mlrval.ERROR
}
}
func float_to_int(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(int(input1.AcquireFloatValue()))
}
func bool_to_int(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.AcquireBoolValue() == true {
return mlrval.FromInt(1)
} else {
return mlrval.FromInt(0)
}
}
var to_int_dispositions = [mlrval.MT_DIM]UnaryFunc{
/*ERROR */ _erro1,
/*ABSENT */ _absn1,
/*NULL */ _null1,
/*VOID */ _void1,
/*STRING */ string_to_int,
/*INT */ _1u___,
/*FLOAT */ float_to_int,
/*BOOL */ bool_to_int,
/*ARRAY */ _erro1,
/*MAP */ _erro1,
/*FUNC */ _erro1,
}
func BIF_int(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return to_int_dispositions[input1.Type()](input1)
}
// ----------------------------------------------------------------
func string_to_float(input1 *mlrval.Mlrval) *mlrval.Mlrval {
f, ok := lib.TryFloatFromString(input1.AcquireStringValue())
if ok {
return mlrval.FromFloat(f)
} else {
return mlrval.ERROR
}
}
func int_to_float(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromFloat(float64(input1.AcquireIntValue()))
}
func bool_to_float(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.AcquireBoolValue() == true {
return mlrval.FromFloat(1.0)
} else {
return mlrval.FromFloat(0.0)
}
}
var to_float_dispositions = [mlrval.MT_DIM]UnaryFunc{
/*ERROR */ _erro1,
/*ABSENT */ _absn1,
/*NULL */ _null1,
/*VOID */ _void1,
/*STRING */ string_to_float,
/*INT */ int_to_float,
/*FLOAT */ _1u___,
/*BOOL */ bool_to_float,
/*ARRAY */ _erro1,
/*MAP */ _erro1,
/*FUNC */ _erro1,
}
func BIF_float(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return to_float_dispositions[input1.Type()](input1)
}
// ----------------------------------------------------------------
func string_to_boolean(input1 *mlrval.Mlrval) *mlrval.Mlrval {
b, ok := lib.TryBoolFromBoolString(input1.AcquireStringValue())
if ok {
return mlrval.FromBool(b)
} else {
return mlrval.ERROR
}
}
func int_to_bool(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireIntValue() != 0)
}
func float_to_bool(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.AcquireFloatValue() != 0.0)
}
var to_boolean_dispositions = [mlrval.MT_DIM]UnaryFunc{
/*ERROR */ _erro1,
/*ABSENT */ _absn1,
/*NULL */ _null1,
/*VOID */ _void1,
/*STRING */ string_to_boolean,
/*INT */ int_to_bool,
/*FLOAT */ float_to_bool,
/*BOOL */ _1u___,
/*ARRAY */ _erro1,
/*MAP */ _erro1,
/*FUNC */ _erro1,
}
func BIF_boolean(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return to_boolean_dispositions[input1.Type()](input1)
}
// ----------------------------------------------------------------
func BIF_is_absent(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsAbsent())
}
func BIF_is_error(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsError())
}
func BIF_is_bool(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsBool())
}
func BIF_is_boolean(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsBool())
}
func BIF_is_empty(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsVoid() {
return mlrval.TRUE
} else if input1.IsString() {
if input1.AcquireStringValue() == "" {
return mlrval.TRUE
} else {
return mlrval.FALSE
}
} else {
return mlrval.FALSE
}
}
func BIF_is_emptymap(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsMap() && input1.AcquireMapValue().IsEmpty())
}
func BIF_is_float(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsFloat())
}
func BIF_is_int(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsInt())
}
func BIF_is_map(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsMap())
}
func BIF_is_array(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsArray())
}
func BIF_is_nonemptymap(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsMap() && input1.AcquireMapValue().FieldCount != 0)
}
func BIF_is_notempty(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.IsVoid() {
return mlrval.FALSE
} else if input1.IsString() {
if input1.AcquireStringValue() == "" {
return mlrval.FALSE
} else {
return mlrval.TRUE
}
} else {
return mlrval.TRUE
}
}
func BIF_is_notmap(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(!input1.IsMap())
}
func BIF_is_notarray(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(!input1.IsArray())
}
func BIF_is_notnull(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(!input1.IsAbsent() && !input1.IsVoid())
}
func BIF_is_null(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsAbsent() || input1.IsVoid())
}
func BIF_is_numeric(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsInt() || input1.IsFloat())
}
func BIF_is_present(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(!input1.IsAbsent())
}
func BIF_is_string(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromBool(input1.IsStringOrVoid())
}
// ----------------------------------------------------------------
func assertingCommon(input1, check *mlrval.Mlrval, description string, context *types.Context) *mlrval.Mlrval {
if check.IsFalse() {
// TODO: get context as in the C impl
//fprintf(stderr, "%s: %s type-assertion failed at NR=%lld FNR=%lld FILENAME=%s\n",
//MLR_GLOBALS.bargv0, pstate->desc, pvars->pctx->nr, pvars->pctx->fnr, pvars->pctx->filename);
//exit(1);
fmt.Fprintf(
os.Stderr,
"mlr: %s type-assertion failed at NR=%d FNR=%d FILENAME=%s\n",
description,
context.NR,
context.FNR,
context.FILENAME,
)
os.Exit(1)
}
return input1
}
func BIF_asserting_absent(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_absent(input1), "is_absent", context)
}
func BIF_asserting_error(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_error(input1), "is_error", context)
}
func BIF_asserting_bool(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_bool(input1), "is_bool", context)
}
func BIF_asserting_boolean(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_boolean(input1), "is_boolean", context)
}
func BIF_asserting_empty(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_empty(input1), "is_empty", context)
}
func BIF_asserting_emptyMap(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_emptymap(input1), "is_empty_map", context)
}
func BIF_asserting_float(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_float(input1), "is_float", context)
}
func BIF_asserting_int(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_int(input1), "is_int", context)
}
func BIF_asserting_map(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_map(input1), "is_map", context)
}
func BIF_asserting_array(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_array(input1), "is_array", context)
}
func BIF_asserting_nonempty_map(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_nonemptymap(input1), "is_non_empty_map", context)
}
func BIF_asserting_not_empty(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_notempty(input1), "is_not_empty", context)
}
func BIF_asserting_not_map(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_notmap(input1), "is_not_map", context)
}
func BIF_asserting_not_array(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_notarray(input1), "is_not_array", context)
}
func BIF_asserting_not_null(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_notnull(input1), "is_not_null", context)
}
func BIF_asserting_null(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_null(input1), "is_null", context)
}
func BIF_asserting_numeric(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_numeric(input1), "is_numeric", context)
}
func BIF_asserting_present(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_present(input1), "is_present", context)
}
func BIF_asserting_string(input1 *mlrval.Mlrval, context *types.Context) *mlrval.Mlrval {
return assertingCommon(input1, BIF_is_string(input1), "is_string", context)
}

View file

@ -15,7 +15,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/colorizer"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// FinalizeReaderOptions does a few things.
@ -2584,7 +2584,7 @@ In general --no-hash-records is faster, and is the default. For specific use-cas
data having many fields, and many of them being processed during a given processing run,
--hash-records might offer a slight performance benefit.`,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
types.HashRecords(true)
mlrval.HashRecords(true)
*pargi += 1
},
},
@ -2593,7 +2593,7 @@ data having many fields, and many of them being processed during a given process
name: "--no-hash-records",
help: `See --hash-records.`,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
types.HashRecords(false)
mlrval.HashRecords(false)
*pargi += 1
},
},
@ -2603,7 +2603,7 @@ data having many fields, and many of them being processed during a given process
altNames: []string{"-S"},
help: `Don't treat values like 123 or 456.7 in data files as int/float; leave them as strings.`,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
types.SetInferrerStringOnly()
mlrval.SetInferrerStringOnly()
*pargi += 1
},
},
@ -2613,7 +2613,7 @@ data having many fields, and many of them being processed during a given process
altNames: []string{"-A"},
help: `Cast all integers in data files to floats.`,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
types.SetInferrerIntAsFloat()
mlrval.SetInferrerIntAsFloat()
*pargi += 1
},
},
@ -2623,7 +2623,7 @@ data having many fields, and many of them being processed during a given process
altNames: []string{"-O"},
help: `Treat numbers like 0123 in data files as string "0123", not octal for decimal 83 etc.`,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
types.SetInferrerNoOctal()
mlrval.SetInferrerNoOctal()
*pargi += 1
},
},

View file

@ -75,8 +75,8 @@ import (
"github.com/johnkerl/miller/internal/pkg/auxents/help"
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/transformers"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/version"
)
@ -280,7 +280,7 @@ func parseCommandLinePassTwo(
// Set an optional global formatter for floating-point values
if options.WriterOptions.FPOFMT != "" {
err = types.SetMlrvalFloatOutputFormat(options.WriterOptions.FPOFMT)
err = mlrval.SetFloatOutputFormat(options.WriterOptions.FPOFMT)
if err != nil {
return options, recordTransformers, err
}

File diff suppressed because it is too large Load diff

View file

@ -8,10 +8,11 @@ import (
"errors"
"fmt"
"github.com/johnkerl/miller/internal/pkg/bifs"
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
// ----------------------------------------------------------------
@ -88,7 +89,7 @@ func (root *RootNode) BuildMultipleArityFunctionCallsiteNode(
// ----------------------------------------------------------------
type ZaryFunctionCallsiteNode struct {
zaryFunc types.ZaryFunc
zaryFunc bifs.ZaryFunc
}
func (root *RootNode) BuildZaryFunctionCallsiteNode(
@ -116,13 +117,13 @@ func (root *RootNode) BuildZaryFunctionCallsiteNode(
func (node *ZaryFunctionCallsiteNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.zaryFunc()
}
// ----------------------------------------------------------------
type UnaryFunctionCallsiteNode struct {
unaryFunc types.UnaryFunc
unaryFunc bifs.UnaryFunc
evaluable1 IEvaluable
}
@ -157,13 +158,13 @@ func (root *RootNode) BuildUnaryFunctionCallsiteNode(
func (node *UnaryFunctionCallsiteNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.unaryFunc(node.evaluable1.Evaluate(state))
}
// ----------------------------------------------------------------
type UnaryFunctionWithContextCallsiteNode struct {
unaryFuncWithContext types.UnaryFuncWithContext
unaryFuncWithContext bifs.UnaryFuncWithContext
evaluable1 IEvaluable
}
@ -198,13 +199,13 @@ func (root *RootNode) BuildUnaryFunctionWithContextCallsiteNode(
func (node *UnaryFunctionWithContextCallsiteNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.unaryFuncWithContext(node.evaluable1.Evaluate(state), state.Context)
}
// ----------------------------------------------------------------
type BinaryFunctionCallsiteNode struct {
binaryFunc types.BinaryFunc
binaryFunc bifs.BinaryFunc
evaluable1 IEvaluable
evaluable2 IEvaluable
}
@ -271,7 +272,7 @@ func (root *RootNode) BuildBinaryFunctionCallsiteNode(
func (node *BinaryFunctionCallsiteNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.binaryFunc(
node.evaluable1.Evaluate(state),
node.evaluable2.Evaluate(state),
@ -321,7 +322,7 @@ func (root *RootNode) BuildBinaryFunctionWithStateCallsiteNode(
func (node *BinaryFunctionWithStateCallsiteNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.binaryFuncWithState(
node.evaluable1.Evaluate(state),
node.evaluable2.Evaluate(state),
@ -378,7 +379,7 @@ func (root *RootNode) BuildTernaryFunctionWithStateCallsiteNode(
func (node *TernaryFunctionWithStateCallsiteNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.ternaryFuncWithState(
node.evaluable1.Evaluate(state),
node.evaluable2.Evaluate(state),
@ -391,9 +392,9 @@ func (node *TernaryFunctionWithStateCallsiteNode) Evaluate(
// RegexCaptureBinaryFunctionCallsiteNode special-cases the =~ and !=~
// operators which set the CST State object's captures array for "\1".."\9".
// This is identical to BinaryFunctionCallsite except that
// BinaryFunctionCallsite's impl function takes two *types.Mlrval arguments and
// returns a *types.Mlrval, whereas RegexCaptureBinaryFunctionCallsiteNode's
// impl function takes two *types.Mlrval arguments but returns *types.Mlrval
// BinaryFunctionCallsite's impl function takes two *mlrval.Mlrval arguments and
// returns a *mlrval.Mlrval, whereas RegexCaptureBinaryFunctionCallsiteNode's
// impl function takes two *mlrval.Mlrval arguments but returns *mlrval.Mlrval
// along with a []string captures array. The captures are stored in the State
// object for use in subsequent statements.
//
@ -420,7 +421,7 @@ func (node *TernaryFunctionWithStateCallsiteNode) Evaluate(
// !=~ callsites only -- not sub/gsub, and not the capture-using replacement
// statements like '$y = "\2:\1".
type RegexCaptureBinaryFunctionCallsiteNode struct {
regexCaptureBinaryFunc types.RegexCaptureBinaryFunc
regexCaptureBinaryFunc bifs.RegexCaptureBinaryFunc
evaluable1 IEvaluable
evaluable2 IEvaluable
}
@ -461,7 +462,7 @@ func (root *RootNode) BuildRegexCaptureBinaryFunctionCallsiteNode(
func (node *RegexCaptureBinaryFunctionCallsiteNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
output, captures := node.regexCaptureBinaryFunc(
node.evaluable1.Evaluate(state),
node.evaluable2.Evaluate(state),
@ -515,7 +516,7 @@ func (root *RootNode) BuildDotCallsiteNode(
func (node *DotCallsiteNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
value1 := node.evaluable1.Evaluate(state)
mapvalue1 := value1.GetMap()
@ -524,23 +525,20 @@ func (node *DotCallsiteNode) Evaluate(
// Case 1: map.attribute as shorthand for map["attribute"]
value2 := mapvalue1.Get(node.string2)
if value2 == nil {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
} else {
return value2
}
} else {
// Case 2: string concatenation
value2 := node.evaluable2.Evaluate(state)
return types.BIF_dot(
value1,
value2,
)
return bifs.BIF_dot(value1, value2)
}
}
// ----------------------------------------------------------------
type TernaryFunctionCallsiteNode struct {
ternaryFunc types.TernaryFunc
ternaryFunc bifs.TernaryFunc
evaluable1 IEvaluable
evaluable2 IEvaluable
evaluable3 IEvaluable
@ -596,7 +594,7 @@ func (root *RootNode) BuildTernaryFunctionCallsiteNode(
func (node *TernaryFunctionCallsiteNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.ternaryFunc(
node.evaluable1.Evaluate(state),
node.evaluable2.Evaluate(state),
@ -606,7 +604,7 @@ func (node *TernaryFunctionCallsiteNode) Evaluate(
// ----------------------------------------------------------------
type VariadicFunctionCallsiteNode struct {
variadicFunc types.VariadicFunc
variadicFunc bifs.VariadicFunc
evaluables []IEvaluable
}
@ -658,8 +656,8 @@ func (root *RootNode) BuildVariadicFunctionCallsiteNode(
func (node *VariadicFunctionCallsiteNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
args := make([]*types.Mlrval, len(node.evaluables))
) *mlrval.Mlrval {
args := make([]*mlrval.Mlrval, len(node.evaluables))
for i := range node.evaluables {
args[i] = node.evaluables[i].Evaluate(state)
}
@ -720,8 +718,8 @@ func (root *RootNode) BuildVariadicFunctionWithStateCallsiteNode(
func (node *VariadicFunctionWithStateCallsiteNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
args := make([]*types.Mlrval, len(node.evaluables))
) *mlrval.Mlrval {
args := make([]*mlrval.Mlrval, len(node.evaluables))
for i := range node.evaluables {
args[i] = node.evaluables[i].Evaluate(state)
}
@ -778,14 +776,14 @@ func (root *RootNode) BuildLogicalANDOperatorNode(a, b IEvaluable) *LogicalANDOp
func (node *LogicalANDOperatorNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
aout := node.a.Evaluate(state)
atype := aout.GetType()
if !(atype == types.MT_ABSENT || atype == types.MT_BOOL) {
return types.MLRVAL_ERROR
atype := aout.Type()
if !(atype == mlrval.MT_ABSENT || atype == mlrval.MT_BOOL) {
return mlrval.ERROR
}
if atype == types.MT_ABSENT {
return types.MLRVAL_ABSENT
if atype == mlrval.MT_ABSENT {
return mlrval.ABSENT
}
if aout.IsFalse() {
// This means false && bogus type evaluates to true, which is sad but
@ -796,15 +794,15 @@ func (node *LogicalANDOperatorNode) Evaluate(
}
bout := node.b.Evaluate(state)
btype := bout.GetType()
if !(btype == types.MT_ABSENT || btype == types.MT_BOOL) {
return types.MLRVAL_ERROR
btype := bout.Type()
if !(btype == mlrval.MT_ABSENT || btype == mlrval.MT_BOOL) {
return mlrval.ERROR
}
if btype == types.MT_ABSENT {
return types.MLRVAL_ABSENT
if btype == mlrval.MT_ABSENT {
return mlrval.ABSENT
}
return types.MlrvalLogicalAND(aout, bout)
return bifs.BIF_logical_AND(aout, bout)
}
// ================================================================
@ -826,14 +824,14 @@ func (root *RootNode) BuildLogicalOROperatorNode(a, b IEvaluable) *LogicalOROper
// See the disposition-matrix discussion for LogicalANDOperator.
func (node *LogicalOROperatorNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
aout := node.a.Evaluate(state)
atype := aout.GetType()
if !(atype == types.MT_ABSENT || atype == types.MT_BOOL) {
return types.MLRVAL_ERROR
atype := aout.Type()
if !(atype == mlrval.MT_ABSENT || atype == mlrval.MT_BOOL) {
return mlrval.ERROR
}
if atype == types.MT_ABSENT {
return types.MLRVAL_ABSENT
if atype == mlrval.MT_ABSENT {
return mlrval.ABSENT
}
if aout.IsTrue() {
// This means true || bogus type evaluates to true, which is sad but
@ -844,14 +842,14 @@ func (node *LogicalOROperatorNode) Evaluate(
}
bout := node.b.Evaluate(state)
btype := bout.GetType()
if !(btype == types.MT_ABSENT || btype == types.MT_BOOL) {
return types.MLRVAL_ERROR
btype := bout.Type()
if !(btype == mlrval.MT_ABSENT || btype == mlrval.MT_BOOL) {
return mlrval.ERROR
}
if btype == types.MT_ABSENT {
return types.MLRVAL_ABSENT
if btype == mlrval.MT_ABSENT {
return mlrval.ABSENT
}
return types.MlrvalLogicalOR(aout, bout)
return bifs.BIF_logical_OR(aout, bout)
}
// ================================================================
@ -868,9 +866,9 @@ func (root *RootNode) BuildAbsentCoalesceOperatorNode(a, b IEvaluable) *AbsentCo
// argument is not absent.
func (node *AbsentCoalesceOperatorNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
aout := node.a.Evaluate(state)
if aout.GetType() != types.MT_ABSENT {
if aout.Type() != mlrval.MT_ABSENT {
return aout
}
@ -891,10 +889,10 @@ func (root *RootNode) BuildEmptyCoalesceOperatorNode(a, b IEvaluable) *EmptyCoal
// argument is not absent.
func (node *EmptyCoalesceOperatorNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
aout := node.a.Evaluate(state)
atype := aout.GetType()
if atype == types.MT_ABSENT || atype == types.MT_VOID || (atype == types.MT_STRING && aout.String() == "") {
atype := aout.Type()
if atype == mlrval.MT_ABSENT || atype == mlrval.MT_VOID || (atype == mlrval.MT_STRING && aout.String() == "") {
return node.b.Evaluate(state)
} else {
return aout
@ -909,12 +907,12 @@ func (root *RootNode) BuildStandardTernaryOperatorNode(a, b, c IEvaluable) *Stan
}
func (node *StandardTernaryOperatorNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
aout := node.a.Evaluate(state)
boolValue, isBool := aout.GetBoolValue()
if !isBool {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
// Short-circuit: defer evaluation unless needed
@ -936,12 +934,12 @@ func (node *StandardTernaryOperatorNode) Evaluate(
// for the function-manager lookup table to indicate the arity of the function,
// even though at runtime these functions should not get invoked.
func BinaryShortCircuitPlaceholder(input1, input2 *types.Mlrval) *types.Mlrval {
func BinaryShortCircuitPlaceholder(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
lib.InternalCodingErrorPanic("Short-circuting was not correctly implemented")
return types.MLRVAL_ERROR // not reached
return mlrval.ERROR // not reached
}
func TernaryShortCircuitPlaceholder(input1, input2, input3 *types.Mlrval) *types.Mlrval {
func TernaryShortCircuitPlaceholder(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
lib.InternalCodingErrorPanic("Short-circuting was not correctly implemented")
return types.MLRVAL_ERROR // not reached
return mlrval.ERROR // not reached
}

View file

@ -6,10 +6,11 @@
package cst
import (
"github.com/johnkerl/miller/internal/pkg/bifs"
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
// ----------------------------------------------------------------
@ -42,12 +43,12 @@ func (node *RootNode) BuildArrayLiteralNode(
func (node *ArrayLiteralNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
mlrvals := make([]types.Mlrval, len(node.evaluables))
) *mlrval.Mlrval {
mlrvals := make([]mlrval.Mlrval, len(node.evaluables))
for i := range node.evaluables {
mlrvals[i] = *node.evaluables[i].Evaluate(state)
}
return types.MlrvalFromArrayReference(mlrvals)
return mlrval.FromArray(mlrvals)
}
// ----------------------------------------------------------------
@ -82,7 +83,7 @@ func (node *RootNode) BuildArrayOrMapIndexAccessNode(
func (node *CollectionIndexAccessNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
baseMlrval := node.baseEvaluable.Evaluate(state)
indexMlrval := node.indexEvaluable.Evaluate(state)
@ -96,21 +97,21 @@ func (node *CollectionIndexAccessNode) Evaluate(
} else if baseMlrval.IsStringOrVoid() {
mindex, isInt := indexMlrval.GetIntValue()
if !isInt {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
// Handle UTF-8 correctly: len(input1.printrep) will count bytes, not runes.
runes := []rune(baseMlrval.String())
// Miller uses 1-up, and negatively aliased, indexing for strings and arrays.
zindex, inBounds := types.UnaliasArrayLengthIndex(len(runes), mindex)
zindex, inBounds := mlrval.UnaliasArrayLengthIndex(len(runes), mindex)
if !inBounds {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
return types.MlrvalFromString(string(runes[zindex]))
return mlrval.FromString(string(runes[zindex]))
} else if baseMlrval.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
}
@ -155,55 +156,55 @@ func (node *RootNode) BuildArraySliceAccessNode(
func (node *ArraySliceAccessNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
baseMlrval := node.baseEvaluable.Evaluate(state)
lowerIndexMlrval := node.lowerIndexEvaluable.Evaluate(state)
upperIndexMlrval := node.upperIndexEvaluable.Evaluate(state)
if baseMlrval.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
if baseMlrval.IsString() {
return types.BIF_substr_1_up(baseMlrval, lowerIndexMlrval, upperIndexMlrval)
return bifs.BIF_substr_1_up(baseMlrval, lowerIndexMlrval, upperIndexMlrval)
}
array := baseMlrval.GetArray()
if array == nil {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
n := len(array)
if lowerIndexMlrval.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
if upperIndexMlrval.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
lowerIndex, ok := lowerIndexMlrval.GetIntValue()
if !ok {
if lowerIndexMlrval.IsEmpty() {
if lowerIndexMlrval.IsVoid() {
lowerIndex = 1
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
}
upperIndex, ok := upperIndexMlrval.GetIntValue()
if !ok {
if upperIndexMlrval.IsEmpty() {
if upperIndexMlrval.IsVoid() {
upperIndex = n
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
}
// UnaliasArrayIndex returns a boolean second return value to indicate
// whether the index is in range. But here, for the slicing operation, we
// inspect the in-range-ness ourselves so we discard that 2nd return value.
lowerZindex, _ := types.UnaliasArrayIndex(&array, lowerIndex)
upperZindex, _ := types.UnaliasArrayIndex(&array, upperIndex)
lowerZindex, _ := mlrval.UnaliasArrayIndex(&array, lowerIndex)
upperZindex, _ := mlrval.UnaliasArrayIndex(&array, upperIndex)
if lowerZindex > upperZindex {
return types.MlrvalFromArrayReference(make([]types.Mlrval, 0))
return mlrval.FromArray(make([]mlrval.Mlrval, 0))
}
// Semantics: say x=[1,2,3,4,5]. Then x[3:10] is [3,4,5].
@ -220,13 +221,13 @@ func (node *ArraySliceAccessNode) Evaluate(
if lowerZindex < 0 {
lowerZindex = 0
if lowerZindex > upperZindex {
return types.MlrvalFromArrayReference(make([]types.Mlrval, 0))
return mlrval.FromArray(make([]mlrval.Mlrval, 0))
}
}
if upperZindex > n-1 {
upperZindex = n - 1
if lowerZindex > upperZindex {
return types.MlrvalFromArrayReference(make([]types.Mlrval, 0))
return mlrval.FromArray(make([]mlrval.Mlrval, 0))
}
}
@ -234,7 +235,7 @@ func (node *ArraySliceAccessNode) Evaluate(
// Miller slices have inclusive lower bound, inclusive upper bound.
var m = upperZindex - lowerZindex + 1
retval := make([]types.Mlrval, m)
retval := make([]mlrval.Mlrval, m)
di := 0
for si := lowerZindex; si <= upperZindex; si++ {
@ -242,7 +243,7 @@ func (node *ArraySliceAccessNode) Evaluate(
di++
}
return types.MlrvalFromArrayReference(retval)
return mlrval.FromArray(retval)
}
// ================================================================
@ -273,23 +274,23 @@ func (node *RootNode) BuildPositionalFieldNameNode(
// TODO: code-dedupe these next four Evaluate methods
func (node *PositionalFieldNameNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
indexMlrval := node.indexEvaluable.Evaluate(state)
if indexMlrval.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
index, ok := indexMlrval.GetIntValue()
if !ok {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
name, ok := state.Inrec.GetNameAtPositionalIndex(index)
if !ok {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
return types.MlrvalFromString(name)
return mlrval.FromString(name)
}
// ================================================================
@ -319,20 +320,20 @@ func (node *RootNode) BuildPositionalFieldValueNode(
func (node *PositionalFieldValueNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
indexMlrval := node.indexEvaluable.Evaluate(state)
if indexMlrval.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
index, ok := indexMlrval.GetIntValue()
if !ok {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
retval := state.Inrec.GetWithPositionalIndex(index)
if retval == nil {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
return retval
@ -372,41 +373,41 @@ func (node *RootNode) BuildArrayOrMapPositionalNameAccessNode(
func (node *ArrayOrMapPositionalNameAccessNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
baseMlrval := node.baseEvaluable.Evaluate(state)
indexMlrval := node.indexEvaluable.Evaluate(state)
if indexMlrval.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
index, ok := indexMlrval.GetIntValue()
if !ok {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
if baseMlrval.IsArray() {
n, _ := baseMlrval.GetArrayLength()
zindex, ok := types.UnaliasArrayLengthIndex(int(n), index)
zindex, ok := mlrval.UnaliasArrayLengthIndex(int(n), index)
if ok {
return types.MlrvalFromInt(zindex + 1) // Miller user-space indices are 1-up
return mlrval.FromInt(zindex + 1) // Miller user-space indices are 1-up
} else {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
} else if baseMlrval.IsMap() {
name, ok := baseMlrval.GetMap().GetNameAtPositionalIndex(index)
if !ok {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
} else {
return types.MlrvalFromString(name)
return mlrval.FromString(name)
}
} else if baseMlrval.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
}
@ -444,17 +445,17 @@ func (node *RootNode) BuildArrayOrMapPositionalValueAccessNode(
func (node *ArrayOrMapPositionalValueAccessNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
baseMlrval := node.baseEvaluable.Evaluate(state)
indexMlrval := node.indexEvaluable.Evaluate(state)
if indexMlrval.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
index, ok := indexMlrval.GetIntValue()
if !ok {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
if baseMlrval.IsArray() {
@ -465,16 +466,16 @@ func (node *ArrayOrMapPositionalValueAccessNode) Evaluate(
} else if baseMlrval.IsMap() {
value := baseMlrval.GetMap().GetWithPositionalIndex(index)
if value == nil {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
return value
} else if baseMlrval.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
}
@ -536,8 +537,8 @@ func (node *RootNode) BuildMapLiteralNode(
func (node *MapLiteralNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
output := types.MlrvalFromEmptyMap()
) *mlrval.Mlrval {
output := mlrval.FromEmptyMap()
for i := range node.evaluablePairs {
key := node.evaluablePairs[i].Key.Evaluate(state)

View file

@ -10,8 +10,8 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
type CondBlockNode struct {
@ -46,7 +46,7 @@ func (root *RootNode) BuildCondBlockNode(astNode *dsl.ASTNode) (*CondBlockNode,
func (node *CondBlockNode) Execute(
state *runtime.State,
) (*BlockExitPayload, error) {
condition := types.MLRVAL_TRUE
condition := mlrval.TRUE
if node.conditionNode != nil {
condition = node.conditionNode.Evaluate(state)
}

View file

@ -45,6 +45,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/output"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
@ -54,13 +55,13 @@ import (
// Shared by emit and emitp
type tEmitToRedirectFunc func(
newrec *types.Mlrmap,
newrec *mlrval.Mlrmap,
state *runtime.State,
) error
type tEmitExecutorFunc func(
names []string,
values []*types.Mlrval,
values []*mlrval.Mlrval,
state *runtime.State,
) error
@ -299,7 +300,7 @@ func (node *EmitXStatementNode) Execute(state *runtime.State) (*BlockExitPayload
if node.topLevelEvaluableMap == nil {
// 'emit @a', 'emit (@a, @b)', etc.
names := node.topLevelNameList
values := make([]*types.Mlrval, len(names))
values := make([]*mlrval.Mlrval, len(names))
for i, evaluable := range node.topLevelEvaluableList {
values[i] = evaluable.Evaluate(state)
}
@ -317,7 +318,7 @@ func (node *EmitXStatementNode) Execute(state *runtime.State) (*BlockExitPayload
return nil, nil
}
names := make([]string, parentMapValue.FieldCount)
values := make([]*types.Mlrval, parentMapValue.FieldCount)
values := make([]*mlrval.Mlrval, parentMapValue.FieldCount)
i := 0
for pe := parentMapValue.Head; pe != nil; pe = pe.Next {
@ -362,7 +363,7 @@ func (node *EmitXStatementNode) Execute(state *runtime.State) (*BlockExitPayload
func (node *EmitXStatementNode) executeNonIndexedNonLashedEmit(
names []string,
values []*types.Mlrval,
values []*mlrval.Mlrval,
state *runtime.State,
) error {
for i, value := range values {
@ -373,7 +374,7 @@ func (node *EmitXStatementNode) executeNonIndexedNonLashedEmit(
valueAsMap := value.GetMap() // nil if not a map
if valueAsMap == nil {
newrec := types.NewMlrmapAsRecord()
newrec := mlrval.NewMlrmapAsRecord()
newrec.PutCopy(names[i], value)
err := node.emitToRedirectFunc(newrec, state)
if err != nil {
@ -383,7 +384,7 @@ func (node *EmitXStatementNode) executeNonIndexedNonLashedEmit(
} else {
recurse := valueAsMap.IsNested()
if !recurse {
newrec := types.NewMlrmapAsRecord()
newrec := mlrval.NewMlrmapAsRecord()
for pe := valueAsMap.Head; pe != nil; pe = pe.Next {
newrec.PutCopy(pe.Key, pe.Value)
}
@ -394,7 +395,7 @@ func (node *EmitXStatementNode) executeNonIndexedNonLashedEmit(
} else { // recurse
nextLevelNames := make([]string, 0)
nextLevelValues := make([]*types.Mlrval, 0)
nextLevelValues := make([]*mlrval.Mlrval, 0)
for pe := value.GetMap().Head; pe != nil; pe = pe.Next {
nextLevelNames = append(nextLevelNames, pe.Key)
nextLevelValues = append(nextLevelValues, pe.Value.Copy())
@ -409,14 +410,14 @@ func (node *EmitXStatementNode) executeNonIndexedNonLashedEmit(
func (node *EmitXStatementNode) executeNonIndexedNonLashedEmitP(
names []string,
values []*types.Mlrval,
values []*mlrval.Mlrval,
state *runtime.State,
) error {
for i, value := range values {
if value.IsAbsent() {
continue
}
newrec := types.NewMlrmapAsRecord()
newrec := mlrval.NewMlrmapAsRecord()
newrec.PutCopy(names[i], value)
err := node.emitToRedirectFunc(newrec, state)
if err != nil {
@ -433,14 +434,14 @@ func (node *EmitXStatementNode) executeNonIndexedNonLashedEmitP(
func (node *EmitXStatementNode) executeNonIndexedLashedEmit(
names []string,
values []*types.Mlrval,
values []*mlrval.Mlrval,
state *runtime.State,
) error {
lib.InternalCodingErrorIf(len(values) < 1)
leadingValueAsMap := values[0].GetMap()
if leadingValueAsMap == nil {
// Emit a record like a=1,b=2
newrec := types.NewMlrmapAsRecord()
newrec := mlrval.NewMlrmapAsRecord()
for i, value := range values {
if value.IsAbsent() {
continue
@ -462,7 +463,7 @@ func (node *EmitXStatementNode) executeNonIndexedLashedEmit(
valueAsMap := value.GetMap() // nil if not a map
if valueAsMap == nil {
newrec := types.NewMlrmapAsRecord()
newrec := mlrval.NewMlrmapAsRecord()
newrec.PutCopy(names[i], value)
err := node.emitToRedirectFunc(newrec, state)
if err != nil {
@ -472,7 +473,7 @@ func (node *EmitXStatementNode) executeNonIndexedLashedEmit(
} else {
recurse := valueAsMap.IsNested()
if !recurse {
newrec := types.NewMlrmapAsRecord()
newrec := mlrval.NewMlrmapAsRecord()
for pe := valueAsMap.Head; pe != nil; pe = pe.Next {
newrec.PutCopy(pe.Key, pe.Value)
}
@ -483,7 +484,7 @@ func (node *EmitXStatementNode) executeNonIndexedLashedEmit(
} else { // recurse
nextLevelNames := make([]string, 0)
nextLevelValues := make([]*types.Mlrval, 0)
nextLevelValues := make([]*mlrval.Mlrval, 0)
for pe := value.GetMap().Head; pe != nil; pe = pe.Next {
nextLevelNames = append(nextLevelNames, pe.Key)
nextLevelValues = append(nextLevelValues, pe.Value.Copy())
@ -499,10 +500,10 @@ func (node *EmitXStatementNode) executeNonIndexedLashedEmit(
func (node *EmitXStatementNode) executeNonIndexedLashedEmitP(
names []string,
values []*types.Mlrval,
values []*mlrval.Mlrval,
state *runtime.State,
) error {
newrec := types.NewMlrmapAsRecord()
newrec := mlrval.NewMlrmapAsRecord()
for i, value := range values {
if value.IsAbsent() {
@ -518,11 +519,11 @@ func (node *EmitXStatementNode) executeNonIndexedLashedEmitP(
// ----------------------------------------------------------------
func (node *EmitXStatementNode) executeIndexed(
names []string,
values []*types.Mlrval,
values []*mlrval.Mlrval,
state *runtime.State,
) error {
emittableMaps := make([]*types.Mlrmap, len(values))
emittableMaps := make([]*mlrval.Mlrmap, len(values))
for i, value := range values {
if value.IsAbsent() {
return nil
@ -535,7 +536,7 @@ func (node *EmitXStatementNode) executeIndexed(
}
// TODO: libify this
indices := make([]*types.Mlrval, len(node.indexEvaluables))
indices := make([]*mlrval.Mlrval, len(node.indexEvaluables))
for i := range node.indexEvaluables {
indices[i] = node.indexEvaluables[i].Evaluate(state)
if indices[i].IsAbsent() {
@ -550,7 +551,7 @@ func (node *EmitXStatementNode) executeIndexed(
if !node.isEmitP {
if !node.isLashed {
return node.executeIndexedNonLashedEmitAux(
types.NewMlrmapAsRecord(),
mlrval.NewMlrmapAsRecord(),
names,
emittableMaps,
indices,
@ -558,7 +559,7 @@ func (node *EmitXStatementNode) executeIndexed(
)
} else {
return node.executeIndexedLashedEmitAux(
types.NewMlrmapAsRecord(),
mlrval.NewMlrmapAsRecord(),
names,
emittableMaps,
indices,
@ -568,7 +569,7 @@ func (node *EmitXStatementNode) executeIndexed(
} else {
if !node.isLashed {
return node.executeIndexedNonLashedEmitPAux(
types.NewMlrmapAsRecord(),
mlrval.NewMlrmapAsRecord(),
names,
emittableMaps,
indices,
@ -576,7 +577,7 @@ func (node *EmitXStatementNode) executeIndexed(
)
} else {
return node.executeIndexedLashedEmitPAux(
types.NewMlrmapAsRecord(),
mlrval.NewMlrmapAsRecord(),
names,
emittableMaps,
indices,
@ -650,10 +651,10 @@ func (node *EmitXStatementNode) executeIndexed(
// * indices = ["b"]
func (node *EmitXStatementNode) executeIndexedNonLashedEmitAux(
templateRecord *types.Mlrmap,
templateRecord *mlrval.Mlrmap,
names []string,
emittableMaps []*types.Mlrmap,
indices []*types.Mlrval,
emittableMaps []*mlrval.Mlrmap,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
lib.InternalCodingErrorIf(len(indices) < 1)
@ -663,7 +664,7 @@ func (node *EmitXStatementNode) executeIndexedNonLashedEmitAux(
for i, emittableMap := range emittableMaps {
for pe := emittableMap.Head; pe != nil; pe = pe.Next {
newrec := templateRecord.Copy()
newrec.PutCopy(indexString, types.MlrvalFromString(pe.Key))
newrec.PutCopy(indexString, mlrval.FromString(pe.Key))
if len(indices) == 1 {
valueAsMap := pe.Value.GetMap()
@ -690,7 +691,7 @@ func (node *EmitXStatementNode) executeIndexedNonLashedEmitAux(
node.executeIndexedNonLashedEmitPAux(
newrec,
[]string{names[i]},
[]*types.Mlrmap{valueAsMap},
[]*mlrval.Mlrmap{valueAsMap},
indices[1:],
state,
)
@ -796,10 +797,10 @@ func (node *EmitXStatementNode) executeIndexedNonLashedEmitAux(
// o indices ["b"]
func (node *EmitXStatementNode) executeIndexedLashedEmitAux(
templateRecord *types.Mlrmap,
templateRecord *mlrval.Mlrmap,
names []string,
emittableMaps []*types.Mlrmap,
indices []*types.Mlrval,
emittableMaps []*mlrval.Mlrmap,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
lib.InternalCodingErrorIf(len(indices) < 1)
@ -810,11 +811,11 @@ func (node *EmitXStatementNode) executeIndexedLashedEmitAux(
for pe := leadingMap.Head; pe != nil; pe = pe.Next {
newrec := templateRecord.Copy()
indexValue := types.MlrvalFromString(pe.Key)
indexValue := mlrval.FromString(pe.Key)
newrec.PutCopy(indexString, indexValue)
nextLevelValues := make([]*types.Mlrval, len(emittableMaps))
nextLevelMaps := make([]*types.Mlrmap, len(emittableMaps))
nextLevelValues := make([]*mlrval.Mlrval, len(emittableMaps))
nextLevelMaps := make([]*mlrval.Mlrmap, len(emittableMaps))
for i, emittableMap := range emittableMaps {
if emittableMap != nil {
nextLevelValues[i] = emittableMaps[i].Get(pe.Key)
@ -865,10 +866,10 @@ func (node *EmitXStatementNode) executeIndexedLashedEmitAux(
// Recurses over indices.
func (node *EmitXStatementNode) executeIndexedNonLashedEmitPAux(
templateRecord *types.Mlrmap,
templateRecord *mlrval.Mlrmap,
names []string,
emittableMaps []*types.Mlrmap,
indices []*types.Mlrval,
emittableMaps []*mlrval.Mlrmap,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
lib.InternalCodingErrorIf(len(indices) < 1)
@ -878,7 +879,7 @@ func (node *EmitXStatementNode) executeIndexedNonLashedEmitPAux(
for i, emittableMap := range emittableMaps {
for pe := emittableMap.Head; pe != nil; pe = pe.Next {
newrec := templateRecord.Copy()
newrec.PutCopy(indexString, types.MlrvalFromString(pe.Key))
newrec.PutCopy(indexString, mlrval.FromString(pe.Key))
if len(indices) == 1 {
newrec.PutCopy(names[i], pe.Value)
@ -898,7 +899,7 @@ func (node *EmitXStatementNode) executeIndexedNonLashedEmitPAux(
node.executeIndexedNonLashedEmitPAux(
newrec,
[]string{names[i]},
[]*types.Mlrmap{valueAsMap},
[]*mlrval.Mlrmap{valueAsMap},
indices[1:],
state,
)
@ -911,10 +912,10 @@ func (node *EmitXStatementNode) executeIndexedNonLashedEmitPAux(
}
func (node *EmitXStatementNode) executeIndexedLashedEmitPAux(
templateRecord *types.Mlrmap,
templateRecord *mlrval.Mlrmap,
names []string,
emittableMaps []*types.Mlrmap,
indices []*types.Mlrval,
emittableMaps []*mlrval.Mlrmap,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
lib.InternalCodingErrorIf(len(indices) < 1)
@ -926,12 +927,12 @@ func (node *EmitXStatementNode) executeIndexedLashedEmitPAux(
for pe := leadingMap.Head; pe != nil; pe = pe.Next {
newrec := templateRecord.Copy()
indexValue := types.MlrvalFromString(pe.Key)
indexValue := mlrval.FromString(pe.Key)
newrec.PutCopy(indexString, indexValue)
indexValueString := indexValue.String()
nextLevels := make([]*types.Mlrval, len(emittableMaps))
nextLevelMaps := make([]*types.Mlrmap, len(emittableMaps))
nextLevels := make([]*mlrval.Mlrval, len(emittableMaps))
nextLevelMaps := make([]*mlrval.Mlrmap, len(emittableMaps))
for i, emittableMap := range emittableMaps {
if emittableMap != nil {
nextLevel := emittableMap.Get(indexValueString)
@ -979,7 +980,7 @@ func (node *EmitXStatementNode) executeIndexedLashedEmitPAux(
// ----------------------------------------------------------------
func (node *EmitXStatementNode) emitRecordToRecordStream(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
state *runtime.State,
) error {
// The output channel is always non-nil, except for the Miller REPL.
@ -993,7 +994,7 @@ func (node *EmitXStatementNode) emitRecordToRecordStream(
// ----------------------------------------------------------------
func (node *EmitXStatementNode) emitRecordToFileOrPipe(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
state *runtime.State,
) error {
redirectorTarget := node.redirectorTargetEvaluable.Evaluate(state)

View file

@ -11,6 +11,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/output"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
@ -27,7 +28,7 @@ import (
// in the CST logic, to keep this parser/AST logic simpler.
type tEmitFToRedirectFunc func(
newrec *types.Mlrmap,
newrec *mlrval.Mlrmap,
state *runtime.State,
) error
@ -139,7 +140,7 @@ func (root *RootNode) BuildEmitFStatementNode(astNode *dsl.ASTNode) (IExecutable
}
func (node *EmitFStatementNode) Execute(state *runtime.State) (*BlockExitPayload, error) {
newrec := types.NewMlrmapAsRecord()
newrec := mlrval.NewMlrmapAsRecord()
for i, emitfEvaluable := range node.emitfEvaluables {
emitfName := node.emitfNames[i]
emitfValue := emitfEvaluable.Evaluate(state)
@ -178,7 +179,7 @@ func getNameFromNamedNode(astNode *dsl.ASTNode, description string) (string, err
// ----------------------------------------------------------------
func (node *EmitFStatementNode) emitfToRecordStream(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
state *runtime.State,
) error {
// The output channel is always non-nil, except for the Miller REPL.
@ -192,7 +193,7 @@ func (node *EmitFStatementNode) emitfToRecordStream(
// ----------------------------------------------------------------
func (node *EmitFStatementNode) emitfToFileOrPipe(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
state *runtime.State,
) error {
redirectorTarget := node.redirectorTargetEvaluable.Evaluate(state)

View file

@ -12,8 +12,8 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
type EnvironmentVariableNode struct {
@ -35,14 +35,14 @@ func (root *RootNode) BuildEnvironmentVariableNode(astNode *dsl.ASTNode) (*Envir
func (node *EnvironmentVariableNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
name := node.nameEvaluable.Evaluate(state)
if name.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
if !name.IsString() {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
return types.MlrvalFromString(os.Getenv(name.String()))
return mlrval.FromString(os.Getenv(name.String()))
}

View file

@ -13,8 +13,8 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
// ----------------------------------------------------------------
@ -107,10 +107,10 @@ func (root *RootNode) BuildIndirectFieldValueNode(
func (node *IndirectFieldValueNode) Evaluate(
state *runtime.State,
) *types.Mlrval { // TODO: err
) *mlrval.Mlrval { // TODO: err
fieldName := node.fieldNameEvaluable.Evaluate(state)
if fieldName.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
// For normal DSL use the CST validator will prohibit this from being
@ -119,7 +119,7 @@ func (node *IndirectFieldValueNode) Evaluate(
// print inrec attributes. Also, a UDF/UDS invoked from begin/end could try
// to access the inrec, and that would get past the validator.
if state.Inrec == nil {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
value, err := state.Inrec.GetWithMlrvalIndex(fieldName)
@ -130,7 +130,7 @@ func (node *IndirectFieldValueNode) Evaluate(
os.Exit(1)
}
if value == nil {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
return value
}
@ -157,15 +157,15 @@ func (root *RootNode) BuildIndirectOosvarValueNode(
func (node *IndirectOosvarValueNode) Evaluate(
state *runtime.State,
) *types.Mlrval { // TODO: err
) *mlrval.Mlrval { // TODO: err
oosvarName := node.oosvarNameEvaluable.Evaluate(state)
if oosvarName.IsAbsent() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
value := state.Oosvars.Get(oosvarName.String())
if value == nil {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
return value

View file

@ -9,8 +9,8 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
// ----------------------------------------------------------------
@ -126,7 +126,7 @@ func (node *ForLoopOneVariableNode) Execute(state *runtime.State) (*BlockExitPay
state.Stack.PushStackFrame()
defer state.Stack.PopStackFrame()
for pe := mapval.Head; pe != nil; pe = pe.Next {
mapkey := types.MlrvalFromString(pe.Key)
mapkey := mlrval.FromString(pe.Key)
err := state.Stack.SetAtScope(node.indexVariable, mapkey)
if err != nil {
@ -311,7 +311,7 @@ func (node *ForLoopTwoVariableNode) Execute(state *runtime.State) (*BlockExitPay
state.Stack.PushStackFrame()
defer state.Stack.PopStackFrame()
for pe := mapval.Head; pe != nil; pe = pe.Next {
mapkey := types.MlrvalFromString(pe.Key)
mapkey := mlrval.FromString(pe.Key)
err := state.Stack.SetAtScope(node.keyIndexVariable, mapkey)
if err != nil {
@ -352,7 +352,7 @@ func (node *ForLoopTwoVariableNode) Execute(state *runtime.State) (*BlockExitPay
state.Stack.PushStackFrame()
defer state.Stack.PopStackFrame()
for zindex, element := range arrayval {
mindex := types.MlrvalFromInt(int(zindex + 1))
mindex := mlrval.FromInt(int(zindex + 1))
err := state.Stack.SetAtScope(node.keyIndexVariable, mindex)
if err != nil {
@ -524,20 +524,20 @@ func (node *ForLoopMultivariableNode) Execute(state *runtime.State) (*BlockExitP
// ----------------------------------------------------------------
func (node *ForLoopMultivariableNode) executeOuter(
mlrval *types.Mlrval,
mv *mlrval.Mlrval,
keyIndexVariables []*runtime.StackVariable,
state *runtime.State,
) (*BlockExitPayload, error) {
if len(keyIndexVariables) == 1 {
return node.executeInner(mlrval, keyIndexVariables[0], state)
return node.executeInner(mv, keyIndexVariables[0], state)
}
// else, recurse
if mlrval.IsMap() {
mapval := mlrval.GetMap()
if mv.IsMap() {
mapval := mv.GetMap()
for pe := mapval.Head; pe != nil; pe = pe.Next {
mapkey := types.MlrvalFromString(pe.Key)
mapkey := mlrval.FromString(pe.Key)
err := state.Stack.SetAtScope(keyIndexVariables[0], mapkey)
if err != nil {
@ -563,14 +563,14 @@ func (node *ForLoopMultivariableNode) executeOuter(
}
}
} else if mlrval.IsArray() {
arrayval := mlrval.GetArray()
} else if mv.IsArray() {
arrayval := mv.GetArray()
// Note: Miller user-space array indices ("mindex") are 1-up. Internal
// Go storage ("zindex") is 0-up.
for zindex, element := range arrayval {
mindex := types.MlrvalFromInt(int(zindex + 1))
mindex := mlrval.FromInt(int(zindex + 1))
err := state.Stack.SetAtScope(keyIndexVariables[0], mindex)
if err != nil {
@ -597,7 +597,7 @@ func (node *ForLoopMultivariableNode) executeOuter(
}
}
} else if mlrval.IsAbsent() {
} else if mv.IsAbsent() {
// Data-heterogeneity no-op
}
@ -608,7 +608,7 @@ func (node *ForLoopMultivariableNode) executeOuter(
// return nil, errors.New(
// fmt.Sprintf(
// "mlr: looped-over item is not a map or array; got %s",
// mlrval.GetTypeName(),
// mv.GetTypeName(),
// ),
// )
@ -617,15 +617,15 @@ func (node *ForLoopMultivariableNode) executeOuter(
// ----------------------------------------------------------------
func (node *ForLoopMultivariableNode) executeInner(
mlrval *types.Mlrval,
mv *mlrval.Mlrval,
keyIndexVariable *runtime.StackVariable,
state *runtime.State,
) (*BlockExitPayload, error) {
if mlrval.IsMap() {
mapval := mlrval.GetMap()
if mv.IsMap() {
mapval := mv.GetMap()
for pe := mapval.Head; pe != nil; pe = pe.Next {
mapkey := types.MlrvalFromString(pe.Key)
mapkey := mlrval.FromString(pe.Key)
err := state.Stack.SetAtScope(keyIndexVariable, mapkey)
if err != nil {
@ -656,14 +656,14 @@ func (node *ForLoopMultivariableNode) executeInner(
}
}
} else if mlrval.IsArray() {
arrayval := mlrval.GetArray()
} else if mv.IsArray() {
arrayval := mv.GetArray()
// Note: Miller user-space array indices ("mindex") are 1-up. Internal
// Go storage ("zindex") is 0-up.
for zindex, element := range arrayval {
mindex := types.MlrvalFromInt(int(zindex + 1))
mindex := mlrval.FromInt(int(zindex + 1))
err := state.Stack.SetAtScope(keyIndexVariable, mindex)
if err != nil {
@ -694,7 +694,7 @@ func (node *ForLoopMultivariableNode) executeInner(
}
}
} else if mlrval.IsAbsent() {
} else if mv.IsAbsent() {
// Data-heterogeneity no-op
}
@ -705,7 +705,7 @@ func (node *ForLoopMultivariableNode) executeInner(
// return nil, errors.New(
// fmt.Sprintf(
// "mlr: looped-over item is not a map or array; got %s",
// mlrval.GetTypeName(),
// mv.GetTypeName(),
// ),
// )

View file

@ -13,8 +13,8 @@ import (
"strings"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
// Most function types are in the github.com/johnkerl/miller/internal/pkg/types package. These types, though,
@ -24,29 +24,29 @@ import (
// BinaryFuncWithState is for select, apply, and reduce.
type BinaryFuncWithState func(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval
) *mlrval.Mlrval
// TernaryFuncWithState is for fold.
type TernaryFuncWithState func(
input1 *types.Mlrval,
input2 *types.Mlrval,
input3 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
input3 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval
) *mlrval.Mlrval
// VariadicFuncWithState is for sort.
type VariadicFuncWithState func(
inputs []*types.Mlrval,
inputs []*mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval
) *mlrval.Mlrval
// tHOFSpace is the datatype for the getHOFSpace cache-manager.
type tHOFSpace struct {
udfCallsite *UDFCallsite
argsArray []*types.Mlrval
argsArray []*mlrval.Mlrval
}
// hofCache is persistent data for the getHOFSpace cache-manager.
@ -56,7 +56,7 @@ var hofCache map[string]*tHOFSpace = make(map[string]*tHOFSpace)
// Those functions may be invoked on every record of a big data file, so we try
// to cache data they need for UDF-callsite setup.
func getHOFSpace(
funcVal *types.Mlrval,
funcVal *mlrval.Mlrval,
arity int,
hofName string,
arrayOrMap string,
@ -120,7 +120,7 @@ func getHOFSpace(
}
udfCallsite := NewUDFCallsiteForHigherOrderFunction(udf, arity)
argsArray := make([]*types.Mlrval, arity)
argsArray := make([]*mlrval.Mlrval, arity)
entry = &tHOFSpace{
udfCallsite: udfCallsite,
argsArray: argsArray,
@ -131,7 +131,7 @@ func getHOFSpace(
}
// mustBeNonAbsent checks that a UDF for array reduce/fold/apply returned a value.
func isNonAbsentOrDie(mlrval *types.Mlrval, hofName string) *types.Mlrval {
func isNonAbsentOrDie(mlrval *mlrval.Mlrval, hofName string) *mlrval.Mlrval {
if mlrval.IsAbsent() {
hofCheckDie(mlrval, hofName, "second-argument function must return a value")
}
@ -140,7 +140,7 @@ func isNonAbsentOrDie(mlrval *types.Mlrval, hofName string) *types.Mlrval {
// getKVPairForAccumulatorOrDie checks that a user-supplied accumulator value
// for a map fold is indeed a single-element map.
func getKVPairForAccumulatorOrDie(mlrval *types.Mlrval, hofName string) *types.Mlrmap {
func getKVPairForAccumulatorOrDie(mlrval *mlrval.Mlrval, hofName string) *mlrval.Mlrmap {
kvPair := getKVPair(mlrval)
if kvPair == nil {
hofCheckDie(mlrval, hofName, "accumulator value must be a single-element map")
@ -150,7 +150,7 @@ func getKVPairForAccumulatorOrDie(mlrval *types.Mlrval, hofName string) *types.M
// getKVPairForCallbackOrDie checks that a return value from a UDF for map
// reduce/fold/apply is indeed a single-element map.
func getKVPairForCallbackOrDie(mlrval *types.Mlrval, hofName string) *types.Mlrmap {
func getKVPairForCallbackOrDie(mlrval *mlrval.Mlrval, hofName string) *mlrval.Mlrmap {
kvPair := getKVPair(mlrval)
if kvPair == nil {
hofCheckDie(mlrval, hofName, "second-argument function must return single-element map")
@ -160,7 +160,7 @@ func getKVPairForCallbackOrDie(mlrval *types.Mlrval, hofName string) *types.Mlrm
// hofCheckDie is a helper function for HOFs on maps, to check that the
// user-supplied UDF returned a single-entry map.
func hofCheckDie(mlrval *types.Mlrval, hofName string, message string) {
func hofCheckDie(mlrval *mlrval.Mlrval, hofName string, message string) {
fmt.Fprintf(
os.Stderr,
"mlr: %s: %s; got \"%s\".\n",
@ -172,7 +172,7 @@ func hofCheckDie(mlrval *types.Mlrval, hofName string, message string) {
}
// getKVPair is a helper function getKVPairOrDie.
func getKVPair(mlrval *types.Mlrval) *types.Mlrmap {
func getKVPair(mlrval *mlrval.Mlrval) *mlrval.Mlrmap {
mapval := mlrval.GetMap()
if mapval == nil {
return nil
@ -183,7 +183,7 @@ func getKVPair(mlrval *types.Mlrval) *types.Mlrmap {
return mapval
}
func isFunctionOrDie(mlrval *types.Mlrval, hofName string) {
func isFunctionOrDie(mlrval *mlrval.Mlrval, hofName string) {
if !mlrval.IsFunction() {
fmt.Fprintf(os.Stderr, "mlr: %s: second argument must be a function; got %s.\n",
hofName, mlrval.GetTypeName(),
@ -196,27 +196,27 @@ func isFunctionOrDie(mlrval *types.Mlrval, hofName string) {
// SELECT HOF
func SelectHOF(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
if input1.IsArray() {
return selectArray(input1, input2, state)
} else if input1.IsMap() {
return selectMap(input1, input2, state)
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
}
func selectArray(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputArray := input1.GetArray()
if inputArray == nil { // not an array
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "select")
@ -224,7 +224,7 @@ func selectArray(
udfCallsite := hofSpace.udfCallsite
argsArray := hofSpace.argsArray
outputArray := make([]types.Mlrval, 0, len(inputArray))
outputArray := make([]mlrval.Mlrval, 0, len(inputArray))
for i := range inputArray {
argsArray[0] = &inputArray[i]
@ -242,17 +242,17 @@ func selectArray(
outputArray = append(outputArray, *inputArray[i].Copy())
}
}
return types.MlrvalFromArrayReference(outputArray)
return mlrval.FromArray(outputArray)
}
func selectMap(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputMap := input1.GetMap()
if inputMap == nil { // not a map
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "select")
@ -260,10 +260,10 @@ func selectMap(
udfCallsite := hofSpace.udfCallsite
argsArray := hofSpace.argsArray
outputMap := types.NewMlrmap()
outputMap := mlrval.NewMlrmap()
for pe := inputMap.Head; pe != nil; pe = pe.Next {
argsArray[0] = types.MlrvalFromString(pe.Key)
argsArray[0] = mlrval.FromString(pe.Key)
argsArray[1] = pe.Value
mret := udfCallsite.EvaluateWithArguments(state, udfCallsite.udf, argsArray)
bret, ok := mret.GetBoolValue()
@ -280,34 +280,34 @@ func selectMap(
}
}
return types.MlrvalFromMap(outputMap)
return mlrval.FromMap(outputMap)
}
// ================================================================
// APPLY HOF
func ApplyHOF(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
if input1.IsArray() {
return applyArray(input1, input2, state)
} else if input1.IsMap() {
return applyMap(input1, input2, state)
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
}
func applyArray(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputArray := input1.GetArray()
if inputArray == nil { // not an array
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "apply")
@ -315,7 +315,7 @@ func applyArray(
udfCallsite := hofSpace.udfCallsite
argsArray := hofSpace.argsArray
outputArray := make([]types.Mlrval, len(inputArray))
outputArray := make([]mlrval.Mlrval, len(inputArray))
for i := range inputArray {
argsArray[0] = &inputArray[i]
@ -323,17 +323,17 @@ func applyArray(
isNonAbsentOrDie(&retval, "apply")
outputArray[i] = retval
}
return types.MlrvalFromArrayReference(outputArray)
return mlrval.FromArray(outputArray)
}
func applyMap(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputMap := input1.GetMap()
if inputMap == nil { // not a map
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "apply")
@ -341,43 +341,43 @@ func applyMap(
udfCallsite := hofSpace.udfCallsite
argsArray := hofSpace.argsArray
outputMap := types.NewMlrmap()
outputMap := mlrval.NewMlrmap()
for pe := inputMap.Head; pe != nil; pe = pe.Next {
argsArray[0] = types.MlrvalFromString(pe.Key)
argsArray[0] = mlrval.FromString(pe.Key)
argsArray[1] = pe.Value
retval := udfCallsite.EvaluateWithArguments(state, udfCallsite.udf, argsArray)
kvPair := getKVPairForCallbackOrDie(retval, "apply")
outputMap.PutReference(kvPair.Head.Key, kvPair.Head.Value)
}
return types.MlrvalFromMap(outputMap)
return mlrval.FromMap(outputMap)
}
// ================================================================
// REDUCE HOF
func ReduceHOF(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
if input1.IsArray() {
return reduceArray(input1, input2, state)
} else if input1.IsMap() {
return reduceMap(input1, input2, state)
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
}
func reduceArray(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputArray := input1.GetArray()
if inputArray == nil { // not an array
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "reduce")
@ -401,13 +401,13 @@ func reduceArray(
}
func reduceMap(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputMap := input1.GetMap()
if inputMap == nil { // not a map
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "reduce")
@ -421,44 +421,44 @@ func reduceMap(
}
for pe := inputMap.Head.Next; pe != nil; pe = pe.Next {
argsArray[0] = types.MlrvalFromString(accumulator.Head.Key)
argsArray[0] = mlrval.FromString(accumulator.Head.Key)
argsArray[1] = accumulator.Head.Value
argsArray[2] = types.MlrvalFromString(pe.Key)
argsArray[2] = mlrval.FromString(pe.Key)
argsArray[3] = pe.Value.Copy()
retval := (udfCallsite.EvaluateWithArguments(state, udfCallsite.udf, argsArray))
kvPair := getKVPairForCallbackOrDie(retval, "reduce")
accumulator = kvPair
}
return types.MlrvalFromMap(accumulator)
return mlrval.FromMap(accumulator)
}
// ================================================================
// FOLD HOF
func FoldHOF(
input1 *types.Mlrval,
input2 *types.Mlrval,
input3 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
input3 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
if input1.IsArray() {
return foldArray(input1, input2, input3, state)
} else if input1.IsMap() {
return foldMap(input1, input2, input3, state)
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
}
func foldArray(
input1 *types.Mlrval,
input2 *types.Mlrval,
input3 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
input3 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputArray := input1.GetArray()
if inputArray == nil { // not an array
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "fold")
@ -478,14 +478,14 @@ func foldArray(
}
func foldMap(
input1 *types.Mlrval,
input2 *types.Mlrval,
input3 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
input3 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputMap := input1.GetMap()
if inputMap == nil { // not a map
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "fold")
@ -494,30 +494,30 @@ func foldMap(
argsArray := hofSpace.argsArray
if inputMap.IsEmpty() {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
accumulator := getKVPairForAccumulatorOrDie(input3, "reduce").Copy()
for pe := inputMap.Head; pe != nil; pe = pe.Next {
argsArray[0] = types.MlrvalFromString(accumulator.Head.Key)
argsArray[0] = mlrval.FromString(accumulator.Head.Key)
argsArray[1] = accumulator.Head.Value
argsArray[2] = types.MlrvalFromString(pe.Key)
argsArray[2] = mlrval.FromString(pe.Key)
argsArray[3] = pe.Value.Copy()
retval := (udfCallsite.EvaluateWithArguments(state, udfCallsite.udf, argsArray))
kvPair := getKVPairForCallbackOrDie(retval, "reduce")
accumulator = kvPair
}
return types.MlrvalFromMap(accumulator)
return mlrval.FromMap(accumulator)
}
// ================================================================
// SORT HOF
func SortHOF(
inputs []*types.Mlrval,
inputs []*mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
if len(inputs) == 1 {
if inputs[0].IsArray() {
@ -525,7 +525,7 @@ func SortHOF(
} else if inputs[0].IsMap() {
return sortMK(inputs[0], "")
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
} else if inputs[1].IsString() {
@ -534,7 +534,7 @@ func SortHOF(
} else if inputs[0].IsMap() {
return sortMK(inputs[0], inputs[1].String())
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
} else if inputs[1].IsFunction() {
@ -543,7 +543,7 @@ func SortHOF(
} else if inputs[0].IsMap() {
return sortMF(inputs[0], inputs[1], state)
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
} else {
@ -552,7 +552,7 @@ func SortHOF(
)
os.Exit(1)
}
return types.MLRVAL_ERROR
return mlrval.ERROR
}
// ----------------------------------------------------------------
@ -588,11 +588,11 @@ func decodeSortFlags(flags string) (tSortType, bool) {
// sortA implements sort on array, with string flags rather than callback UDF.
func sortA(
input1 *types.Mlrval,
input1 *mlrval.Mlrval,
flags string,
) *types.Mlrval {
) *mlrval.Mlrval {
if input1.GetArray() == nil { // not an array
return types.MLRVAL_ERROR
return mlrval.ERROR
}
output := input1.Copy()
@ -612,19 +612,19 @@ func sortA(
return output
}
func sortANumerical(array []types.Mlrval, reverse bool) {
func sortANumerical(array []mlrval.Mlrval, reverse bool) {
if !reverse {
sort.Slice(array, func(i, j int) bool {
return types.MlrvalLessThanAsBool(&array[i], &array[j])
return mlrval.LessThan(&array[i], &array[j])
})
} else {
sort.Slice(array, func(i, j int) bool {
return types.MlrvalGreaterThanAsBool(&array[i], &array[j])
return mlrval.GreaterThan(&array[i], &array[j])
})
}
}
func sortALexical(array []types.Mlrval, reverse bool) {
func sortALexical(array []mlrval.Mlrval, reverse bool) {
if !reverse {
sort.Slice(array, func(i, j int) bool {
return array[i].String() < array[j].String()
@ -636,7 +636,7 @@ func sortALexical(array []types.Mlrval, reverse bool) {
}
}
func sortACaseFold(array []types.Mlrval, reverse bool) {
func sortACaseFold(array []mlrval.Mlrval, reverse bool) {
if !reverse {
sort.Slice(array, func(i, j int) bool {
return strings.ToLower(array[i].String()) < strings.ToLower(array[j].String())
@ -650,12 +650,12 @@ func sortACaseFold(array []types.Mlrval, reverse bool) {
// sortA implements sort on map, with string flags rather than callback UDF.
func sortMK(
input1 *types.Mlrval,
input1 *mlrval.Mlrval,
flags string,
) *types.Mlrval {
) *mlrval.Mlrval {
inmap := input1.GetMap()
if inmap == nil { // not a map
return types.MLRVAL_ERROR
return mlrval.ERROR
}
// Copy the keys to an array for sorting.
@ -682,13 +682,13 @@ func sortMK(
}
// Make a new map with keys in the new sort order.
outmap := types.NewMlrmap()
outmap := mlrval.NewMlrmap()
for i := 0; i < n; i++ {
key := keys[i]
outmap.PutCopy(key, inmap.Get(key))
}
return types.MlrvalFromMapReferenced(outmap)
return mlrval.FromMap(outmap)
}
func sortMKNumerical(array []string, reverse bool) {
@ -742,30 +742,30 @@ func sortMKCaseFold(array []string, reverse bool) {
// sortAF implements sort on arrays with callback UDF.
func sortAF(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputArray := input1.GetArray()
if inputArray == nil { // not an array
return types.MLRVAL_ERROR
return mlrval.ERROR
}
if !input2.IsFunction() {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
hofSpace := getHOFSpace(input2, 2, "sort", "array")
udfCallsite := hofSpace.udfCallsite
argsArray := hofSpace.argsArray
outputArray := types.CopyMlrvalArray(inputArray)
outputArray := mlrval.CopyMlrvalArray(inputArray)
sort.Slice(outputArray, func(i, j int) bool {
argsArray[0] = &outputArray[i]
argsArray[1] = &outputArray[j]
// Call the user's comparator function.
mret := udfCallsite.EvaluateWithArguments(state, udfCallsite.udf, argsArray)
// Unpack the types.Mlrval return value into a number.
// Unpack the mlrval.Mlrval return value into a number.
nret, ok := mret.GetNumericToFloatValue()
if !ok {
fmt.Fprintf(
@ -780,21 +780,21 @@ func sortAF(
// Go sort-callback conventions: true if a < b, false otherwise.
return nret < 0
})
return types.MlrvalFromArrayReference(outputArray)
return mlrval.FromArray(outputArray)
}
// sortAF implements sort on arrays with callback UDF.
func sortMF(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputMap := input1.GetMap()
if inputMap == nil { // not a map
return types.MLRVAL_ERROR
return mlrval.ERROR
}
if !input2.IsFunction() {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
pairsArray := inputMap.ToPairsArray()
@ -804,14 +804,14 @@ func sortMF(
argsArray := hofSpace.argsArray
sort.Slice(pairsArray, func(i, j int) bool {
argsArray[0] = types.MlrvalFromString(pairsArray[i].Key)
argsArray[0] = mlrval.FromString(pairsArray[i].Key)
argsArray[1] = pairsArray[i].Value
argsArray[2] = types.MlrvalFromString(pairsArray[j].Key)
argsArray[2] = mlrval.FromString(pairsArray[j].Key)
argsArray[3] = pairsArray[j].Value
// Call the user's comparator function.
mret := udfCallsite.EvaluateWithArguments(state, udfCallsite.udf, argsArray)
// Unpack the types.Mlrval return value into a number.
// Unpack the mlrval.Mlrval return value into a number.
nret, ok := mret.GetNumericToFloatValue()
if !ok {
fmt.Fprintf(
@ -827,35 +827,35 @@ func sortMF(
return nret < 0
})
sortedMap := types.MlrmapFromPairsArray(pairsArray)
return types.MlrvalFromMapReferenced(sortedMap)
sortedMap := mlrval.MlrmapFromPairsArray(pairsArray)
return mlrval.FromMap(sortedMap)
}
// ================================================================
// ANY HOF
func AnyHOF(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
if input1.IsArray() {
return anyArray(input1, input2, state)
} else if input1.IsMap() {
return anyMap(input1, input2, state)
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
}
func anyArray(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputArray := input1.GetArray()
if inputArray == nil { // not an array
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "any")
@ -881,17 +881,17 @@ func anyArray(
break
}
}
return types.MlrvalFromBool(boolAny)
return mlrval.FromBool(boolAny)
}
func anyMap(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputMap := input1.GetMap()
if inputMap == nil { // not a map
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "any")
@ -902,7 +902,7 @@ func anyMap(
boolAny := false
for pe := inputMap.Head; pe != nil; pe = pe.Next {
argsArray[0] = types.MlrvalFromString(pe.Key)
argsArray[0] = mlrval.FromString(pe.Key)
argsArray[1] = pe.Value
mret := udfCallsite.EvaluateWithArguments(state, udfCallsite.udf, argsArray)
bret, ok := mret.GetBoolValue()
@ -920,34 +920,34 @@ func anyMap(
}
}
return types.MlrvalFromBool(boolAny)
return mlrval.FromBool(boolAny)
}
// ================================================================
// EVERY HOF
func EveryHOF(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
if input1.IsArray() {
return everyArray(input1, input2, state)
} else if input1.IsMap() {
return everyMap(input1, input2, state)
} else {
return types.MLRVAL_ERROR
return mlrval.ERROR
}
}
func everyArray(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputArray := input1.GetArray()
if inputArray == nil { // not an array
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "every")
@ -973,17 +973,17 @@ func everyArray(
break
}
}
return types.MlrvalFromBool(boolEvery)
return mlrval.FromBool(boolEvery)
}
func everyMap(
input1 *types.Mlrval,
input2 *types.Mlrval,
input1 *mlrval.Mlrval,
input2 *mlrval.Mlrval,
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
inputMap := input1.GetMap()
if inputMap == nil { // not a map
return types.MLRVAL_ERROR
return mlrval.ERROR
}
isFunctionOrDie(input2, "every")
@ -994,7 +994,7 @@ func everyMap(
boolEvery := true
for pe := inputMap.Head; pe != nil; pe = pe.Next {
argsArray[0] = types.MlrvalFromString(pe.Key)
argsArray[0] = mlrval.FromString(pe.Key)
argsArray[1] = pe.Value
mret := udfCallsite.EvaluateWithArguments(state, udfCallsite.udf, argsArray)
bret, ok := mret.GetBoolValue()
@ -1012,5 +1012,5 @@ func everyMap(
}
}
return types.MlrvalFromBool(boolEvery)
return mlrval.FromBool(boolEvery)
}

View file

@ -9,8 +9,8 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
// ----------------------------------------------------------------
@ -120,7 +120,7 @@ func (root *RootNode) BuildIfChainNode(astNode *dsl.ASTNode) (*IfChainNode, erro
// ----------------------------------------------------------------
func (node *IfChainNode) Execute(state *runtime.State) (*BlockExitPayload, error) {
for _, ifItem := range node.ifItems {
condition := types.MLRVAL_TRUE
condition := mlrval.TRUE
if ifItem.conditionNode != nil {
condition = ifItem.conditionNode.Evaluate(state)
}

View file

@ -10,8 +10,8 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
// ----------------------------------------------------------------
@ -114,18 +114,18 @@ func (root *RootNode) BuildDirectFieldRvalueNode(fieldName string) *DirectFieldR
}
func (node *DirectFieldRvalueNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
// For normal DSL use the CST validator will prohibit this from being
// called in places the current record is undefined (begin and end blocks).
// However in the REPL people can read past end of stream and still try to
// print inrec attributes. Also, a UDF/UDS invoked from begin/end could try
// to access the inrec, and that would get past the validator.
if state.Inrec == nil {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
value := state.Inrec.Get(node.fieldName)
if value == nil {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
} else {
return value
}
@ -140,16 +140,16 @@ func (root *RootNode) BuildFullSrecRvalueNode() *FullSrecRvalueNode {
}
func (node *FullSrecRvalueNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
// For normal DSL use the CST validator will prohibit this from being
// called in places the current record is undefined (begin and end blocks).
// However in the REPL people can read past end of stream and still try to
// print inrec attributes. Also, a UDF/UDS invoked from begin/end could try
// to access the inrec, and that would get past the validator.
if state.Inrec == nil {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
} else {
return types.MlrvalFromMap(state.Inrec)
return mlrval.FromMap(state.Inrec)
}
}
@ -165,10 +165,10 @@ func (root *RootNode) BuildDirectOosvarRvalueNode(variableName string) *DirectOo
}
func (node *DirectOosvarRvalueNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
value := state.Oosvars.Get(node.variableName)
if value == nil {
return types.MLRVAL_ABSENT
return mlrval.ABSENT
} else {
return value
}
@ -183,8 +183,8 @@ func (root *RootNode) BuildFullOosvarRvalueNode() *FullOosvarRvalueNode {
}
func (node *FullOosvarRvalueNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromMap(state.Oosvars)
) *mlrval.Mlrval {
return mlrval.FromMap(state.Oosvars)
}
// ----------------------------------------------------------------
@ -208,7 +208,7 @@ func (root *RootNode) BuildLocalVariableNode(variableName string) *LocalVariable
}
func (node *LocalVariableNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
value := state.Stack.Get(node.stackVariable)
if value != nil {
return value
@ -218,14 +218,14 @@ func (node *LocalVariableNode) Evaluate(
udf := node.udfManager.LookUpDisregardingArity(functionName)
if udf != nil {
return types.MlrvalFromFunction(udf, functionName)
return mlrval.FromFunction(udf, functionName)
}
// TODO: allow built-in functions as well. Needs some API-merging as a
// prerequisite since UDFs and BIFs are managed in quite different
// structures.
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
// ----------------------------------------------------------------
@ -237,18 +237,18 @@ func (node *LocalVariableNode) Evaluate(
// regex literals differently from those for non-regex string literals.
type RegexLiteralNode struct {
literal *types.Mlrval
literal *mlrval.Mlrval
}
func (root *RootNode) BuildRegexLiteralNode(literal string) IEvaluable {
return &RegexLiteralNode{
literal: types.MlrvalFromString(literal),
literal: mlrval.FromString(literal),
}
}
func (node *RegexLiteralNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.literal
}
@ -256,7 +256,7 @@ func (node *RegexLiteralNode) Evaluate(
// StringLiteralNode is for any string literal that doesn't have any "\0" ..
// "\9" in it.
type StringLiteralNode struct {
literal *types.Mlrval
literal *mlrval.Mlrval
}
// RegexCaptureReplacementNode is for any string literal that has any "\0" ..
@ -288,7 +288,7 @@ func (root *RootNode) BuildStringLiteralNode(literal string) IEvaluable {
hasCaptures, replacementCaptureMatrix := lib.RegexReplacementHasCaptures(literal)
if !hasCaptures {
return &StringLiteralNode{
literal: types.MlrvalFromString(literal),
literal: mlrval.FromString(literal),
}
} else {
return &RegexCaptureReplacementNode{
@ -300,7 +300,7 @@ func (root *RootNode) BuildStringLiteralNode(literal string) IEvaluable {
func (node *StringLiteralNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.literal
}
@ -316,8 +316,8 @@ func (node *StringLiteralNode) Evaluate(
// set on some previous invocation of =~ or !=~.
func (node *RegexCaptureReplacementNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromString(
) *mlrval.Mlrval {
return mlrval.FromString(
lib.InterpolateCaptures(
node.replacementString,
node.replacementCaptureMatrix,
@ -328,65 +328,69 @@ func (node *RegexCaptureReplacementNode) Evaluate(
// ----------------------------------------------------------------
type IntLiteralNode struct {
literal *types.Mlrval
literal *mlrval.Mlrval
}
func (root *RootNode) BuildIntLiteralNode(literal string) *IntLiteralNode {
ival, ok := lib.TryIntFromString(literal)
lib.InternalCodingErrorIf(!ok)
return &IntLiteralNode{
literal: types.MlrvalFromPrevalidatedIntString(literal),
literal: mlrval.FromPrevalidatedIntString(literal, ival),
}
}
func (node *IntLiteralNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.literal
}
// ----------------------------------------------------------------
type FloatLiteralNode struct {
literal *types.Mlrval
literal *mlrval.Mlrval
}
func (root *RootNode) BuildFloatLiteralNode(literal string) *FloatLiteralNode {
fval, ok := lib.TryFloatFromString(literal)
lib.InternalCodingErrorIf(!ok)
return &FloatLiteralNode{
literal: types.MlrvalFromPrevalidatedFloat64String(literal),
literal: mlrval.FromPrevalidatedFloatString(literal, fval),
}
}
func (node *FloatLiteralNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.literal
}
// ----------------------------------------------------------------
type BoolLiteralNode struct {
literal *types.Mlrval
literal *mlrval.Mlrval
}
func (root *RootNode) BuildBoolLiteralNode(literal string) *BoolLiteralNode {
return &BoolLiteralNode{
literal: types.MlrvalFromBoolString(literal),
literal: mlrval.FromBoolString(literal),
}
}
func (node *BoolLiteralNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.literal
}
// ----------------------------------------------------------------
type NullLiteralNode struct {
literal *types.Mlrval
literal *mlrval.Mlrval
}
func (root *RootNode) BuildNullLiteralNode() *NullLiteralNode {
return &NullLiteralNode{
literal: types.MLRVAL_NULL,
literal: mlrval.NULL,
}
}
func (node *NullLiteralNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
return node.literal
}
@ -453,8 +457,8 @@ func (root *RootNode) BuildFILENAMENode() *FILENAMENode {
}
func (node *FILENAMENode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromString(state.Context.FILENAME)
) *mlrval.Mlrval {
return mlrval.FromString(state.Context.FILENAME)
}
// ----------------------------------------------------------------
@ -466,8 +470,8 @@ func (root *RootNode) BuildFILENUMNode() *FILENUMNode {
}
func (node *FILENUMNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromInt(state.Context.FILENUM)
) *mlrval.Mlrval {
return mlrval.FromInt(state.Context.FILENUM)
}
// ----------------------------------------------------------------
@ -479,8 +483,8 @@ func (root *RootNode) BuildNFNode() *NFNode {
}
func (node *NFNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromInt(state.Inrec.FieldCount)
) *mlrval.Mlrval {
return mlrval.FromInt(state.Inrec.FieldCount)
}
// ----------------------------------------------------------------
@ -492,8 +496,8 @@ func (root *RootNode) BuildNRNode() *NRNode {
}
func (node *NRNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromInt(state.Context.NR)
) *mlrval.Mlrval {
return mlrval.FromInt(state.Context.NR)
}
// ----------------------------------------------------------------
@ -505,8 +509,8 @@ func (root *RootNode) BuildFNRNode() *FNRNode {
}
func (node *FNRNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromInt(state.Context.FNR)
) *mlrval.Mlrval {
return mlrval.FromInt(state.Context.FNR)
}
// ----------------------------------------------------------------
@ -518,8 +522,8 @@ func (root *RootNode) BuildIRSNode() *IRSNode {
}
func (node *IRSNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromString(state.Options.ReaderOptions.IRS)
) *mlrval.Mlrval {
return mlrval.FromString(state.Options.ReaderOptions.IRS)
}
// ----------------------------------------------------------------
@ -531,8 +535,8 @@ func (root *RootNode) BuildIFSNode() *IFSNode {
}
func (node *IFSNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromString(state.Options.ReaderOptions.IFS)
) *mlrval.Mlrval {
return mlrval.FromString(state.Options.ReaderOptions.IFS)
}
// ----------------------------------------------------------------
@ -544,8 +548,8 @@ func (root *RootNode) BuildIPSNode() *IPSNode {
}
func (node *IPSNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromString(state.Options.ReaderOptions.IPS)
) *mlrval.Mlrval {
return mlrval.FromString(state.Options.ReaderOptions.IPS)
}
// ----------------------------------------------------------------
@ -557,8 +561,8 @@ func (root *RootNode) BuildORSNode() *ORSNode {
}
func (node *ORSNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromString(state.Options.WriterOptions.ORS)
) *mlrval.Mlrval {
return mlrval.FromString(state.Options.WriterOptions.ORS)
}
// ----------------------------------------------------------------
@ -570,8 +574,8 @@ func (root *RootNode) BuildOFSNode() *OFSNode {
}
func (node *OFSNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromString(state.Options.WriterOptions.OFS)
) *mlrval.Mlrval {
return mlrval.FromString(state.Options.WriterOptions.OFS)
}
// ----------------------------------------------------------------
@ -583,8 +587,8 @@ func (root *RootNode) BuildOPSNode() *OPSNode {
}
func (node *OPSNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromString(state.Options.WriterOptions.OPS)
) *mlrval.Mlrval {
return mlrval.FromString(state.Options.WriterOptions.OPS)
}
// ----------------------------------------------------------------
@ -596,8 +600,8 @@ func (root *RootNode) BuildFLATSEPNode() *FLATSEPNode {
}
func (node *FLATSEPNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromString(state.Options.WriterOptions.FLATSEP)
) *mlrval.Mlrval {
return mlrval.FromString(state.Options.WriterOptions.FLATSEP)
}
// ================================================================
@ -630,8 +634,8 @@ func (root *RootNode) BuildMathPINode() *MathPINode {
}
func (node *MathPINode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromFloat64(math.Pi)
) *mlrval.Mlrval {
return mlrval.FromFloat(math.Pi)
}
// ----------------------------------------------------------------
@ -643,8 +647,8 @@ func (root *RootNode) BuildMathENode() *MathENode {
}
func (node *MathENode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromFloat64(math.E)
) *mlrval.Mlrval {
return mlrval.FromFloat(math.E)
}
// ================================================================
@ -661,8 +665,8 @@ func (root *RootNode) BuildArraySliceEmptyLowerIndexNode(
}
func (node *LiteralOneNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromInt(1)
) *mlrval.Mlrval {
return mlrval.FromInt(1)
}
// ================================================================
@ -681,8 +685,8 @@ func (root *RootNode) BuildArraySliceEmptyUpperIndexNode(
}
func (node *LiteralEmptyStringNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
return types.MlrvalFromString("")
) *mlrval.Mlrval {
return mlrval.FromString("")
}
// ----------------------------------------------------------------
@ -698,7 +702,7 @@ func (root *RootNode) BuildPanicNode(astNode *dsl.ASTNode) (*PanicNode, error) {
}
func (node *PanicNode) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
lib.InternalCodingErrorPanic("Panic token was evaluated, not short-circuited.")
return nil // not reached
}

View file

@ -12,8 +12,8 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
// ----------------------------------------------------------------
@ -84,7 +84,7 @@ func (root *RootNode) BuildAssignableNode(
// ----------------------------------------------------------------
type DirectFieldValueLvalueNode struct {
lhsFieldName *types.Mlrval
lhsFieldName *mlrval.Mlrval
}
func (root *RootNode) BuildDirectFieldValueLvalueNode(
@ -92,26 +92,26 @@ func (root *RootNode) BuildDirectFieldValueLvalueNode(
) (IAssignable, error) {
lib.InternalCodingErrorIf(astNode.Type != dsl.NodeTypeDirectFieldValue)
lhsFieldName := types.MlrvalFromString(string(astNode.Token.Lit))
lhsFieldName := mlrval.FromString(string(astNode.Token.Lit))
return NewDirectFieldValueLvalueNode(lhsFieldName), nil
}
func NewDirectFieldValueLvalueNode(lhsFieldName *types.Mlrval) *DirectFieldValueLvalueNode {
func NewDirectFieldValueLvalueNode(lhsFieldName *mlrval.Mlrval) *DirectFieldValueLvalueNode {
return &DirectFieldValueLvalueNode{
lhsFieldName: lhsFieldName,
}
}
func (node *DirectFieldValueLvalueNode) Assign(
rvalue *types.Mlrval,
rvalue *mlrval.Mlrval,
state *runtime.State,
) error {
return node.AssignIndexed(rvalue, nil, state)
}
func (node *DirectFieldValueLvalueNode) AssignIndexed(
rvalue *types.Mlrval,
indices []*types.Mlrval,
rvalue *mlrval.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
@ -134,7 +134,7 @@ func (node *DirectFieldValueLvalueNode) AssignIndexed(
return nil
} else {
return state.Inrec.PutIndexed(
append([]*types.Mlrval{node.lhsFieldName}, indices...),
append([]*mlrval.Mlrval{node.lhsFieldName}, indices...),
rvalue,
)
}
@ -147,7 +147,7 @@ func (node *DirectFieldValueLvalueNode) Unassign(
}
func (node *DirectFieldValueLvalueNode) UnassignIndexed(
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) {
@ -166,7 +166,7 @@ func (node *DirectFieldValueLvalueNode) UnassignIndexed(
state.Inrec.Remove(name)
} else {
state.Inrec.RemoveIndexed(
append([]*types.Mlrval{node.lhsFieldName}, indices...),
append([]*mlrval.Mlrval{node.lhsFieldName}, indices...),
)
}
}
@ -199,15 +199,15 @@ func NewIndirectFieldValueLvalueNode(
}
func (node *IndirectFieldValueLvalueNode) Assign(
rvalue *types.Mlrval,
rvalue *mlrval.Mlrval,
state *runtime.State,
) error {
return node.AssignIndexed(rvalue, nil, state)
}
func (node *IndirectFieldValueLvalueNode) AssignIndexed(
rvalue *types.Mlrval,
indices []*types.Mlrval,
rvalue *mlrval.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
// AssignmentNode checks for absentness of the rvalue, so we just assign
@ -233,7 +233,7 @@ func (node *IndirectFieldValueLvalueNode) AssignIndexed(
return nil
} else {
return state.Inrec.PutIndexed(
append([]*types.Mlrval{lhsFieldName.Copy()}, indices...),
append([]*mlrval.Mlrval{lhsFieldName.Copy()}, indices...),
rvalue,
)
}
@ -246,7 +246,7 @@ func (node *IndirectFieldValueLvalueNode) Unassign(
}
func (node *IndirectFieldValueLvalueNode) UnassignIndexed(
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) {
// For normal DSL use the CST validator will prohibit this from being
@ -264,7 +264,7 @@ func (node *IndirectFieldValueLvalueNode) UnassignIndexed(
state.Inrec.Remove(name)
} else {
state.Inrec.RemoveIndexed(
append([]*types.Mlrval{lhsFieldName.Copy()}, indices...),
append([]*mlrval.Mlrval{lhsFieldName.Copy()}, indices...),
)
}
}
@ -300,7 +300,7 @@ func NewPositionalFieldNameLvalueNode(
}
func (node *PositionalFieldNameLvalueNode) Assign(
rvalue *types.Mlrval,
rvalue *mlrval.Mlrval,
state *runtime.State,
) error {
// AssignmentNode checks for absentness of the rvalue, so we just assign
@ -334,8 +334,8 @@ func (node *PositionalFieldNameLvalueNode) Assign(
}
func (node *PositionalFieldNameLvalueNode) AssignIndexed(
rvalue *types.Mlrval,
indices []*types.Mlrval,
rvalue *mlrval.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
// TODO: reconsider this if /when we decide to allow string-slice
@ -352,7 +352,7 @@ func (node *PositionalFieldNameLvalueNode) Unassign(
}
func (node *PositionalFieldNameLvalueNode) UnassignIndexed(
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) {
lhsFieldIndex := node.lhsFieldIndexExpression.Evaluate(state)
@ -376,7 +376,7 @@ func (node *PositionalFieldNameLvalueNode) UnassignIndexed(
} else {
// xxx positional
state.Inrec.RemoveIndexed(
append([]*types.Mlrval{lhsFieldIndex}, indices...),
append([]*mlrval.Mlrval{lhsFieldIndex}, indices...),
)
}
}
@ -412,15 +412,15 @@ func NewPositionalFieldValueLvalueNode(
}
func (node *PositionalFieldValueLvalueNode) Assign(
rvalue *types.Mlrval,
rvalue *mlrval.Mlrval,
state *runtime.State,
) error {
return node.AssignIndexed(rvalue, nil, state)
}
func (node *PositionalFieldValueLvalueNode) AssignIndexed(
rvalue *types.Mlrval,
indices []*types.Mlrval,
rvalue *mlrval.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
// AssignmentNode checks for absentness of the rvalue, so we just assign
@ -460,7 +460,7 @@ func (node *PositionalFieldValueLvalueNode) AssignIndexed(
} else {
// xxx positional
return state.Inrec.PutIndexed(
append([]*types.Mlrval{lhsFieldIndex}, indices...),
append([]*mlrval.Mlrval{lhsFieldIndex}, indices...),
rvalue,
)
}
@ -475,7 +475,7 @@ func (node *PositionalFieldValueLvalueNode) Unassign(
}
func (node *PositionalFieldValueLvalueNode) UnassignIndexed(
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) {
// For normal DSL use the CST validator will prohibit this from being
@ -498,7 +498,7 @@ func (node *PositionalFieldValueLvalueNode) UnassignIndexed(
} else {
// xxx positional
state.Inrec.RemoveIndexed(
append([]*types.Mlrval{lhsFieldIndex}, indices...),
append([]*mlrval.Mlrval{lhsFieldIndex}, indices...),
)
}
}
@ -519,15 +519,15 @@ func NewFullSrecLvalueNode() *FullSrecLvalueNode {
}
func (node *FullSrecLvalueNode) Assign(
rvalue *types.Mlrval,
rvalue *mlrval.Mlrval,
state *runtime.State,
) error {
return node.AssignIndexed(rvalue, nil, state)
}
func (node *FullSrecLvalueNode) AssignIndexed(
rvalue *types.Mlrval,
indices []*types.Mlrval,
rvalue *mlrval.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
// For normal DSL use the CST validator will prohibit this from being
@ -558,7 +558,7 @@ func (node *FullSrecLvalueNode) Unassign(
}
func (node *FullSrecLvalueNode) UnassignIndexed(
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) {
// For normal DSL use the CST validator will prohibit this from being
@ -579,32 +579,32 @@ func (node *FullSrecLvalueNode) UnassignIndexed(
// ----------------------------------------------------------------
type DirectOosvarValueLvalueNode struct {
lhsOosvarName *types.Mlrval
lhsOosvarName *mlrval.Mlrval
}
func (root *RootNode) BuildDirectOosvarValueLvalueNode(astNode *dsl.ASTNode) (IAssignable, error) {
lib.InternalCodingErrorIf(astNode.Type != dsl.NodeTypeDirectOosvarValue)
lhsOosvarName := types.MlrvalFromString(string(astNode.Token.Lit))
lhsOosvarName := mlrval.FromString(string(astNode.Token.Lit))
return NewDirectOosvarValueLvalueNode(lhsOosvarName), nil
}
func NewDirectOosvarValueLvalueNode(lhsOosvarName *types.Mlrval) *DirectOosvarValueLvalueNode {
func NewDirectOosvarValueLvalueNode(lhsOosvarName *mlrval.Mlrval) *DirectOosvarValueLvalueNode {
return &DirectOosvarValueLvalueNode{
lhsOosvarName: lhsOosvarName,
}
}
func (node *DirectOosvarValueLvalueNode) Assign(
rvalue *types.Mlrval,
rvalue *mlrval.Mlrval,
state *runtime.State,
) error {
return node.AssignIndexed(rvalue, nil, state)
}
func (node *DirectOosvarValueLvalueNode) AssignIndexed(
rvalue *types.Mlrval,
indices []*types.Mlrval,
rvalue *mlrval.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
// AssignmentNode checks for absent, so we just assign whatever we get
@ -617,7 +617,7 @@ func (node *DirectOosvarValueLvalueNode) AssignIndexed(
return nil
} else {
return state.Oosvars.PutIndexed(
append([]*types.Mlrval{node.lhsOosvarName}, indices...),
append([]*mlrval.Mlrval{node.lhsOosvarName}, indices...),
rvalue,
)
}
@ -630,7 +630,7 @@ func (node *DirectOosvarValueLvalueNode) Unassign(
}
func (node *DirectOosvarValueLvalueNode) UnassignIndexed(
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) {
if indices == nil {
@ -638,7 +638,7 @@ func (node *DirectOosvarValueLvalueNode) UnassignIndexed(
state.Oosvars.Remove(name)
} else {
state.Oosvars.RemoveIndexed(
append([]*types.Mlrval{node.lhsOosvarName}, indices...),
append([]*mlrval.Mlrval{node.lhsOosvarName}, indices...),
)
}
}
@ -672,15 +672,15 @@ func NewIndirectOosvarValueLvalueNode(
}
func (node *IndirectOosvarValueLvalueNode) Assign(
rvalue *types.Mlrval,
rvalue *mlrval.Mlrval,
state *runtime.State,
) error {
return node.AssignIndexed(rvalue, nil, state)
}
func (node *IndirectOosvarValueLvalueNode) AssignIndexed(
rvalue *types.Mlrval,
indices []*types.Mlrval,
rvalue *mlrval.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
// AssignmentNode checks for absentness of the rvalue, so we just assign
@ -697,7 +697,7 @@ func (node *IndirectOosvarValueLvalueNode) AssignIndexed(
return nil
} else {
return state.Oosvars.PutIndexed(
append([]*types.Mlrval{lhsOosvarName.Copy()}, indices...),
append([]*mlrval.Mlrval{lhsOosvarName.Copy()}, indices...),
rvalue,
)
}
@ -710,7 +710,7 @@ func (node *IndirectOosvarValueLvalueNode) Unassign(
}
func (node *IndirectOosvarValueLvalueNode) UnassignIndexed(
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) {
lhsOosvarName := node.lhsOosvarNameExpression.Evaluate(state)
@ -720,7 +720,7 @@ func (node *IndirectOosvarValueLvalueNode) UnassignIndexed(
state.Oosvars.Remove(sname)
} else {
state.Oosvars.RemoveIndexed(
append([]*types.Mlrval{lhsOosvarName}, indices...),
append([]*mlrval.Mlrval{lhsOosvarName}, indices...),
)
}
}
@ -741,15 +741,15 @@ func NewFullOosvarLvalueNode() *FullOosvarLvalueNode {
}
func (node *FullOosvarLvalueNode) Assign(
rvalue *types.Mlrval,
rvalue *mlrval.Mlrval,
state *runtime.State,
) error {
return node.AssignIndexed(rvalue, nil, state)
}
func (node *FullOosvarLvalueNode) AssignIndexed(
rvalue *types.Mlrval,
indices []*types.Mlrval,
rvalue *mlrval.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
// AssignmentNode checks for absentness of the rvalue, so we just assign
@ -771,7 +771,7 @@ func (node *FullOosvarLvalueNode) Unassign(
}
func (node *FullOosvarLvalueNode) UnassignIndexed(
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) {
if indices == nil {
@ -827,15 +827,15 @@ func NewLocalVariableLvalueNode(
}
func (node *LocalVariableLvalueNode) Assign(
rvalue *types.Mlrval,
rvalue *mlrval.Mlrval,
state *runtime.State,
) error {
return node.AssignIndexed(rvalue, nil, state)
}
func (node *LocalVariableLvalueNode) AssignIndexed(
rvalue *types.Mlrval,
indices []*types.Mlrval,
rvalue *mlrval.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
// AssignmentNode checks for absent, so we just assign whatever we get
@ -863,7 +863,7 @@ func (node *LocalVariableLvalueNode) Unassign(
}
func (node *LocalVariableLvalueNode) UnassignIndexed(
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) {
if indices == nil {
@ -1006,10 +1006,10 @@ func NewIndexedLvalueNode(
// '$x[1][2] = 3' or '@x[1][2] = 3', the indices are [1,2], and the baseLvalue
// is '$x' or '@x' respectively.
func (node *IndexedLvalueNode) Assign(
rvalue *types.Mlrval,
rvalue *mlrval.Mlrval,
state *runtime.State,
) error {
indices := make([]*types.Mlrval, len(node.indexEvaluables))
indices := make([]*mlrval.Mlrval, len(node.indexEvaluables))
for i := range node.indexEvaluables {
indices[i] = node.indexEvaluables[i].Evaluate(state)
@ -1021,15 +1021,15 @@ func (node *IndexedLvalueNode) Assign(
// This lets the user do '$y[ ["a", "b", "c"] ] = $x' in lieu of
// '$y["a"]["b"]["c"] = $x'.
if len(indices) == 1 && indices[0].IsArray() {
indices = types.MakePointerArray(indices[0].GetArray())
indices = mlrval.MakePointerArray(indices[0].GetArray())
}
return node.baseLvalue.AssignIndexed(rvalue, indices, state)
}
func (node *IndexedLvalueNode) AssignIndexed(
rvalue *types.Mlrval,
indices []*types.Mlrval,
rvalue *mlrval.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
// We are the delegator, not the delegatee
@ -1040,7 +1040,7 @@ func (node *IndexedLvalueNode) AssignIndexed(
func (node *IndexedLvalueNode) Unassign(
state *runtime.State,
) {
indices := make([]*types.Mlrval, len(node.indexEvaluables))
indices := make([]*mlrval.Mlrval, len(node.indexEvaluables))
for i := range node.indexEvaluables {
indices[i] = node.indexEvaluables[i].Evaluate(state)
}
@ -1049,7 +1049,7 @@ func (node *IndexedLvalueNode) Unassign(
}
func (node *IndexedLvalueNode) UnassignIndexed(
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) {
// We are the delegator, not the delegatee
@ -1082,7 +1082,7 @@ func NewEnvironmentVariableLvalueNode(
}
func (node *EnvironmentVariableLvalueNode) Assign(
rvalue *types.Mlrval,
rvalue *mlrval.Mlrval,
state *runtime.State,
) error {
// AssignmentNode checks for absentness of the rvalue, so we just assign
@ -1114,8 +1114,8 @@ func (node *EnvironmentVariableLvalueNode) Assign(
}
func (node *EnvironmentVariableLvalueNode) AssignIndexed(
rvalue *types.Mlrval,
indices []*types.Mlrval,
rvalue *mlrval.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) error {
return errors.New("mlr: ENV[...] cannot be indexed.")
@ -1138,7 +1138,7 @@ func (node *EnvironmentVariableLvalueNode) Unassign(
}
func (node *EnvironmentVariableLvalueNode) UnassignIndexed(
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
state *runtime.State,
) {
// TODO: needs error return

View file

@ -14,11 +14,11 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/output"
"github.com/johnkerl/miller/internal/pkg/parsing/lexer"
"github.com/johnkerl/miller/internal/pkg/parsing/parser"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
// NewEmptyRoot sets up an empty CST, before ingesting any DSL strings. For
@ -464,7 +464,7 @@ func (root *RootNode) ExecuteBeginBlocks(state *runtime.State) error {
return nil
}
func (root *RootNode) ExecuteMainBlock(state *runtime.State) (outrec *types.Mlrmap, err error) {
func (root *RootNode) ExecuteMainBlock(state *runtime.State) (outrec *mlrval.Mlrmap, err error) {
_, err = root.mainBlock.Execute(state)
return state.Inrec, err
}
@ -488,7 +488,7 @@ func (root *RootNode) ExecuteEndBlocks(state *runtime.State) error {
// executed once, and then discarded.
// This is the 'execute once' part of that.
func (root *RootNode) ExecuteREPLImmediate(state *runtime.State) (outrec *types.Mlrmap, err error) {
func (root *RootNode) ExecuteREPLImmediate(state *runtime.State) (outrec *mlrval.Mlrmap, err error) {
_, err = root.replImmediateBlock.ExecuteFrameless(state)
return state.Inrec, err
}

View file

@ -10,6 +10,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/output"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
@ -58,7 +59,7 @@ import (
// ================================================================
type tTeeToRedirectFunc func(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
state *runtime.State,
) error
@ -156,7 +157,7 @@ func (node *TeeStatementNode) Execute(state *runtime.State) (*BlockExitPayload,
// ----------------------------------------------------------------
func (node *TeeStatementNode) teeToFileOrPipe(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
state *runtime.State,
) error {
redirectorTarget := node.redirectorTargetEvaluable.Evaluate(state)

View file

@ -9,8 +9,8 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
// ----------------------------------------------------------------
@ -67,16 +67,16 @@ type Executor func(state *runtime.State) (*BlockExitPayload, error)
// ================================================================
// This is for any left-hand side (LHS or Lvalue) of an assignment statement.
type IAssignable interface {
Assign(rvalue *types.Mlrval, state *runtime.State) error
Assign(rvalue *mlrval.Mlrval, state *runtime.State) error
// 'foo = "bar"' or 'foo[3]["abc"] = "bar"'
// For non-indexed assignment, which is the normal case, indices can be
// zero-length or nil.
AssignIndexed(rvalue *types.Mlrval, indices []*types.Mlrval, state *runtime.State) error
AssignIndexed(rvalue *mlrval.Mlrval, indices []*mlrval.Mlrval, state *runtime.State) error
Unassign(state *runtime.State)
UnassignIndexed(indices []*types.Mlrval, state *runtime.State)
UnassignIndexed(indices []*mlrval.Mlrval, state *runtime.State)
}
// ================================================================
@ -84,7 +84,7 @@ type IAssignable interface {
// Also, for computed field names on the left-hand side, like '$a . $b' in mlr
// put '$[$a . $b]' = $x + $y'.
type IEvaluable interface {
Evaluate(state *runtime.State) *types.Mlrval
Evaluate(state *runtime.State) *mlrval.Mlrval
}
// ================================================================
@ -119,5 +119,5 @@ type BlockExitPayload struct {
blockExitStatus BlockExitStatus
// No multiple return yet in the Miller DSL -- if there were, this would be
// an array.
blockReturnValue *types.Mlrval // TODO: TypeGatedMlrval
blockReturnValue *mlrval.Mlrval // TODO: TypeGatedMlrval
}

View file

@ -11,6 +11,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -83,7 +84,7 @@ func NewUDFCallsite(
// NewUDFCallsiteForHigherOrderFunction is for UDF callsites such as
// sortaf/sortmf. Here, the array/map to be sorted has already been evaluated
// and is an array of *types.Mlrval. The UDF needs to be invoked on pairs of
// and is an array of *mlrval.Mlrval. The UDF needs to be invoked on pairs of
// array elements.
func NewUDFCallsiteForHigherOrderFunction(
udf *UDF,
@ -123,7 +124,7 @@ func (site *UDFCallsite) findUDF(state *runtime.State) *UDF {
// See comments above NewUDFCallsite.
func (site *UDFCallsite) Evaluate(
state *runtime.State,
) *types.Mlrval {
) *mlrval.Mlrval {
udf := site.findUDF(state)
if udf == nil {
@ -188,7 +189,7 @@ func (site *UDFCallsite) Evaluate(
os.Exit(1)
}
arguments := make([]*types.Mlrval, numArguments)
arguments := make([]*mlrval.Mlrval, numArguments)
for i := range udf.signature.typeGatedParameterNames {
arguments[i] = site.argumentNodes[i].Evaluate(state)
@ -210,8 +211,8 @@ func (site *UDFCallsite) Evaluate(
func (site *UDFCallsite) EvaluateWithArguments(
state *runtime.State,
udf *UDF,
arguments []*types.Mlrval,
) *types.Mlrval {
arguments []*mlrval.Mlrval,
) *mlrval.Mlrval {
// Bind the arguments to the parameters. Function literals can access
// locals in their enclosing scope; named functions cannot. Hence stack
@ -250,34 +251,34 @@ func (site *UDFCallsite) EvaluateWithArguments(
// being MT_ERROR should be mapped to MT_ERROR here (nominally,
// data-dependent). But error-return could be something not data-dependent.
if err != nil {
err = udf.signature.typeGatedReturnValue.Check(types.MLRVAL_ERROR)
err = udf.signature.typeGatedReturnValue.Check(mlrval.ERROR)
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
return types.MLRVAL_ERROR
return mlrval.ERROR
}
// Fell off end of function with no return
if blockExitPayload == nil {
err = udf.signature.typeGatedReturnValue.Check(types.MLRVAL_ABSENT)
err = udf.signature.typeGatedReturnValue.Check(mlrval.ABSENT)
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
// TODO: should be an internal coding error. This would be break or
// continue not in a loop, or return-void, both of which should have been
// reported as syntax errors during the parsing pass.
if blockExitPayload.blockExitStatus != BLOCK_EXIT_RETURN_VALUE {
err = udf.signature.typeGatedReturnValue.Check(types.MLRVAL_ABSENT)
err = udf.signature.typeGatedReturnValue.Check(mlrval.ABSENT)
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
return types.MLRVAL_ABSENT
return mlrval.ABSENT
}
// Definitely a Miller internal coding error if the user put 'return x' in
@ -434,7 +435,7 @@ func genFunctionLiteralName() string {
// UnnamedUDFNode holds function literals like 'func (a, b) { return b - a }'.
type UnnamedUDFNode struct {
udfAsMlrval *types.Mlrval
udfAsMlrval *mlrval.Mlrval
}
func (root *RootNode) BuildUnnamedUDFNode(astNode *dsl.ASTNode) (IEvaluable, error) {
@ -447,14 +448,14 @@ func (root *RootNode) BuildUnnamedUDFNode(astNode *dsl.ASTNode) (IEvaluable, err
return nil, err
}
udfAsMlrval := types.MlrvalFromFunction(udf, name)
udfAsMlrval := mlrval.FromFunction(udf, name)
return &UnnamedUDFNode{
udfAsMlrval: udfAsMlrval,
}, nil
}
func (node *UnnamedUDFNode) Evaluate(state *runtime.State) *types.Mlrval {
func (node *UnnamedUDFNode) Evaluate(state *runtime.State) *mlrval.Mlrval {
return node.udfAsMlrval
}

View file

@ -10,6 +10,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/dsl"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/runtime"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -106,7 +107,7 @@ func (site *UDSCallsite) Execute(state *runtime.State) (*BlockExitPayload, error
// we push a new frameset and DefineTypedAtScope using the callee's frameset.
// Evaluate the arguments
arguments := make([]*types.Mlrval, len(site.uds.signature.typeGatedParameterNames))
arguments := make([]*mlrval.Mlrval, len(site.uds.signature.typeGatedParameterNames))
for i, typeGatedParameterName := range site.uds.signature.typeGatedParameterNames {
arguments[i] = site.argumentNodes[i].Evaluate(state)

View file

@ -5,7 +5,9 @@ import (
"errors"
"fmt"
"github.com/johnkerl/miller/internal/pkg/bifs"
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -62,9 +64,9 @@ func (reader *PseudoReaderGen) process(
return
}
var doneComparator types.BinaryFunc = types.BIF_greater_than
var doneComparator mlrval.CmpFuncBool = mlrval.GreaterThan
if step.GetNumericNegativeorDie() {
doneComparator = types.BIF_less_than
doneComparator = mlrval.LessThan
}
key := reader.readerOptions.GeneratorOptions.FieldName
@ -75,13 +77,11 @@ func (reader *PseudoReaderGen) process(
eof := false
for !eof {
mdone := doneComparator(value, stop)
done, _ := mdone.GetBoolValue()
if done {
if doneComparator(value, stop) {
break
}
record := types.NewMlrmap()
record := mlrval.NewMlrmap()
record.PutCopy(key, value)
context.UpdateForInputRecord()
@ -109,7 +109,7 @@ func (reader *PseudoReaderGen) process(
}
value = types.BIF_plus_binary(value, step)
value = bifs.BIF_plus_binary(value, step)
}
if recordsAndContexts.Len() > 0 {
@ -121,8 +121,8 @@ func (reader *PseudoReaderGen) process(
func (reader *PseudoReaderGen) tryParse(
name string,
svalue string,
) (*types.Mlrval, error) {
mvalue := types.MlrvalFromInferredType(svalue)
) (*mlrval.Mlrval, error) {
mvalue := mlrval.FromDeferredType(svalue)
if mvalue == nil || !mvalue.IsNumeric() {
return nil, errors.New(
fmt.Sprintf("mlr: gen: %s \"%s\" is not parseable as number", name, svalue),

View file

@ -14,7 +14,7 @@ const CSV_BOM = "\xef\xbb\xbf"
// FILENAME, NF, NF, FNR, etc.) needs to be duplicated and passed through the
// channels along with each record. Hence the initial context, which readers
// update on each new file/record, and the channel of types.RecordAndContext
// rather than channel of types.Mlrmap.
// rather than channel of mlrval.Mlrmap.
type IRecordReader interface {
Read(

View file

@ -12,6 +12,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -27,7 +28,6 @@ type RecordReaderCSV struct {
header []string
}
// ----------------------------------------------------------------
func NewRecordReaderCSV(
readerOptions *cli.TReaderOptions,
recordsPerBatch int,
@ -45,7 +45,6 @@ func NewRecordReaderCSV(
}, nil
}
// ----------------------------------------------------------------
func (reader *RecordReaderCSV) Read(
filenames []string,
context types.Context,
@ -218,7 +217,7 @@ func (reader *RecordReaderCSV) getRecordBatch(
}
}
record := types.NewMlrmapAsRecord()
record := mlrval.NewMlrmapAsRecord()
nh := len(reader.header)
nd := len(csvRecord)
@ -226,7 +225,7 @@ func (reader *RecordReaderCSV) getRecordBatch(
if nh == nd {
for i := 0; i < nh; i++ {
key := reader.header[i]
value := types.MlrvalFromInferredTypeForDataFiles(csvRecord[i])
value := mlrval.FromDeferredType(csvRecord[i])
record.PutReference(key, value)
}
@ -246,19 +245,19 @@ func (reader *RecordReaderCSV) getRecordBatch(
n := lib.IntMin2(nh, nd)
for i = 0; i < n; i++ {
key := reader.header[i]
value := types.MlrvalFromInferredTypeForDataFiles(csvRecord[i])
value := mlrval.FromDeferredType(csvRecord[i])
record.PutReference(key, value)
}
if nh < nd {
// if header shorter than data: use 1-up itoa keys
key := strconv.Itoa(i + 1)
value := types.MlrvalFromInferredTypeForDataFiles(csvRecord[i])
value := mlrval.FromDeferredType(csvRecord[i])
record.PutCopy(key, value)
}
if nh > nd {
// if header longer than data: use "" values
for i = nd; i < nh; i++ {
record.PutCopy(reader.header[i], types.MLRVAL_VOID)
record.PutCopy(reader.header[i], mlrval.VOID)
}
}
}

View file

@ -28,6 +28,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -242,10 +243,10 @@ func getRecordBatchExplicitCSVHeader(
return
}
record := types.NewMlrmapAsRecord()
record := mlrval.NewMlrmapAsRecord()
if !reader.readerOptions.AllowRaggedCSVInput {
for i, field := range fields {
value := types.MlrvalFromInferredTypeForDataFiles(field)
value := mlrval.FromDeferredType(field)
record.PutCopy(reader.headerStrings[i], value)
}
} else {
@ -254,21 +255,21 @@ func getRecordBatchExplicitCSVHeader(
n := lib.IntMin2(nh, nd)
var i int
for i = 0; i < n; i++ {
value := types.MlrvalFromInferredTypeForDataFiles(fields[i])
value := mlrval.FromDeferredType(fields[i])
record.PutCopy(reader.headerStrings[i], value)
}
if nh < nd {
// if header shorter than data: use 1-up itoa keys
for i = nh; i < nd; i++ {
key := strconv.Itoa(i + 1)
value := types.MlrvalFromInferredTypeForDataFiles(fields[i])
value := mlrval.FromDeferredType(fields[i])
record.PutCopy(key, value)
}
}
if nh > nd {
// if header longer than data: use "" values
for i = nd; i < nh; i++ {
record.PutCopy(reader.headerStrings[i], types.MLRVAL_VOID)
record.PutCopy(reader.headerStrings[i], mlrval.VOID)
}
}
}
@ -359,10 +360,10 @@ func getRecordBatchImplicitCSVHeader(
}
}
record := types.NewMlrmapAsRecord()
record := mlrval.NewMlrmapAsRecord()
if !reader.readerOptions.AllowRaggedCSVInput {
for i, field := range fields {
value := types.MlrvalFromInferredTypeForDataFiles(field)
value := mlrval.FromDeferredType(field)
record.PutCopy(reader.headerStrings[i], value)
}
} else {
@ -371,19 +372,19 @@ func getRecordBatchImplicitCSVHeader(
n := lib.IntMin2(nh, nd)
var i int
for i = 0; i < n; i++ {
value := types.MlrvalFromInferredTypeForDataFiles(fields[i])
value := mlrval.FromDeferredType(fields[i])
record.PutCopy(reader.headerStrings[i], value)
}
if nh < nd {
// if header shorter than data: use 1-up itoa keys
key := strconv.Itoa(i + 1)
value := types.MlrvalFromInferredTypeForDataFiles(fields[i])
value := mlrval.FromDeferredType(fields[i])
record.PutCopy(key, value)
}
if nh > nd {
// if header longer than data: use "" values
for i = nd; i < nh; i++ {
record.PutCopy(reader.headerStrings[i], types.MLRVAL_VOID)
record.PutCopy(reader.headerStrings[i], mlrval.VOID)
}
}
}

View file

@ -10,12 +10,13 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
// splitter_DKVP_NIDX is a function type for the one bit of code differing
// between the DKVP reader and the NIDX reader, namely, how it splits lines.
type splitter_DKVP_NIDX func(reader *RecordReaderDKVPNIDX, line string) *types.Mlrmap
type splitter_DKVP_NIDX func(reader *RecordReaderDKVPNIDX, line string) *mlrval.Mlrmap
type RecordReaderDKVPNIDX struct {
readerOptions *cli.TReaderOptions
@ -150,8 +151,8 @@ func (reader *RecordReaderDKVPNIDX) getRecordBatch(
return recordsAndContexts, false
}
func recordFromDKVPLine(reader *RecordReaderDKVPNIDX, line string) *types.Mlrmap {
record := types.NewMlrmapAsRecord()
func recordFromDKVPLine(reader *RecordReaderDKVPNIDX, line string) *mlrval.Mlrmap {
record := mlrval.NewMlrmapAsRecord()
var pairs []string
// TODO: func-pointer this away
@ -179,19 +180,19 @@ func recordFromDKVPLine(reader *RecordReaderDKVPNIDX, line string) *types.Mlrmap
// "a=". Here we use the positional index as the key. This way
// DKVP is a generalization of NIDX.
key := strconv.Itoa(i + 1) // Miller userspace indices are 1-up
value := types.MlrvalFromInferredTypeForDataFiles(kv[0])
value := mlrval.FromDeferredType(kv[0])
record.PutReference(key, value)
} else {
key := kv[0]
value := types.MlrvalFromInferredTypeForDataFiles(kv[1])
value := mlrval.FromDeferredType(kv[1])
record.PutReference(key, value)
}
}
return record
}
func recordFromNIDXLine(reader *RecordReaderDKVPNIDX, line string) *types.Mlrmap {
record := types.NewMlrmapAsRecord()
func recordFromNIDXLine(reader *RecordReaderDKVPNIDX, line string) *mlrval.Mlrmap {
record := mlrval.NewMlrmapAsRecord()
var values []string
// TODO: func-pointer this away
@ -208,7 +209,7 @@ func recordFromNIDXLine(reader *RecordReaderDKVPNIDX, line string) *types.Mlrmap
for _, value := range values {
i++
key := strconv.Itoa(i)
mval := types.MlrvalFromInferredTypeForDataFiles(value)
mval := mlrval.FromDeferredType(value)
record.PutReference(key, mval)
}
return record

View file

@ -0,0 +1,59 @@
package input
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/johnkerl/miller/internal/pkg/cli"
)
func TestRecordFromDKVPLine(t *testing.T) {
readerOptions := cli.DefaultReaderOptions()
cli.FinalizeReaderOptions(&readerOptions) // compute IPS, IFS -> IPSRegex, IFSRegex
reader, err := NewRecordReaderDKVP(&readerOptions, 1)
assert.NotNil(t, reader)
assert.Nil(t, err)
line := ""
record := recordFromDKVPLine(reader, line)
assert.NotNil(t, record)
assert.Equal(t, 0, record.FieldCount)
line = "a=1,b=2,c=3"
record = recordFromDKVPLine(reader, line)
assert.NotNil(t, record)
assert.Equal(t, 3, record.FieldCount)
assert.NotNil(t, record.Head)
assert.NotNil(t, record.Head.Next)
assert.NotNil(t, record.Head.Next.Next)
assert.Nil(t, record.Head.Next.Next.Next)
assert.Equal(t, record.Head.Key, "a")
assert.Equal(t, record.Head.Next.Key, "b")
assert.Equal(t, record.Head.Next.Next.Key, "c")
line = "a=1,b=2,b=3"
record = recordFromDKVPLine(reader, line)
assert.NotNil(t, record)
assert.Equal(t, 2, record.FieldCount)
assert.NotNil(t, record.Head)
assert.NotNil(t, record.Head.Next)
assert.Nil(t, record.Head.Next.Next)
assert.Equal(t, record.Head.Key, "a")
assert.Equal(t, record.Head.Next.Key, "b")
line = "a,b,c"
record = recordFromDKVPLine(reader, line)
assert.NotNil(t, record)
assert.Equal(t, 3, record.FieldCount)
assert.NotNil(t, record.Head)
assert.NotNil(t, record.Head.Next)
assert.NotNil(t, record.Head.Next.Next)
assert.Nil(t, record.Head.Next.Next.Next)
assert.Equal(t, record.Head.Key, "1")
assert.Equal(t, record.Head.Next.Key, "2")
assert.Equal(t, record.Head.Next.Next.Key, "3")
}

View file

@ -12,6 +12,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -107,7 +108,7 @@ func (reader *RecordReaderJSON) processHandle(
}
}
mlrval, eof, err := types.MlrvalDecodeFromJSON(decoder)
mlrval, eof, err := mlrval.MlrvalDecodeFromJSON(decoder)
if eof {
break
}

View file

@ -9,6 +9,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -254,8 +255,8 @@ func (reader *RecordReaderXTAB) getRecordBatch(
func (reader *RecordReaderXTAB) recordFromXTABLines(
stanza *list.List,
) (*types.Mlrmap, error) {
record := types.NewMlrmapAsRecord()
) (*mlrval.Mlrmap, error) {
record := mlrval.NewMlrmapAsRecord()
for e := stanza.Front(); e != nil; e = e.Next() {
line := e.Value.(string)
@ -272,10 +273,10 @@ func (reader *RecordReaderXTAB) recordFromXTABLines(
key := kv[0]
if len(kv) == 1 {
value := types.MLRVAL_VOID
value := mlrval.VOID
record.PutReference(key, value)
} else {
value := types.MlrvalFromInferredTypeForDataFiles(kv[1])
value := mlrval.FromDeferredType(kv[1])
record.PutReference(key, value)
}
}

View file

@ -114,7 +114,7 @@ func TryIntFromString(input string) (int, bool) {
return 0, false
}
func TryFloat64FromString(input string) (float64, bool) {
func TryFloatFromString(input string) (float64, bool) {
fval, err := strconv.ParseFloat(input, 64)
if err == nil {
return fval, true

View file

@ -51,7 +51,7 @@
// trivial.
// ================================================================
package types
package mlrval
// For the C port having this off was a noticeable performance improvement (10-15%).
// For the Go port having it off is a less-noticeable performance improvement (5%).

View file

@ -1,4 +1,4 @@
package types
package mlrval
import (
"bytes"
@ -12,12 +12,47 @@ func (mlrmap *Mlrmap) IsEmpty() bool {
return mlrmap.Head == nil
}
// ----------------------------------------------------------------
func (mlrmap *Mlrmap) Has(key string) bool {
return mlrmap.findEntry(key) != nil
}
// PutCpoy copies the key and value (deep-copying in case the value is array/map).
func (mlrmap *Mlrmap) Get(key string) *Mlrval {
pe := mlrmap.findEntry(key)
if pe == nil {
return nil
} else {
return pe.Value
}
return nil
}
// PutReference copies the key but not the value. This is not safe for DSL use,
// where we could create undesired references between different objects. Only
// intended to be used at callsites which allocate a mlrval solely for the
// purpose of putting into a map, e.g. input-record readers.
func (mlrmap *Mlrmap) PutReference(key string, value *Mlrval) {
pe := mlrmap.findEntry(key)
if pe == nil {
pe = newMlrmapEntry(key, value)
if mlrmap.Head == nil {
mlrmap.Head = pe
mlrmap.Tail = pe
} else {
pe.Prev = mlrmap.Tail
pe.Next = nil
mlrmap.Tail.Next = pe
mlrmap.Tail = pe
}
if mlrmap.keysToEntries != nil {
mlrmap.keysToEntries[key] = pe
}
mlrmap.FieldCount++
} else {
pe.Value = value
}
}
// PutCopy copies the key and value (deep-copying in case the value is array/map).
// This is safe for DSL use. See also PutReference.
func (mlrmap *Mlrmap) PutCopy(key string, value *Mlrval) {
pe := mlrmap.findEntry(key)
@ -41,22 +76,19 @@ func (mlrmap *Mlrmap) PutCopy(key string, value *Mlrval) {
}
}
// PutReference copies the key but not the value. This is not safe for DSL use,
// where we could create undesired references between different objects. Only
// intended to be used at callsites which allocate a mlrval solely for the
// purpose of putting into a map, e.g. input-record readers.
func (mlrmap *Mlrmap) PutReference(key string, value *Mlrval) {
// PrependReference is the same as PutReference, but puts a new entry first, not last.
func (mlrmap *Mlrmap) PrependReference(key string, value *Mlrval) {
pe := mlrmap.findEntry(key)
if pe == nil {
pe = newMlrmapEntry(key, value)
if mlrmap.Head == nil {
if mlrmap.Tail == nil {
mlrmap.Head = pe
mlrmap.Tail = pe
} else {
pe.Prev = mlrmap.Tail
pe.Next = nil
mlrmap.Tail.Next = pe
mlrmap.Tail = pe
pe.Prev = nil
pe.Next = mlrmap.Head
mlrmap.Head.Prev = pe
mlrmap.Head = pe
}
if mlrmap.keysToEntries != nil {
mlrmap.keysToEntries[key] = pe
@ -123,11 +155,61 @@ func (mlrmap *Mlrmap) PutReferenceAfter(
}
}
func (mlrmap *Mlrmap) PutCopyWithMlrvalIndex(key *Mlrval, value *Mlrval) error {
if key.mvtype == MT_STRING {
mlrmap.PutCopy(key.printrep, value)
// findEntry is the basic hash-map accessor for Has, Put, Get, Remove, etc.
// Hashmaps in Go are a built-in type; Mlrmap is (a)
// insertion-order-preserving, and (b) supports either hashed or non-hashed
// access.
func (mlrmap *Mlrmap) findEntry(key string) *MlrmapEntry {
if mlrmap.keysToEntries != nil {
return mlrmap.keysToEntries[key]
} else {
for pe := mlrmap.Head; pe != nil; pe = pe.Next {
if pe.Key == key {
return pe
}
}
return nil
} else if key.mvtype == MT_INT {
}
}
// findEntryByPositionalIndex is for '$[1]' etc. in the DSL.
//
// Notes:
// * This is a linear search.
// * Indices are 1-up not 0-up
// * Indices -n..-1 are aliases for 1..n. In particular, it will be faster to
// get the -1st field than the nth.
// * Returns 0 on invalid index: 0, or < -n, or > n where n is the number of
// fields.
func (mlrmap *Mlrmap) findEntryByPositionalIndex(position int) *MlrmapEntry {
if position > mlrmap.FieldCount || position < -mlrmap.FieldCount || position == 0 {
return nil
}
if position > 0 {
var i int = 1
for pe := mlrmap.Head; pe != nil; pe = pe.Next {
if i == position {
return pe
}
i++
}
lib.InternalCodingErrorIf(true)
} else {
var i int = -1
for pe := mlrmap.Tail; pe != nil; pe = pe.Prev {
if i == position {
return pe
}
i--
}
lib.InternalCodingErrorIf(true)
}
lib.InternalCodingErrorIf(true)
return nil
}
func (mlrmap *Mlrmap) PutCopyWithMlrvalIndex(key *Mlrval, value *Mlrval) error {
if key.IsStringOrInt() {
mlrmap.PutCopy(key.String(), value)
return nil
} else {
@ -142,29 +224,6 @@ func (mlrmap *Mlrmap) PrependCopy(key string, value *Mlrval) {
mlrmap.PrependReference(key, value.Copy())
}
// ----------------------------------------------------------------
func (mlrmap *Mlrmap) PrependReference(key string, value *Mlrval) {
pe := mlrmap.findEntry(key)
if pe == nil {
pe = newMlrmapEntry(key, value)
if mlrmap.Tail == nil {
mlrmap.Head = pe
mlrmap.Tail = pe
} else {
pe.Prev = nil
pe.Next = mlrmap.Head
mlrmap.Head.Prev = pe
mlrmap.Head = pe
}
if mlrmap.keysToEntries != nil {
mlrmap.keysToEntries[key] = pe
}
mlrmap.FieldCount++
} else {
pe.Value = value
}
}
// ----------------------------------------------------------------
// Merges that into mlrmap.
func (mlrmap *Mlrmap) Merge(other *Mlrmap) {
@ -173,24 +232,12 @@ func (mlrmap *Mlrmap) Merge(other *Mlrmap) {
}
}
// ----------------------------------------------------------------
func (mlrmap *Mlrmap) Get(key string) *Mlrval {
pe := mlrmap.findEntry(key)
if pe == nil {
return nil
} else {
return pe.Value
}
return nil
}
// ----------------------------------------------------------------
// Exposed for the 'nest' verb
func (mlrmap *Mlrmap) GetEntry(key string) *MlrmapEntry {
return mlrmap.findEntry(key)
}
// ----------------------------------------------------------------
func (mlrmap *Mlrmap) GetKeys() []string {
keys := make([]string, mlrmap.FieldCount)
i := 0
@ -202,15 +249,40 @@ func (mlrmap *Mlrmap) GetKeys() []string {
}
// ----------------------------------------------------------------
// For '$[[[1]]]' etc. in the DSL.
//
// Notes:
// * This is a linear search.
// * Indices are 1-up not 0-up
// * Indices -n..-1 are aliases for 1..n. In particular, it will be faster to
// get the -1st field than the nth.
// * Returns 0 on invalid index: 0, or < -n, or > n where n is the number of
// fields.
// TODO: put error-return into this API
func (mlrmap *Mlrmap) PutNameWithPositionalIndex(position int, name *Mlrval) {
positionalEntry := mlrmap.findEntryByPositionalIndex(position)
if positionalEntry == nil {
// TODO: handle out-of-bounds accesses
return
}
s := ""
if name.IsString() || name.IsInt() {
s = name.String()
} else {
// TODO: return MlrvalFromError()
return
}
// E.g. there are fields named 'a' and 'b', as positions 1 and 2,
// and the user does '$[[1]] = $[[2]]'. Then there would be two b's.
mapEntry := mlrmap.findEntry(s)
if mapEntry != nil && mapEntry != positionalEntry {
if mlrmap.keysToEntries != nil {
delete(mlrmap.keysToEntries, positionalEntry.Key)
}
mlrmap.Unlink(mapEntry)
}
lib.InternalCodingErrorIf(s == "")
positionalEntry.Key = s
if mlrmap.keysToEntries != nil {
mlrmap.keysToEntries[s] = positionalEntry
}
}
func (mlrmap *Mlrmap) GetWithPositionalIndex(position int) *Mlrval {
mapEntry := mlrmap.findEntryByPositionalIndex(position)
@ -221,7 +293,7 @@ func (mlrmap *Mlrmap) GetWithPositionalIndex(position int) *Mlrval {
}
func (mlrmap *Mlrmap) GetWithMlrvalIndex(index *Mlrval) (*Mlrval, error) {
if index.mvtype == MT_ARRAY {
if index.IsArray() {
return mlrmap.getWithMlrvalArrayIndex(index)
} else {
return mlrmap.getWithMlrvalSingleIndex(index)
@ -233,7 +305,7 @@ func (mlrmap *Mlrmap) GetWithMlrvalIndex(index *Mlrval) (*Mlrval, error) {
func (mlrmap *Mlrmap) getWithMlrvalArrayIndex(index *Mlrval) (*Mlrval, error) {
current := mlrmap
var retval *Mlrval = nil
lib.InternalCodingErrorIf(index.mvtype != MT_ARRAY)
lib.InternalCodingErrorIf(!index.IsArray())
array := index.arrayval
n := len(array)
for i, piece := range array {
@ -257,9 +329,9 @@ func (mlrmap *Mlrmap) getWithMlrvalArrayIndex(index *Mlrval) (*Mlrval, error) {
}
func (mlrmap *Mlrmap) getWithMlrvalSingleIndex(index *Mlrval) (*Mlrval, error) {
if index.mvtype == MT_STRING {
if index.IsString() {
return mlrmap.Get(index.printrep), nil
} else if index.mvtype == MT_INT {
} else if index.IsInt() {
return mlrmap.Get(index.String()), nil
} else {
return nil, errors.New(
@ -286,44 +358,6 @@ func (mlrmap *Mlrmap) GetNameAtPositionalIndex(position int) (string, bool) {
return mapEntry.Key, true
}
// ----------------------------------------------------------------
// TODO: put error-return into this API
func (mlrmap *Mlrmap) PutNameWithPositionalIndex(position int, name *Mlrval) {
positionalEntry := mlrmap.findEntryByPositionalIndex(position)
if positionalEntry == nil {
// TODO: handle out-of-bounds accesses
return
}
s := ""
if name.mvtype == MT_STRING {
s = name.printrep
} else if name.mvtype == MT_INT {
s = name.String()
} else {
// TODO: return MlrvalFromError()
return
}
// E.g. there are fields named 'a' and 'b', as positions 1 and 2,
// and the user does '$[[1]] = $[[2]]'. Then there would be two b's.
mapEntry := mlrmap.findEntry(s)
if mapEntry != nil && mapEntry != positionalEntry {
if mlrmap.keysToEntries != nil {
delete(mlrmap.keysToEntries, positionalEntry.Key)
}
mlrmap.Unlink(mapEntry)
}
lib.InternalCodingErrorIf(s == "")
positionalEntry.Key = s
if mlrmap.keysToEntries != nil {
mlrmap.keysToEntries[s] = positionalEntry
}
}
// ----------------------------------------------------------------
// Copies the key and value (deep-copying in case the value is array/map).
// This is safe for DSL use. See also PutReference.
@ -371,17 +405,13 @@ func (mlrmap *Mlrmap) Contains(other *Mlrmap) bool {
}
thisval := mlrmap.Get(pe.Key)
thatval := pe.Value
meq := BIF_equals(thisval, thatval)
eq, ok := meq.GetBoolValue()
lib.InternalCodingErrorIf(!ok)
if !eq {
if !Equals(thisval, thatval) {
return false
}
}
return true
}
// ----------------------------------------------------------------
func (mlrmap *Mlrmap) Clear() {
mlrmap.FieldCount = 0
// Assuming everything unreferenced is getting GC'ed by the Go runtime
@ -401,7 +431,6 @@ func (mlrmap *Mlrmap) Copy() *Mlrmap {
return other
}
// ----------------------------------------------------------------
// Returns true if it was found and removed
func (mlrmap *Mlrmap) Remove(key string) bool {
pe := mlrmap.findEntry(key)
@ -413,7 +442,6 @@ func (mlrmap *Mlrmap) Remove(key string) bool {
}
}
// ----------------------------------------------------------------
func (mlrmap *Mlrmap) MoveToHead(key string) {
pe := mlrmap.findEntry(key)
if pe != nil {
@ -422,7 +450,6 @@ func (mlrmap *Mlrmap) MoveToHead(key string) {
}
}
// ----------------------------------------------------------------
func (mlrmap *Mlrmap) MoveToTail(key string) {
pe := mlrmap.findEntry(key)
if pe != nil {
@ -439,6 +466,7 @@ func (mlrmap *Mlrmap) MoveToTail(key string) {
// This is a Mlrmap (from string to Mlrval) so we handle the first level of
// indexing here, then pass the remaining indices to the Mlrval at the desired
// slot.
func (mlrmap *Mlrmap) PutIndexed(indices []*Mlrval, rvalue *Mlrval) error {
return putIndexedOnMap(mlrmap, indices, rvalue)
}
@ -485,6 +513,7 @@ func (mlrmap *Mlrmap) GetValuesJoined() string {
// transformers which support a -g option but are invoked without it (e.g. 'mlr tail
// -n 1' vs 'mlr tail -n 1 -g a,b,c'). In this case the return value is simply
// the empty string.
func (mlrmap *Mlrmap) GetSelectedValuesJoined(selectedFieldNames []string) (string, bool) {
if len(selectedFieldNames) == 0 {
// The fall-through is functionally correct, but this is quicker with
@ -738,6 +767,7 @@ func (mlrmap *Mlrmap) IsNested() bool {
if mlrmap.Head == nil {
return false
} else if mlrmap.Head.Value.GetMap() == nil {
//TODO: check IsArrayOrMap()
return false
} else {
return true
@ -747,58 +777,6 @@ func (mlrmap *Mlrmap) IsNested() bool {
// ================================================================
// PRIVATE METHODS
// ----------------------------------------------------------------
func (mlrmap *Mlrmap) findEntry(key string) *MlrmapEntry {
if mlrmap.keysToEntries != nil {
return mlrmap.keysToEntries[key]
} else {
for pe := mlrmap.Head; pe != nil; pe = pe.Next {
if pe.Key == key {
return pe
}
}
return nil
}
}
// ----------------------------------------------------------------
// For '$[1]' etc. in the DSL.
//
// Notes:
// * This is a linear search.
// * Indices are 1-up not 0-up
// * Indices -n..-1 are aliases for 1..n. In particular, it will be faster to
// get the -1st field than the nth.
// * Returns 0 on invalid index: 0, or < -n, or > n where n is the number of
// fields.
func (mlrmap *Mlrmap) findEntryByPositionalIndex(position int) *MlrmapEntry {
if position > mlrmap.FieldCount || position < -mlrmap.FieldCount || position == 0 {
return nil
}
if position > 0 {
var i int = 1
for pe := mlrmap.Head; pe != nil; pe = pe.Next {
if i == position {
return pe
}
i++
}
lib.InternalCodingErrorIf(true)
} else {
var i int = -1
for pe := mlrmap.Tail; pe != nil; pe = pe.Prev {
if i == position {
return pe
}
i--
}
lib.InternalCodingErrorIf(true)
}
lib.InternalCodingErrorIf(true)
return nil
}
// ----------------------------------------------------------------
func (mlrmap *Mlrmap) Unlink(pe *MlrmapEntry) {
if pe == mlrmap.Head {
if pe == mlrmap.Tail {
@ -822,7 +800,6 @@ func (mlrmap *Mlrmap) Unlink(pe *MlrmapEntry) {
mlrmap.FieldCount--
}
// ----------------------------------------------------------------
// Does not check for duplicate keys
func (mlrmap *Mlrmap) linkAtHead(pe *MlrmapEntry) {
if mlrmap.Head == nil {

View file

@ -0,0 +1,49 @@
package mlrval
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestIsEmpty(t *testing.T) {
mlrmap := NewMlrmap()
assert.Equal(t, true, mlrmap.IsEmpty())
}
func TestPutReference(t *testing.T) {
mlrmap := NewMlrmap()
key1 := "a"
val1 := FromInt(1)
mlrmap.PutReference(key1, val1)
assert.False(t, mlrmap.IsEmpty())
assert.True(t, mlrmap.Has("a"))
assert.False(t, mlrmap.Has("b"))
assert.Equal(t, 1, mlrmap.FieldCount)
read := mlrmap.Get("b")
assert.Nil(t, read)
read = mlrmap.Get("a")
assert.NotNil(t, read)
intval, ok := read.GetIntValue()
assert.True(t, ok)
assert.Equal(t, 1, intval)
key2 := "b"
val2 := FromBool(true)
mlrmap.PutReference(key2, val2)
assert.True(t, mlrmap.Has("a"))
assert.True(t, mlrmap.Has("b"))
assert.Equal(t, 2, mlrmap.FieldCount)
read = mlrmap.Get("a")
assert.NotNil(t, read)
read = mlrmap.Get("b")
assert.NotNil(t, read)
}
// TODO: TestPrependReference

View file

@ -20,7 +20,7 @@
// otherwise) when we convert to/from JSON.
// ================================================================
package types
package mlrval
import (
"strings"
@ -136,7 +136,7 @@ func (mlrmap *Mlrmap) CopyUnflattened(
for pe := mlrmap.Head; pe != nil; pe = pe.Next {
// Is the field name something dot something?
if strings.Contains(pe.Key, separator) {
arrayOfIndices := mlrvalSplitAXHelper(pe.Key, separator)
arrayOfIndices := SplitAXHelper(pe.Key, separator)
lib.InternalCodingErrorIf(len(arrayOfIndices.arrayval) < 1)
// If the input field name was "x.a" then remember the "x".
baseIndex := arrayOfIndices.arrayval[0].String()
@ -157,7 +157,7 @@ func (mlrmap *Mlrmap) CopyUnflattened(
for baseIndex := range affectedBaseIndices {
oldValue := other.Get(baseIndex)
lib.InternalCodingErrorIf(oldValue == nil)
newValue := BIF_arrayify(oldValue)
newValue := oldValue.Arrayify()
other.PutReference(baseIndex, newValue)
}
@ -186,7 +186,7 @@ func (mlrmap *Mlrmap) CopyUnflattenFields(
for pe := mlrmap.Head; pe != nil; pe = pe.Next {
// Is the field name something dot something?
if strings.Contains(pe.Key, separator) {
arrayOfIndices := mlrvalSplitAXHelper(pe.Key, separator)
arrayOfIndices := SplitAXHelper(pe.Key, separator)
lib.InternalCodingErrorIf(len(arrayOfIndices.arrayval) < 1)
// If the input field name was "x.a" then remember the "x".
baseIndex := arrayOfIndices.arrayval[0].String()
@ -211,7 +211,7 @@ func (mlrmap *Mlrmap) CopyUnflattenFields(
for baseIndex := range affectedBaseIndices {
oldValue := other.Get(baseIndex)
lib.InternalCodingErrorIf(oldValue == nil)
newValue := BIF_arrayify(oldValue)
newValue := oldValue.Arrayify()
other.PutReference(baseIndex, newValue)
}
@ -231,10 +231,24 @@ func unflattenTerminal(input *Mlrval) *Mlrval {
return input
}
if input.printrep == "{}" {
return MlrvalFromMapReferenced(NewMlrmap())
return FromMap(NewMlrmap())
}
if input.printrep == "[]" {
return MlrvalFromArrayReference(make([]Mlrval, 0))
return FromArray(make([]Mlrval, 0))
}
return input
}
// SplitAXHelper is split out for the benefit of BIF_splitax and
// BIF_unflatten.
func SplitAXHelper(input string, separator string) *Mlrval {
fields := lib.SplitString(input, separator)
output := FromArray(make([]Mlrval, len(fields)))
for i, field := range fields {
output.arrayval[i] = *FromString(field)
}
return output
}

View file

@ -2,7 +2,7 @@
// See mlrval_json.go for details. This is the unmarshal/marshal solely for Mlrmap.
// ================================================================
package types
package mlrval
import (
"bytes"
@ -76,7 +76,7 @@ func (mlrmap *Mlrmap) marshalJSONAuxMultiline(
// Write the key which is necessarily string-valued in Miller, and in
// JSON for that matter :)
for i := 0; i < elementNestingDepth; i++ {
buffer.WriteString(MLRVAL_JSON_INDENT_STRING)
buffer.WriteString(JSON_INDENT_STRING)
}
encoded := string(millerJSONEncodeString(pe.Key))
colorized := colorizer.MaybeColorizeKey(encoded, outputIsStdout)
@ -102,7 +102,7 @@ func (mlrmap *Mlrmap) marshalJSONAuxMultiline(
// Write empty map as '{}'.
if mlrmap.Head != nil {
for i := 0; i < elementNestingDepth-1; i++ {
buffer.WriteString(MLRVAL_JSON_INDENT_STRING)
buffer.WriteString(JSON_INDENT_STRING)
}
}
buffer.WriteString("}")
@ -153,9 +153,9 @@ func (entry *MlrmapEntry) JSONStringifyInPlace(
) {
outputBytes, err := entry.Value.MarshalJSON(jsonFormatting, false)
if err != nil {
entry.Value = MLRVAL_ERROR
entry.Value = ERROR
} else {
entry.Value = MlrvalFromString(string(outputBytes))
entry.Value = FromString(string(outputBytes))
}
}
@ -165,6 +165,6 @@ func (entry *MlrmapEntry) JSONParseInPlace() {
input := entry.Value.String()
err := entry.Value.UnmarshalJSON([]byte(input))
if err != nil {
entry.Value = MLRVAL_ERROR
entry.Value = ERROR
}
}

View file

@ -0,0 +1,17 @@
package mlrval
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewMlrmapAsRecord(t *testing.T) {
mlrmap := newMlrmapUnhashed()
assert.Equal(t, false, mlrmap.isHashed())
}
func TestNewMlrmap(t *testing.T) {
mlrmap := NewMlrmap()
assert.Equal(t, true, mlrmap.isHashed())
}

View file

@ -1,4 +1,4 @@
package types
package mlrval
import (
"bytes"

View file

@ -0,0 +1,103 @@
package mlrval
import (
"strconv"
"github.com/johnkerl/miller/internal/pkg/lib"
)
func (mv *Mlrval) GetArrayLength() (int, bool) {
if mv.IsArray() {
return len(mv.arrayval), true
} else {
return -999, false
}
}
func CopyMlrvalArray(input []Mlrval) []Mlrval {
output := make([]Mlrval, len(input))
for i, element := range input {
output[i] = *element.Copy()
}
return output
}
func CopyMlrvalPointerArray(input []*Mlrval) []*Mlrval {
output := make([]*Mlrval, len(input))
for i, element := range input {
output[i] = element.Copy()
}
return output
}
// ---------------------------------------------------------------
// For the flatten verb and DSL function.
func (mv *Mlrval) FlattenToMap(prefix string, delimiter string) Mlrval {
retval := NewMlrmap()
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.mapval.IsEmpty() {
if prefix != "" {
retval.PutCopy(prefix, FromString("{}"))
}
}
for pe := mv.mapval.Head; pe != nil; pe = pe.Next {
nextPrefix := pe.Key
if prefix != "" {
nextPrefix = prefix + delimiter + nextPrefix
}
if pe.Value.IsMap() || pe.Value.IsArray() {
nextResult := pe.Value.FlattenToMap(nextPrefix, delimiter)
lib.InternalCodingErrorIf(nextResult.mvtype != MT_MAP)
for pf := nextResult.mapval.Head; pf != nil; pf = pf.Next {
retval.PutCopy(pf.Key, pf.Value.Copy())
}
} else {
retval.PutCopy(nextPrefix, pe.Value.Copy())
}
}
} 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.arrayval) == 0 {
if prefix != "" {
retval.PutCopy(prefix, FromString("[]"))
}
}
for zindex, value := range mv.arrayval {
nextPrefix := strconv.Itoa(zindex + 1) // Miller user-space indices are 1-up
if prefix != "" {
nextPrefix = prefix + delimiter + nextPrefix
}
if value.IsMap() || value.IsArray() {
nextResult := value.FlattenToMap(nextPrefix, delimiter)
lib.InternalCodingErrorIf(nextResult.mvtype != MT_MAP)
for pf := nextResult.mapval.Head; pf != nil; pf = pf.Next {
retval.PutCopy(pf.Key, pf.Value.Copy())
}
} else {
retval.PutCopy(nextPrefix, value.Copy())
}
}
} else {
retval.PutCopy(prefix, mv.Copy())
}
return *FromMap(retval)
}
// Increment is used by stats1.
func (mv *Mlrval) Increment() {
if mv.mvtype == MT_INT {
mv.intval++
} else if mv.mvtype == MT_FLOAT {
mv.floatval++
}
}

View file

@ -0,0 +1,439 @@
// ================================================================
// Boolean expressions for ==, !=, >, >=, <, <=, <=> on Mlrvals
// ================================================================
// TODO: comment about mvtype; deferral; copying of deferrence.
package mlrval
import (
"github.com/johnkerl/miller/internal/pkg/lib"
)
type CmpFuncBool func(input1, input2 *Mlrval) bool
type CmpFuncInt func(input1, input2 *Mlrval) int // -1, 0, 1 for <=>
// ----------------------------------------------------------------
// Exported methods
func Equals(input1, input2 *Mlrval) bool {
return eq_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func NotEquals(input1, input2 *Mlrval) bool {
return ne_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func GreaterThan(input1, input2 *Mlrval) bool {
return gt_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func GreaterThanOrEquals(input1, input2 *Mlrval) bool {
return ge_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func LessThan(input1, input2 *Mlrval) bool {
return lt_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func LessThanOrEquals(input1, input2 *Mlrval) bool {
return le_dispositions[input1.Type()][input2.Type()](input1, input2)
}
func Cmp(input1, input2 *Mlrval) int {
return cmp_dispositions[input1.Type()][input2.Type()](input1, input2)
}
// ----------------------------------------------------------------
// Support routines for disposition-matrix entries
// string_cmp implements the spaceship operator for strings.
func string_cmp(a, b string) int {
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}
// int_cmp implements the spaceship operator for ints.
func int_cmp(a, b int) int {
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}
// float_cmp implements the spaceship operator for floats.
func float_cmp(a, b float64) int {
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}
// _true return boolean true as a binary-input function
func _true(input1, input2 *Mlrval) bool {
return true
}
// _fals return boolean false as a binary-input function
func _fals(input1, input2 *Mlrval) bool {
return false
}
// _i0__ return int 0 as a binary-input function
func _i0__(input1, input2 *Mlrval) int {
return 0
}
// _i1__ return int 1 as a binary-input function
func _i1__(input1, input2 *Mlrval) int {
return 1
}
// _n1__ return int -1 as a binary-input function
func _n1__(input1, input2 *Mlrval) int {
return -1
}
// ----------------------------------------------------------------
// Disposition-matrix entries
func eq_b_ss(input1, input2 *Mlrval) bool {
return input1.printrep == input2.printrep
}
func ne_b_ss(input1, input2 *Mlrval) bool {
return input1.printrep != input2.printrep
}
func gt_b_ss(input1, input2 *Mlrval) bool {
return input1.printrep > input2.printrep
}
func ge_b_ss(input1, input2 *Mlrval) bool {
return input1.printrep >= input2.printrep
}
func lt_b_ss(input1, input2 *Mlrval) bool {
return input1.printrep < input2.printrep
}
func le_b_ss(input1, input2 *Mlrval) bool {
return input1.printrep <= input2.printrep
}
func cmp_b_ss(input1, input2 *Mlrval) int {
return string_cmp(input1.printrep, input2.printrep)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_xs(input1, input2 *Mlrval) bool {
return input1.String() == input2.printrep
}
func ne_b_xs(input1, input2 *Mlrval) bool {
return input1.String() != input2.printrep
}
func gt_b_xs(input1, input2 *Mlrval) bool {
return input1.String() > input2.printrep
}
func ge_b_xs(input1, input2 *Mlrval) bool {
return input1.String() >= input2.printrep
}
func lt_b_xs(input1, input2 *Mlrval) bool {
return input1.String() < input2.printrep
}
func le_b_xs(input1, input2 *Mlrval) bool {
return input1.String() <= input2.printrep
}
func cmp_b_xs(input1, input2 *Mlrval) int {
return string_cmp(input1.String(), input2.printrep)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_sx(input1, input2 *Mlrval) bool {
return input1.printrep == input2.String()
}
func ne_b_sx(input1, input2 *Mlrval) bool {
return input1.printrep != input2.String()
}
func gt_b_sx(input1, input2 *Mlrval) bool {
return input1.printrep > input2.String()
}
func ge_b_sx(input1, input2 *Mlrval) bool {
return input1.printrep >= input2.String()
}
func lt_b_sx(input1, input2 *Mlrval) bool {
return input1.printrep < input2.String()
}
func le_b_sx(input1, input2 *Mlrval) bool {
return input1.printrep <= input2.String()
}
func cmp_b_sx(input1, input2 *Mlrval) int {
return string_cmp(input1.printrep, input2.String())
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_ii(input1, input2 *Mlrval) bool {
return input1.intval == input2.intval
}
func ne_b_ii(input1, input2 *Mlrval) bool {
return input1.intval != input2.intval
}
func gt_b_ii(input1, input2 *Mlrval) bool {
return input1.intval > input2.intval
}
func ge_b_ii(input1, input2 *Mlrval) bool {
return input1.intval >= input2.intval
}
func lt_b_ii(input1, input2 *Mlrval) bool {
return input1.intval < input2.intval
}
func le_b_ii(input1, input2 *Mlrval) bool {
return input1.intval <= input2.intval
}
func cmp_b_ii(input1, input2 *Mlrval) int {
return int_cmp(input1.intval, input2.intval)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_if(input1, input2 *Mlrval) bool {
return float64(input1.intval) == input2.floatval
}
func ne_b_if(input1, input2 *Mlrval) bool {
return float64(input1.intval) != input2.floatval
}
func gt_b_if(input1, input2 *Mlrval) bool {
return float64(input1.intval) > input2.floatval
}
func ge_b_if(input1, input2 *Mlrval) bool {
return float64(input1.intval) >= input2.floatval
}
func lt_b_if(input1, input2 *Mlrval) bool {
return float64(input1.intval) < input2.floatval
}
func le_b_if(input1, input2 *Mlrval) bool {
return float64(input1.intval) <= input2.floatval
}
func cmp_b_if(input1, input2 *Mlrval) int {
return float_cmp(float64(input1.intval), input2.floatval)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_fi(input1, input2 *Mlrval) bool {
return input1.floatval == float64(input2.intval)
}
func ne_b_fi(input1, input2 *Mlrval) bool {
return input1.floatval != float64(input2.intval)
}
func gt_b_fi(input1, input2 *Mlrval) bool {
return input1.floatval > float64(input2.intval)
}
func ge_b_fi(input1, input2 *Mlrval) bool {
return input1.floatval >= float64(input2.intval)
}
func lt_b_fi(input1, input2 *Mlrval) bool {
return input1.floatval < float64(input2.intval)
}
func le_b_fi(input1, input2 *Mlrval) bool {
return input1.floatval <= float64(input2.intval)
}
func cmp_b_fi(input1, input2 *Mlrval) int {
return float_cmp(input1.floatval, float64(input2.intval))
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_ff(input1, input2 *Mlrval) bool {
return input1.floatval == input2.floatval
}
func ne_b_ff(input1, input2 *Mlrval) bool {
return input1.floatval != input2.floatval
}
func gt_b_ff(input1, input2 *Mlrval) bool {
return input1.floatval > input2.floatval
}
func ge_b_ff(input1, input2 *Mlrval) bool {
return input1.floatval >= input2.floatval
}
func lt_b_ff(input1, input2 *Mlrval) bool {
return input1.floatval < input2.floatval
}
func le_b_ff(input1, input2 *Mlrval) bool {
return input1.floatval <= input2.floatval
}
func cmp_b_ff(input1, input2 *Mlrval) int {
return float_cmp(input1.floatval, input2.floatval)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_bb(input1, input2 *Mlrval) bool {
return input1.boolval == input2.boolval
}
func ne_b_bb(input1, input2 *Mlrval) bool {
return input1.boolval != input2.boolval
}
func gt_b_bb(input1, input2 *Mlrval) bool {
return lib.BoolToInt(input1.boolval) > lib.BoolToInt(input2.boolval)
}
func ge_b_bb(input1, input2 *Mlrval) bool {
return lib.BoolToInt(input1.boolval) >= lib.BoolToInt(input2.boolval)
}
func lt_b_bb(input1, input2 *Mlrval) bool {
return lib.BoolToInt(input1.boolval) < lib.BoolToInt(input2.boolval)
}
func le_b_bb(input1, input2 *Mlrval) bool {
return lib.BoolToInt(input1.boolval) <= lib.BoolToInt(input2.boolval)
}
func cmp_b_bb(input1, input2 *Mlrval) int {
return int_cmp(lib.BoolToInt(input1.boolval), lib.BoolToInt(input2.boolval))
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_aa(input1, input2 *Mlrval) bool {
a := input1.arrayval
b := input2.arrayval
// Different-length arrays are not equal
if len(a) != len(b) {
return false
}
// Same-length arrays: return false if any slot is not equal, else true.
for i := range a {
if !Equals(&a[i], &b[i]) {
return false
}
}
return true
}
func ne_b_aa(input1, input2 *Mlrval) bool {
return !eq_b_aa(input1, input2)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func eq_b_mm(input1, input2 *Mlrval) bool {
return input1.mapval.Equals(input2.mapval)
}
func ne_b_mm(input1, input2 *Mlrval) bool {
return !input1.mapval.Equals(input2.mapval)
}
// We get a Golang "initialization loop" due to recursive depth computation
// if this is defined statically. So, we use a "package init" function.
var eq_dispositions = [MT_DIM][MT_DIM]CmpFuncBool{}
func init() {
eq_dispositions = [MT_DIM][MT_DIM]CmpFuncBool{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*ABSENT */ {_fals, _true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*NULL */ {_fals, _fals, _true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*VOID */ {_fals, _fals, _fals, eq_b_ss, eq_b_ss, eq_b_sx, eq_b_sx, _fals, _fals, _fals, _fals},
/*STRING */ {_fals, _fals, _fals, eq_b_ss, eq_b_ss, eq_b_sx, eq_b_sx, _fals, _fals, _fals, _fals},
/*INT */ {_fals, _fals, _fals, eq_b_xs, eq_b_xs, eq_b_ii, eq_b_if, _fals, _fals, _fals, _fals},
/*FLOAT */ {_fals, _fals, _fals, eq_b_xs, eq_b_xs, eq_b_fi, eq_b_ff, _fals, _fals, _fals, _fals},
/*BOOL */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, eq_b_bb, _fals, _fals, _fals},
/*ARRAY */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, eq_b_aa, _fals, _fals},
/*MAP */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, eq_b_mm, _fals},
/*FUNC */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _true},
}
}
var ne_dispositions = [MT_DIM][MT_DIM]CmpFuncBool{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*ABSENT */ {_fals, _true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*NULL */ {_fals, _fals, _fals, _true, _true, _true, _true, _true, _true, _true, _fals},
/*VOID */ {_fals, _fals, _true, ne_b_ss, ne_b_ss, ne_b_sx, ne_b_sx, _true, _true, _true, _fals},
/*STRING */ {_fals, _fals, _true, ne_b_ss, ne_b_ss, ne_b_sx, ne_b_sx, _true, _true, _true, _fals},
/*INT */ {_fals, _fals, _true, ne_b_xs, ne_b_xs, ne_b_ii, ne_b_if, _true, _true, _true, _fals},
/*FLOAT */ {_fals, _fals, _true, ne_b_xs, ne_b_xs, ne_b_fi, ne_b_ff, _true, _true, _true, _fals},
/*BOOL */ {_fals, _fals, _true, _true, _true, _true, _true, ne_b_bb, _true, _true, _fals},
/*ARRAY */ {_fals, _fals, _true, _true, _true, _true, _true, _true, ne_b_aa, _true, _fals},
/*MAP */ {_fals, _fals, _true, _true, _true, _true, _true, _true, _true, ne_b_mm, _fals},
/*FUNC */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _true},
}
var gt_dispositions = [MT_DIM][MT_DIM]CmpFuncBool{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*ABSENT */ {_fals, _true, _true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*NULL */ {_true, _fals, _fals, _true, _true, _true, _true, _true, _fals, _fals, _fals},
/*VOID */ {_fals, _fals, _fals, gt_b_ss, gt_b_ss, gt_b_sx, gt_b_sx, _fals, _fals, _fals, _fals},
/*STRING */ {_fals, _fals, _fals, gt_b_ss, gt_b_ss, gt_b_sx, gt_b_sx, _fals, _fals, _fals, _fals},
/*INT */ {_fals, _fals, _fals, gt_b_xs, gt_b_xs, gt_b_ii, gt_b_if, _fals, _fals, _fals, _fals},
/*FLOAT */ {_fals, _fals, _fals, gt_b_xs, gt_b_xs, gt_b_fi, gt_b_ff, _fals, _fals, _fals, _fals},
/*BOOL */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, gt_b_bb, _fals, _fals, _fals},
/*ARRAY */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*MAP */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*FUNC */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _true},
}
var ge_dispositions = [MT_DIM][MT_DIM]CmpFuncBool{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*ABSENT */ {_fals, _true, _true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*NULL */ {_true, _fals, _true, _true, _true, _true, _true, _true, _fals, _fals, _fals},
/*VOID */ {_fals, _fals, _fals, ge_b_ss, ge_b_ss, ge_b_sx, ge_b_sx, _fals, _fals, _fals, _fals},
/*STRING */ {_fals, _fals, _fals, ge_b_ss, ge_b_ss, ge_b_sx, ge_b_sx, _fals, _fals, _fals, _fals},
/*INT */ {_fals, _fals, _fals, ge_b_xs, ge_b_xs, ge_b_ii, ge_b_if, _fals, _fals, _fals, _fals},
/*FLOAT */ {_fals, _fals, _fals, ge_b_xs, ge_b_xs, ge_b_fi, ge_b_ff, _fals, _fals, _fals, _fals},
/*BOOL */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, ge_b_bb, _fals, _fals, _fals},
/*ARRAY */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*MAP */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*FUNC */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _true},
}
var lt_dispositions = [MT_DIM][MT_DIM]CmpFuncBool{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_true, _fals, _true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*ABSENT */ {_fals, _true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*NULL */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*VOID */ {_fals, _fals, _true, lt_b_ss, lt_b_ss, lt_b_sx, lt_b_sx, _fals, _fals, _fals, _fals},
/*STRING */ {_fals, _fals, _true, lt_b_ss, lt_b_ss, lt_b_sx, lt_b_sx, _fals, _fals, _fals, _fals},
/*INT */ {_fals, _fals, _true, lt_b_xs, lt_b_xs, lt_b_ii, lt_b_if, _fals, _fals, _fals, _fals},
/*FLOAT */ {_fals, _fals, _true, lt_b_xs, lt_b_xs, lt_b_fi, lt_b_ff, _fals, _fals, _fals, _fals},
/*BOOL */ {_fals, _fals, _true, _fals, _fals, _fals, _fals, lt_b_bb, _fals, _fals, _fals},
/*ARRAY */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*MAP */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*FUNC */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _true},
}
var le_dispositions = [MT_DIM][MT_DIM]CmpFuncBool{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_true, _fals, _true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*ABSENT */ {_fals, _true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*NULL */ {_fals, _fals, _true, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*VOID */ {_fals, _fals, _true, le_b_ss, le_b_ss, le_b_sx, le_b_sx, _fals, _fals, _fals, _fals},
/*STRING */ {_fals, _fals, _true, le_b_ss, le_b_ss, le_b_sx, le_b_sx, _fals, _fals, _fals, _fals},
/*INT */ {_fals, _fals, _true, le_b_xs, le_b_xs, le_b_ii, le_b_if, _fals, _fals, _fals, _fals},
/*FLOAT */ {_fals, _fals, _true, le_b_xs, le_b_xs, le_b_fi, le_b_ff, _fals, _fals, _fals, _fals},
/*BOOL */ {_fals, _fals, _true, _fals, _fals, _fals, _fals, le_b_bb, _fals, _fals, _fals},
/*ARRAY */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*MAP */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals},
/*FUNC */ {_fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _fals, _true},
}
// TODO: flesh these out for array and map
var cmp_dispositions = [MT_DIM][MT_DIM]CmpFuncInt{
// . ERROR ABSENT NULL VOID STRING INT FLOAT BOOL ARRAY MAP FUNC
/*ERROR */ {_i0__, _i0__, _n1__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__},
/*ABSENT */ {_i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__},
/*NULL */ {_i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__},
/*VOID */ {_i0__, _i0__, _n1__, cmp_b_ss, cmp_b_ss, cmp_b_sx, cmp_b_sx, _i0__, _i0__, _i0__, _i0__},
/*STRING */ {_i0__, _i0__, _n1__, cmp_b_ss, cmp_b_ss, cmp_b_sx, cmp_b_sx, _i0__, _i0__, _i0__, _i0__},
/*INT */ {_i0__, _i0__, _n1__, cmp_b_xs, cmp_b_xs, cmp_b_ii, cmp_b_if, _i0__, _i0__, _i0__, _i0__},
/*FLOAT */ {_i0__, _i0__, _n1__, cmp_b_xs, cmp_b_xs, cmp_b_fi, cmp_b_ff, _i0__, _i0__, _i0__, _i0__},
/*BOOL */ {_i0__, _i0__, _n1__, _i0__, _i0__, _i0__, _i0__, cmp_b_bb, _i0__, _i0__, _i0__},
/*ARRAY */ {_i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__},
/*MAP */ {_i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__},
/*FUNC */ {_i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__, _i0__},
}

View file

@ -66,12 +66,13 @@
//
// ================================================================
package types
package mlrval
import (
"errors"
"fmt"
"os"
"strconv"
"github.com/johnkerl/miller/internal/pkg/lib"
)
@ -79,15 +80,15 @@ import (
// ================================================================
// TODO: copy-reduction refactor
func (mv *Mlrval) ArrayGet(mindex *Mlrval) Mlrval {
if mv.mvtype != MT_ARRAY {
return *MLRVAL_ERROR
if !mv.IsArray() {
return *ERROR
}
if mindex.mvtype != MT_INT {
return *MLRVAL_ERROR
if !mindex.IsInt() {
return *ERROR
}
value := arrayGetAliased(&mv.arrayval, mindex.intval)
if value == nil {
return *MLRVAL_ABSENT
return *ABSENT
} else {
return *value
}
@ -96,7 +97,7 @@ func (mv *Mlrval) ArrayGet(mindex *Mlrval) Mlrval {
// ----------------------------------------------------------------
// TODO: make this return error so caller can do 'if err == nil { ... }'
func (mv *Mlrval) ArrayPut(mindex *Mlrval, value *Mlrval) {
if mv.mvtype != MT_ARRAY {
if !mv.IsArray() {
fmt.Fprintf(
os.Stderr,
"mlr: expected array as indexed item in ArrayPut; got %s\n",
@ -104,7 +105,7 @@ func (mv *Mlrval) ArrayPut(mindex *Mlrval, value *Mlrval) {
)
os.Exit(1)
}
if mindex.mvtype != MT_INT {
if !mindex.IsInt() {
// TODO: need to be careful about semantics here.
// Silent no-ops are not good UX ...
fmt.Fprintf(
@ -208,7 +209,7 @@ func UnaliasArrayLengthIndex(n int, mindex int) (int, bool) {
// ----------------------------------------------------------------
// TODO: thinking about capacity-resizing
func (mv *Mlrval) ArrayAppend(value *Mlrval) {
if mv.mvtype != MT_ARRAY {
if !mv.IsArray() {
// TODO: need to be careful about semantics here.
// Silent no-ops are not good UX ...
return
@ -218,16 +219,16 @@ func (mv *Mlrval) ArrayAppend(value *Mlrval) {
// ================================================================
func (mv *Mlrval) MapGet(key *Mlrval) Mlrval {
if mv.mvtype != MT_MAP {
return *MLRVAL_ERROR
if !mv.IsMap() {
return *ERROR
}
mval, err := mv.mapval.GetWithMlrvalIndex(key)
if err != nil { // xxx maybe error-return in the API
return *MLRVAL_ERROR
return *ERROR
}
if mval == nil {
return *MLRVAL_ABSENT
return *ABSENT
}
// This returns a reference, not a (deep) copy. In general in Miller, we
// copy only on write/put.
@ -236,15 +237,15 @@ func (mv *Mlrval) MapGet(key *Mlrval) Mlrval {
// ----------------------------------------------------------------
func (mv *Mlrval) MapPut(key *Mlrval, value *Mlrval) {
if mv.mvtype != MT_MAP {
if !mv.IsMap() {
// TODO: need to be careful about semantics here.
// Silent no-ops are not good UX ...
return
}
if key.mvtype == MT_STRING {
if key.IsString() {
mv.mapval.PutCopy(key.printrep, value)
} else if key.mvtype == MT_INT {
} else if key.IsInt() {
mv.mapval.PutCopy(key.String(), value)
}
// TODO: need to be careful about semantics here.
@ -290,19 +291,19 @@ func (mv *Mlrval) MapPut(key *Mlrval, value *Mlrval) {
func (mv *Mlrval) PutIndexed(indices []*Mlrval, rvalue *Mlrval) error {
lib.InternalCodingErrorIf(len(indices) < 1)
if mv.mvtype == MT_MAP {
if mv.IsMap() {
return putIndexedOnMap(mv.mapval, indices, rvalue)
} else if mv.mvtype == MT_ARRAY {
} else if mv.IsArray() {
return putIndexedOnArray(&mv.arrayval, indices, rvalue)
} else {
baseIndex := indices[0]
if baseIndex.mvtype == MT_STRING {
*mv = *MlrvalFromEmptyMap()
if baseIndex.IsString() {
*mv = *FromEmptyMap()
return putIndexedOnMap(mv.mapval, indices, rvalue)
} else if baseIndex.mvtype == MT_INT {
*mv = MlrvalEmptyArray()
} else if baseIndex.IsInt() {
*mv = *FromEmptyArray()
return putIndexedOnArray(&mv.arrayval, indices, rvalue)
} else {
return errors.New(
@ -340,7 +341,7 @@ func putIndexedOnMap(baseMap *Mlrmap, indices []*Mlrval, rvalue *Mlrval) error {
}
// If not last index, then recurse.
if baseIndex.mvtype != MT_STRING && baseIndex.mvtype != MT_INT {
if !baseIndex.IsString() && !baseIndex.IsInt() {
// Base is map, index is invalid type
return errors.New(
"mlr: map indices must be string, int, or array thereof; got " + baseIndex.GetTypeName(),
@ -353,7 +354,7 @@ func putIndexedOnMap(baseMap *Mlrmap, indices []*Mlrval, rvalue *Mlrval) error {
nextIndex := indices[1]
var err error = nil
baseValue, err = NewMlrvalForAutoDeepen(nextIndex.mvtype)
baseValue, err = NewMlrvalForAutoDeepen(nextIndex.Type())
if err != nil {
return err
}
@ -374,7 +375,7 @@ func putIndexedOnArray(
lib.InternalCodingErrorIf(numIndices < 1)
mindex := indices[0]
if mindex.mvtype != MT_INT {
if !mindex.IsInt() {
return errors.New(
"Array index must be int, but was " +
mindex.GetTypeName() +
@ -406,13 +407,13 @@ func putIndexedOnArray(
nextIndex := indices[1]
// Overwrite what's in this slot if it's the wrong type
if nextIndex.mvtype == MT_STRING {
if (*baseArray)[zindex].mvtype != MT_MAP {
(*baseArray)[zindex] = *MlrvalFromEmptyMap()
if nextIndex.IsString() {
if !(*baseArray)[zindex].IsMap() {
(*baseArray)[zindex] = *FromEmptyMap()
}
} else if nextIndex.mvtype == MT_INT {
if (*baseArray)[zindex].mvtype != MT_ARRAY {
(*baseArray)[zindex] = MlrvalEmptyArray()
} else if nextIndex.IsInt() {
if !(*baseArray)[zindex].IsArray() {
(*baseArray)[zindex] = *FromEmptyArray()
}
} else {
return errors.New(
@ -442,10 +443,10 @@ func putIndexedOnArray(
func (mv *Mlrval) RemoveIndexed(indices []*Mlrval) error {
lib.InternalCodingErrorIf(len(indices) < 1)
if mv.mvtype == MT_MAP {
if mv.IsMap() {
return removeIndexedOnMap(mv.mapval, indices)
} else if mv.mvtype == MT_ARRAY {
} else if mv.IsArray() {
return removeIndexedOnArray(&mv.arrayval, indices)
} else {
@ -464,7 +465,7 @@ func removeIndexedOnMap(baseMap *Mlrmap, indices []*Mlrval) error {
// If last index, then unset.
if numIndices == 1 {
if baseIndex.mvtype == MT_STRING || baseIndex.mvtype == MT_INT {
if baseIndex.IsString() || baseIndex.IsInt() {
baseMap.Remove(baseIndex.String())
return nil
} else {
@ -476,7 +477,7 @@ func removeIndexedOnMap(baseMap *Mlrmap, indices []*Mlrval) error {
}
// If not last index, then recurse.
if baseIndex.mvtype == MT_STRING || baseIndex.mvtype == MT_INT {
if baseIndex.IsString() || baseIndex.IsInt() {
// Base is map, index is string
baseValue := baseMap.Get(baseIndex.String())
if baseValue != nil {
@ -503,7 +504,7 @@ func removeIndexedOnArray(
lib.InternalCodingErrorIf(numIndices < 1)
mindex := indices[0]
if mindex.mvtype != MT_INT {
if !mindex.IsInt() {
return errors.New(
"Array index must be int, but was " +
mindex.GetTypeName() +
@ -575,18 +576,18 @@ func BsearchMlrvalArrayForDescendingInsert(
return 0
}
if MlrvalGreaterThanAsBool(value, (*array)[0]) {
if GreaterThan(value, (*array)[0]) {
return 0
}
if MlrvalLessThanAsBool(value, (*array)[hi]) {
if LessThan(value, (*array)[hi]) {
return size
}
for lo < hi {
middleElement := (*array)[mid]
if MlrvalEqualsAsBool(value, middleElement) {
if Equals(value, middleElement) {
return mid
} else if MlrvalGreaterThanAsBool(value, middleElement) {
} else if GreaterThan(value, middleElement) {
hi = mid
newmid = (hi + lo) / 2
} else {
@ -594,9 +595,9 @@ func BsearchMlrvalArrayForDescendingInsert(
newmid = (hi + lo) / 2
}
if mid == newmid {
if MlrvalGreaterThanOrEqualsAsBool(value, (*array)[lo]) {
if GreaterThanOrEquals(value, (*array)[lo]) {
return lo
} else if MlrvalGreaterThanOrEqualsAsBool(value, (*array)[hi]) {
} else if GreaterThanOrEquals(value, (*array)[hi]) {
return hi
} else {
return hi + 1
@ -622,18 +623,18 @@ func BsearchMlrvalArrayForAscendingInsert(
return 0
}
if MlrvalLessThanAsBool(value, (*array)[0]) {
if LessThan(value, (*array)[0]) {
return 0
}
if MlrvalGreaterThanAsBool(value, (*array)[hi]) {
if GreaterThan(value, (*array)[hi]) {
return size
}
for lo < hi {
middleElement := (*array)[mid]
if MlrvalEqualsAsBool(value, middleElement) {
if Equals(value, middleElement) {
return mid
} else if MlrvalLessThanAsBool(value, middleElement) {
} else if LessThan(value, middleElement) {
hi = mid
newmid = (hi + lo) / 2
} else {
@ -641,9 +642,9 @@ func BsearchMlrvalArrayForAscendingInsert(
newmid = (hi + lo) / 2
}
if mid == newmid {
if MlrvalLessThanOrEqualsAsBool(value, (*array)[lo]) {
if LessThanOrEquals(value, (*array)[lo]) {
return lo
} else if MlrvalLessThanOrEqualsAsBool(value, (*array)[hi]) {
} else if LessThanOrEquals(value, (*array)[hi]) {
return hi
} else {
return hi + 1
@ -654,3 +655,90 @@ func BsearchMlrvalArrayForAscendingInsert(
return lo
}
// NewMlrvalForAutoDeepen is for auto-deepen of nested maps in things like
//
// $foo[1]["a"][2]["b"] = 3
//
// Autocreated levels are maps. Array levels can be explicitly created e.g.
//
// $foo[1]["a"] ??= []
// $foo[1]["a"][2]["b"] = 3
func NewMlrvalForAutoDeepen(mvtype MVType) (*Mlrval, error) {
if mvtype == MT_STRING || mvtype == MT_INT {
empty := FromEmptyMap()
return empty, nil
} else {
return nil, errors.New(
"mlr: indices must be string, int, or array thereof; got " + GetTypeName(mvtype),
)
}
}
func (mv *Mlrval) Arrayify() *Mlrval {
if mv.IsMap() {
if mv.mapval.IsEmpty() {
return mv
}
convertible := true
i := 0
for pe := mv.mapval.Head; pe != nil; pe = pe.Next {
sval := strconv.Itoa(i + 1) // Miller user-space indices are 1-up
i++
if pe.Key != sval {
convertible = false
}
pe.Value = pe.Value.Arrayify()
}
if convertible {
arrayval := make([]Mlrval, mv.mapval.FieldCount)
i := 0
for pe := mv.mapval.Head; pe != nil; pe = pe.Next {
arrayval[i] = *pe.Value.Copy()
i++
}
return FromArray(arrayval)
} else {
return mv
}
} else if mv.IsArray() {
// TODO: comment (or rethink) that this modifies its inputs!!
output := mv.Copy()
for i := range mv.arrayval {
output.arrayval[i] = *output.arrayval[i].Arrayify()
}
return output
} else {
return mv
}
}
func LengthenMlrvalArray(array *[]Mlrval, newLength64 int) {
newLength := int(newLength64)
lib.InternalCodingErrorIf(newLength <= len(*array))
if newLength <= cap(*array) {
newArray := (*array)[:newLength]
for zindex := len(*array); zindex < newLength; zindex++ {
// TODO: comment why not MT_ABSENT or MT_VOID
newArray[zindex] = *NULL
}
*array = newArray
} else {
newArray := make([]Mlrval, newLength, 2*newLength)
zindex := 0
for zindex = 0; zindex < len(*array); zindex++ {
newArray[zindex] = (*array)[zindex]
}
for zindex = len(*array); zindex < newLength; zindex++ {
// TODO: comment why not MT_ABSENT or MT_VOID
newArray[zindex] = *NULL
}
*array = newArray
}
}

View file

@ -0,0 +1,59 @@
// ================================================================
// Constants/singletons of various types
// ================================================================
package mlrval
// MlrvalFromPending is designed solely for the JSON API, for something
// intended to be mutated after construction once its type is (later) known.
// Whereas ERROR, ABSENT, etc are all singletons, this one
// must be mutable and therefor non-singleton.
func MlrvalFromPending() Mlrval {
return Mlrval{
mvtype: MT_PENDING,
printrep: "(bug-if-you-see-this:case-3)", // INVALID_PRINTREP,
}
}
// These are made singletons as part of a copy-reduction effort. They're not
// marked const (I haven't figured out the right way to get that to compile;
// just using `const` isn't enough) but the gentelpersons' agreement is that
// the caller should never modify these.
var ERROR = &Mlrval{
mvtype: MT_ERROR,
printrep: ERROR_PRINTREP,
printrepValid: true,
}
var ABSENT = &Mlrval{
mvtype: MT_ABSENT,
printrep: ABSENT_PRINTREP,
printrepValid: true,
}
var NULL = &Mlrval{
mvtype: MT_NULL,
printrep: "null",
printrepValid: true,
}
var VOID = &Mlrval{
mvtype: MT_VOID,
printrep: "",
printrepValid: true,
}
var TRUE = &Mlrval{
mvtype: MT_BOOL,
printrep: "true",
printrepValid: true,
boolval: true,
}
var FALSE = &Mlrval{
mvtype: MT_BOOL,
printrep: "false",
printrepValid: true,
}

View file

@ -0,0 +1,12 @@
package mlrval
// TODO: comment about mvtype; deferrence; copying of deferrence.
func (mv *Mlrval) Copy() *Mlrval {
other := *mv
if mv.mvtype == MT_MAP {
other.mapval = mv.mapval.Copy()
} else if mv.mvtype == MT_ARRAY {
other.arrayval = CopyMlrvalArray(mv.arrayval)
}
return &other
}

View file

@ -1,4 +1,4 @@
package types
package mlrval
import (
"errors"
@ -38,40 +38,51 @@ import (
// - -i, -f, -s
// ----------------------------------------------------------------
// ----------------------------------------------------------------
var mlrvalFormatterCache map[string]IMlrvalFormatter = make(map[string]IMlrvalFormatter)
// Nil means use default format.
// Set from the CLI parser using mlr --ofmt.
var floatOutputFormatter IFormatter = nil
func GetMlrvalFormatter(
func SetFloatOutputFormat(formatString string) error {
formatter, err := GetFormatter(formatString)
if err != nil {
return err
}
floatOutputFormatter = formatter
return nil
}
var formatterCache map[string]IFormatter = make(map[string]IFormatter)
type IFormatter interface {
Format(mlrval *Mlrval) *Mlrval
FormatFloat(floatValue float64) string // for --ofmt
}
func GetFormatter(
userLevelFormatString string,
) (IMlrvalFormatter, error) {
) (IFormatter, error) {
// Cache hit
formatter, ok := mlrvalFormatterCache[userLevelFormatString]
formatter, ok := formatterCache[userLevelFormatString]
if ok {
return formatter, nil
}
// Cache miss
formatter, err := newMlrvalFormatter(userLevelFormatString)
formatter, err := newFormatter(userLevelFormatString)
if err != nil {
// TODO: temp exit
fmt.Printf("mlr: %v\n", err)
return nil, err
}
mlrvalFormatterCache[userLevelFormatString] = formatter
formatterCache[userLevelFormatString] = formatter
return formatter, nil
}
// ----------------------------------------------------------------
type IMlrvalFormatter interface {
Format(mlrval *Mlrval) *Mlrval
FormatFloat(floatValue float64) string // for --ofmt
}
// People can pass in things like "X%sX" unfortunately :(
func newMlrvalFormatter(
func newFormatter(
userLevelFormatString string,
) (IMlrvalFormatter, error) {
) (IFormatter, error) {
numPercents := strings.Count(userLevelFormatString, "%")
if numPercents < 1 {
return nil, errors.New(
@ -99,111 +110,112 @@ func newMlrvalFormatter(
// and double-precision floats: e.g. "%08lld" and "%9.6lf". For Miller 6,
// We must still accept these for backward compatibility.
if strings.HasSuffix(goFormatString, "d") {
return newMlrvalFormatterToInt(goFormatString), nil
return newFormatterToInt(goFormatString), nil
}
if strings.HasSuffix(goFormatString, "x") {
return newMlrvalFormatterToInt(goFormatString), nil
return newFormatterToInt(goFormatString), nil
}
if strings.HasSuffix(goFormatString, "f") {
return newMlrvalFormatterToFloat(goFormatString), nil
return newFormatterToFloat(goFormatString), nil
}
if strings.HasSuffix(goFormatString, "e") {
return newMlrvalFormatterToFloat(goFormatString), nil
return newFormatterToFloat(goFormatString), nil
}
if strings.HasSuffix(goFormatString, "g") {
return newMlrvalFormatterToFloat(goFormatString), nil
return newFormatterToFloat(goFormatString), nil
}
if strings.HasSuffix(goFormatString, "s") {
return newMlrvalFormatterToString(goFormatString), nil
return newFormatterToString(goFormatString), nil
}
// TODO:
// return nil, errors.New(fmt.Sprintf("unhandled format string \"%s\"", userLevelFormatString))
return newMlrvalFormatterToString(goFormatString), nil
return newFormatterToString(goFormatString), nil
}
//func regularizeFormat
// ----------------------------------------------------------------
type mlrvalFormatterToFloat struct {
type formatterToFloat struct {
goFormatString string
}
func newMlrvalFormatterToFloat(goFormatString string) IMlrvalFormatter {
return &mlrvalFormatterToFloat{
func newFormatterToFloat(goFormatString string) IFormatter {
return &formatterToFloat{
goFormatString: goFormatString,
}
}
func (formatter *mlrvalFormatterToFloat) Format(mlrval *Mlrval) *Mlrval {
floatValue, isFloat := mlrval.GetFloatValue()
func (formatter *formatterToFloat) Format(mv *Mlrval) *Mlrval {
floatValue, isFloat := mv.GetFloatValue()
if isFloat {
formatted := fmt.Sprintf(formatter.goFormatString, floatValue)
return MlrvalTryPointerFromFloatString(formatted)
return TryFromFloatString(formatted)
}
intValue, isInt := mlrval.GetIntValue()
intValue, isInt := mv.GetIntValue()
if isInt {
formatted := fmt.Sprintf(formatter.goFormatString, float64(intValue))
return MlrvalTryPointerFromFloatString(formatted)
return TryFromFloatString(formatted)
}
return mlrval
return mv
}
func (formatter *mlrvalFormatterToFloat) FormatFloat(floatValue float64) string {
func (formatter *formatterToFloat) FormatFloat(floatValue float64) string {
return fmt.Sprintf(formatter.goFormatString, floatValue)
}
// ----------------------------------------------------------------
type mlrvalFormatterToInt struct {
type formatterToInt struct {
goFormatString string
}
func newMlrvalFormatterToInt(goFormatString string) IMlrvalFormatter {
return &mlrvalFormatterToInt{
func newFormatterToInt(goFormatString string) IFormatter {
return &formatterToInt{
goFormatString: goFormatString,
}
}
func (formatter *mlrvalFormatterToInt) Format(mlrval *Mlrval) *Mlrval {
intValue, isInt := mlrval.GetIntValue()
func (formatter *formatterToInt) Format(mv *Mlrval) *Mlrval {
intValue, isInt := mv.GetIntValue()
if isInt {
formatted := fmt.Sprintf(formatter.goFormatString, intValue)
return MlrvalTryPointerFromIntString(formatted)
return TryFromIntString(formatted)
}
floatValue, isFloat := mlrval.GetFloatValue()
floatValue, isFloat := mv.GetFloatValue()
if isFloat {
formatted := fmt.Sprintf(formatter.goFormatString, int(floatValue))
return MlrvalTryPointerFromIntString(formatted)
return TryFromIntString(formatted)
}
return mlrval
return mv
}
func (formatter *mlrvalFormatterToInt) FormatFloat(floatValue float64) string {
func (formatter *formatterToInt) FormatFloat(floatValue float64) string {
return fmt.Sprintf(formatter.goFormatString, int(floatValue))
}
// ----------------------------------------------------------------
type mlrvalFormatterToString struct {
type formatterToString struct {
goFormatString string
}
func newMlrvalFormatterToString(goFormatString string) IMlrvalFormatter {
return &mlrvalFormatterToString{
func newFormatterToString(goFormatString string) IFormatter {
return &formatterToString{
goFormatString: goFormatString,
}
}
func (formatter *mlrvalFormatterToString) Format(mlrval *Mlrval) *Mlrval {
return MlrvalFromString(
func (formatter *formatterToString) Format(mv *Mlrval) *Mlrval {
return FromString(
fmt.Sprintf(
formatter.goFormatString,
mlrval.String(),
mv.String(),
),
)
}
func (formatter *mlrvalFormatterToString) FormatFloat(floatValue float64) string {
func (formatter *formatterToString) FormatFloat(floatValue float64) string {
return strconv.FormatFloat(floatValue, 'g', -1, 64)
}

View file

@ -1,25 +1,18 @@
// ================================================================
// Most Miller tests (thousands of them) are command-line-driven via
// mlr regtest. Here are some cases needing special focus.
// ================================================================
// Invoke as:
// * cd internal/pkg/types
// * go test
// Or:
// * cd go
// * go test github.com/johnkerl/miller/internal/pkg/types/...
package types
package mlrval
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestFormatterToString(t *testing.T) {
func TestFoo(t *testing.T) {
assert.Equal(t, true, true)
}
mv := MlrvalFromString("hello")
formatter := newMlrvalFormatterToString("%s")
func TestFormatterToString(t *testing.T) {
mv := FromString("hello")
formatter := newFormatterToString("%s")
fmv := formatter.Format(mv)
if !fmv.IsString() {
t.Fatal()
@ -28,8 +21,8 @@ func TestFormatterToString(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_NULL
formatter = newMlrvalFormatterToString("%s")
mv = NULL
formatter = newFormatterToString("%s")
fmv = formatter.Format(mv)
if !fmv.IsString() {
t.Fatal()
@ -38,8 +31,8 @@ func TestFormatterToString(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_TRUE
formatter = newMlrvalFormatterToString("%s")
mv = TRUE
formatter = newFormatterToString("%s")
fmv = formatter.Format(mv)
if !fmv.IsString() {
t.Fatal()
@ -48,8 +41,8 @@ func TestFormatterToString(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_FALSE
formatter = newMlrvalFormatterToString("%s")
mv = FALSE
formatter = newFormatterToString("%s")
fmv = formatter.Format(mv)
if !fmv.IsString() {
t.Fatal()
@ -58,8 +51,8 @@ func TestFormatterToString(t *testing.T) {
t.Fatal()
}
mv = MlrvalFromInt(10)
formatter = newMlrvalFormatterToString("%s")
mv = FromInt(10)
formatter = newFormatterToString("%s")
fmv = formatter.Format(mv)
if !fmv.IsString() {
t.Fatal()
@ -68,8 +61,8 @@ func TestFormatterToString(t *testing.T) {
t.Fatal()
}
mv = MlrvalFromString("hello")
formatter = newMlrvalFormatterToString("[[%s]]")
mv = FromString("hello")
formatter = newFormatterToString("[[%s]]")
fmv = formatter.Format(mv)
if !fmv.IsString() {
t.Fatal()
@ -81,9 +74,8 @@ func TestFormatterToString(t *testing.T) {
}
func TestFormatterToInt(t *testing.T) {
mv := MlrvalFromString("hello")
formatter := newMlrvalFormatterToInt("%d")
mv := FromString("hello")
formatter := newFormatterToInt("%d")
fmv := formatter.Format(mv)
if !fmv.IsString() {
t.Fatal()
@ -92,8 +84,8 @@ func TestFormatterToInt(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_NULL
formatter = newMlrvalFormatterToInt("%d")
mv = NULL
formatter = newFormatterToInt("%d")
fmv = formatter.Format(mv)
if !fmv.IsNull() {
t.Fatal()
@ -102,8 +94,8 @@ func TestFormatterToInt(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_TRUE
formatter = newMlrvalFormatterToInt("%d")
mv = TRUE
formatter = newFormatterToInt("%d")
fmv = formatter.Format(mv)
if !fmv.IsBool() {
t.Fatal()
@ -112,8 +104,8 @@ func TestFormatterToInt(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_FALSE
formatter = newMlrvalFormatterToInt("%d")
mv = FALSE
formatter = newFormatterToInt("%d")
fmv = formatter.Format(mv)
if !fmv.IsBool() {
t.Fatal()
@ -122,8 +114,8 @@ func TestFormatterToInt(t *testing.T) {
t.Fatal()
}
mv = MlrvalFromInt(10)
formatter = newMlrvalFormatterToInt("%d")
mv = FromInt(10)
formatter = newFormatterToInt("%d")
fmv = formatter.Format(mv)
if !fmv.IsInt() {
t.Fatal()
@ -132,8 +124,8 @@ func TestFormatterToInt(t *testing.T) {
t.Fatal()
}
mv = MlrvalFromInt(10)
formatter = newMlrvalFormatterToInt("[[0x%x]]")
mv = FromInt(10)
formatter = newFormatterToInt("[[0x%x]]")
fmv = formatter.Format(mv)
if !fmv.IsString() {
t.Fatal()
@ -142,8 +134,8 @@ func TestFormatterToInt(t *testing.T) {
t.Fatal()
}
mv = MlrvalFromFloat64(10.1)
formatter = newMlrvalFormatterToInt("%d")
mv = FromFloat(10.1)
formatter = newFormatterToInt("%d")
fmv = formatter.Format(mv)
if !fmv.IsInt() {
t.Fatal()
@ -156,8 +148,8 @@ func TestFormatterToInt(t *testing.T) {
func TestFormatterToFloat(t *testing.T) {
mv := MlrvalFromString("hello")
formatter := newMlrvalFormatterToFloat("%.4f")
mv := FromString("hello")
formatter := newFormatterToFloat("%.4f")
fmv := formatter.Format(mv)
if !fmv.IsString() {
t.Fatal()
@ -166,8 +158,8 @@ func TestFormatterToFloat(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_NULL
formatter = newMlrvalFormatterToFloat("%.4f")
mv = NULL
formatter = newFormatterToFloat("%.4f")
fmv = formatter.Format(mv)
if !fmv.IsNull() {
t.Fatal()
@ -176,8 +168,8 @@ func TestFormatterToFloat(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_TRUE
formatter = newMlrvalFormatterToFloat("%.4f")
mv = TRUE
formatter = newFormatterToFloat("%.4f")
fmv = formatter.Format(mv)
if !fmv.IsBool() {
t.Fatal()
@ -186,8 +178,8 @@ func TestFormatterToFloat(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_FALSE
formatter = newMlrvalFormatterToFloat("%.4f")
mv = FALSE
formatter = newFormatterToFloat("%.4f")
fmv = formatter.Format(mv)
if !fmv.IsBool() {
t.Fatal()
@ -196,8 +188,8 @@ func TestFormatterToFloat(t *testing.T) {
t.Fatal()
}
mv = MlrvalFromFloat64(10)
formatter = newMlrvalFormatterToFloat("%.4f")
mv = FromFloat(10)
formatter = newFormatterToFloat("%.4f")
fmv = formatter.Format(mv)
if !fmv.IsFloat() {
t.Fatal()
@ -206,8 +198,8 @@ func TestFormatterToFloat(t *testing.T) {
t.Fatal()
}
mv = MlrvalFromFloat64(10.1)
formatter = newMlrvalFormatterToFloat("%.4f")
mv = FromFloat(10.1)
formatter = newFormatterToFloat("%.4f")
fmv = formatter.Format(mv)
if !fmv.IsFloat() {
t.Fatal()
@ -219,8 +211,8 @@ func TestFormatterToFloat(t *testing.T) {
func TestFormatter(t *testing.T) {
mv := MlrvalFromString("hello")
formatter, err := GetMlrvalFormatter("%d")
mv := FromString("hello")
formatter, err := GetFormatter("%d")
if err != nil {
t.Fatal()
}
@ -232,8 +224,8 @@ func TestFormatter(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_NULL
formatter, err = GetMlrvalFormatter("%d")
mv = NULL
formatter, err = GetFormatter("%d")
if err != nil {
t.Fatal()
}
@ -245,8 +237,8 @@ func TestFormatter(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_TRUE
formatter, err = GetMlrvalFormatter("%d")
mv = TRUE
formatter, err = GetFormatter("%d")
if err != nil {
t.Fatal()
}
@ -258,8 +250,8 @@ func TestFormatter(t *testing.T) {
t.Fatal()
}
mv = MLRVAL_FALSE
formatter, err = GetMlrvalFormatter("%d")
mv = FALSE
formatter, err = GetFormatter("%d")
if err != nil {
t.Fatal()
}
@ -271,8 +263,8 @@ func TestFormatter(t *testing.T) {
t.Fatal()
}
mv = MlrvalFromFloat64(10.123)
formatter, err = GetMlrvalFormatter("%d")
mv = FromFloat(10.123)
formatter, err = GetFormatter("%d")
if err != nil {
t.Fatal()
}
@ -284,8 +276,8 @@ func TestFormatter(t *testing.T) {
t.Fatal()
}
mv = MlrvalFromFloat64(10.1)
formatter, err = GetMlrvalFormatter("%d")
mv = FromFloat(10.1)
formatter, err = GetFormatter("%d")
if err != nil {
t.Fatal()
}

View file

@ -0,0 +1,148 @@
package mlrval
import (
"fmt"
"os"
"github.com/johnkerl/miller/internal/pkg/lib"
)
// It's essential that we use mv.Type() not mv.mvtype, or use an Is...()
// predicate, or another Get...(), since types are JIT-computed on first access
// for most data-file values. See type.go for more information.
func (mv *Mlrval) GetTypeBit() int {
return 1 << mv.Type()
}
func (mv *Mlrval) GetStringValue() (stringValue string, isString bool) {
if mv.Type() == MT_STRING || mv.Type() == MT_VOID {
return mv.printrep, true
} else {
return "", false
}
}
func (mv *Mlrval) GetIntValue() (intValue int, isInt bool) {
if mv.Type() == MT_INT {
return mv.intval, true
} else {
return -999, false
}
}
func (mv *Mlrval) GetFloatValue() (floatValue float64, isFloat bool) {
if mv.Type() == MT_FLOAT {
return mv.floatval, true
} else {
return -777.0, false
}
}
func (mv *Mlrval) GetNumericToFloatValue() (floatValue float64, isFloat bool) {
if mv.Type() == MT_FLOAT {
return mv.floatval, true
} else if mv.Type() == MT_INT {
return float64(mv.intval), true
} else {
return -888.0, false
}
}
func (mv *Mlrval) GetNumericNegativeorDie() bool {
floatValue, ok := mv.GetNumericToFloatValue()
lib.InternalCodingErrorIf(!ok)
return floatValue < 0.0
}
func (mv *Mlrval) GetBoolValue() (boolValue bool, isBool bool) {
if mv.Type() == MT_BOOL {
return mv.boolval, true
} else {
return false, false
}
}
func (mv *Mlrval) GetArray() []Mlrval {
if mv.IsArray() {
return mv.arrayval
} else {
return nil
}
}
func (mv *Mlrval) GetMap() *Mlrmap {
if mv.IsMap() {
return mv.mapval
} else {
return nil
}
}
func (mv *Mlrval) GetFunction() interface{} {
if mv.Type() == MT_FUNC {
return mv.funcval
} else {
return nil
}
}
func (mv *Mlrval) GetTypeName() string {
return TYPE_NAMES[mv.Type()]
}
func GetTypeName(mvtype MVType) string {
return TYPE_NAMES[mvtype]
}
// These are for built-in functions operating within type-keyed
// disposition-vector/disposition-matrix context. They've already computed
// mv.Type() -- it's a fatal error if they haven't -- and they need the typed
// value.
func (mv *Mlrval) AcquireStringValue() string {
lib.InternalCodingErrorIf(mv.mvtype != MT_STRING && mv.mvtype != MT_VOID)
return mv.printrep
}
func (mv *Mlrval) AcquireIntValue() int {
lib.InternalCodingErrorIf(mv.mvtype != MT_INT)
return mv.intval
}
func (mv *Mlrval) AcquireFloatValue() float64 {
lib.InternalCodingErrorIf(mv.mvtype != MT_FLOAT)
return mv.floatval
}
func (mv *Mlrval) AcquireBoolValue() bool {
lib.InternalCodingErrorIf(mv.mvtype != MT_BOOL)
return mv.boolval
}
func (mv *Mlrval) AcquireArrayValue() []Mlrval {
lib.InternalCodingErrorIf(mv.mvtype != MT_ARRAY)
return mv.arrayval
}
func (mv *Mlrval) AcquireMapValue() *Mlrmap {
lib.InternalCodingErrorIf(mv.mvtype != MT_MAP)
return mv.mapval
}
func (mv *Mlrval) GetNumericToFloatValueOrDie() (floatValue float64) {
floatValue, ok := mv.GetNumericToFloatValue()
if !ok {
fmt.Fprintf(
os.Stderr,
"%s: couldn't parse \"%s\" as number.",
"mlr", mv.String(),
)
os.Exit(1)
}
return floatValue
}
func (mv *Mlrval) AssertNumeric() {
_ = mv.GetNumericToFloatValueOrDie()
}

View file

@ -0,0 +1,188 @@
// ================================================================
// Tests mlrval typed-value extractors
// ================================================================
package mlrval
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetString(t *testing.T) {
mv := FromInferredType("234")
stringval, ok := mv.GetStringValue()
assert.False(t, ok)
mv = FromDeferredType("234")
stringval, ok = mv.GetStringValue()
assert.False(t, ok)
mv = FromInferredType("234.5")
stringval, ok = mv.GetStringValue()
assert.False(t, ok)
mv = FromDeferredType("234.5")
stringval, ok = mv.GetStringValue()
assert.False(t, ok)
mv = FromInferredType("abc")
stringval, ok = mv.GetStringValue()
assert.Equal(t, "abc", stringval)
assert.True(t, ok)
mv = FromDeferredType("abc")
stringval, ok = mv.GetStringValue()
assert.Equal(t, "abc", stringval)
assert.True(t, ok)
mv = FromInferredType("")
stringval, ok = mv.GetStringValue()
assert.Equal(t, "", stringval)
assert.True(t, ok)
mv = FromDeferredType("")
stringval, ok = mv.GetStringValue()
assert.Equal(t, "", stringval)
assert.True(t, ok)
}
func TestGetIntValue(t *testing.T) {
mv := FromInferredType("123")
intval, ok := mv.GetIntValue()
assert.Equal(t, 123, intval)
assert.True(t, ok)
mv = FromDeferredType("123")
intval, ok = mv.GetIntValue()
assert.Equal(t, 123, intval)
assert.True(t, ok)
mv = FromInferredType("123.4")
intval, ok = mv.GetIntValue()
assert.False(t, ok)
mv = FromDeferredType("123.4")
intval, ok = mv.GetIntValue()
assert.False(t, ok)
mv = FromInferredType("abc")
intval, ok = mv.GetIntValue()
assert.False(t, ok)
mv = FromDeferredType("abc")
intval, ok = mv.GetIntValue()
assert.False(t, ok)
}
func TestGetFloatValue(t *testing.T) {
mv := FromInferredType("234")
floatval, ok := mv.GetFloatValue()
assert.False(t, ok)
mv = FromDeferredType("234")
floatval, ok = mv.GetFloatValue()
assert.False(t, ok)
mv = FromInferredType("234.5")
floatval, ok = mv.GetFloatValue()
assert.Equal(t, 234.5, floatval)
assert.True(t, ok)
mv = FromDeferredType("234.5")
floatval, ok = mv.GetFloatValue()
assert.Equal(t, 234.5, floatval)
assert.True(t, ok)
mv = FromInferredType("abc")
floatval, ok = mv.GetFloatValue()
assert.False(t, ok)
mv = FromDeferredType("abc")
floatval, ok = mv.GetFloatValue()
assert.False(t, ok)
}
func TestGetNumericToFloatValue(t *testing.T) {
mv := FromInferredType("234")
floatval, ok := mv.GetNumericToFloatValue()
assert.Equal(t, 234.0, floatval)
assert.True(t, ok)
mv = FromDeferredType("234")
floatval, ok = mv.GetNumericToFloatValue()
assert.Equal(t, 234.0, floatval)
assert.True(t, ok)
mv = FromInferredType("234.5")
floatval, ok = mv.GetNumericToFloatValue()
assert.Equal(t, 234.5, floatval)
assert.True(t, ok)
mv = FromDeferredType("234.5")
floatval, ok = mv.GetNumericToFloatValue()
assert.Equal(t, 234.5, floatval)
assert.True(t, ok)
mv = FromInferredType("abc")
floatval, ok = mv.GetNumericToFloatValue()
assert.False(t, ok)
mv = FromDeferredType("abc")
floatval, ok = mv.GetNumericToFloatValue()
assert.False(t, ok)
}
func TestGetBoolValue(t *testing.T) {
mv := FromInferredType("234")
boolval, ok := mv.GetBoolValue()
assert.False(t, ok)
mv = FromDeferredType("234")
boolval, ok = mv.GetBoolValue()
assert.False(t, ok)
mv = FromInferredType("abc")
boolval, ok = mv.GetBoolValue()
assert.False(t, ok)
mv = FromDeferredType("abc")
boolval, ok = mv.GetBoolValue()
assert.False(t, ok)
mv = FromInferredType("true")
boolval, ok = mv.GetBoolValue()
assert.True(t, boolval)
assert.True(t, ok)
mv = FromDeferredType("false")
boolval, ok = mv.GetBoolValue()
assert.False(t, ok, "from-data-file \"false\" should infer to string")
}
func TestGetTypeName(t *testing.T) {
mv := FromInferredType("234")
assert.Equal(t, "int", mv.GetTypeName())
mv = FromDeferredType("234")
assert.Equal(t, "int", mv.GetTypeName())
mv = FromInferredType("234.5")
assert.Equal(t, "float", mv.GetTypeName())
mv = FromDeferredType("234.5")
assert.Equal(t, "float", mv.GetTypeName())
mv = FromInferredType("abc")
assert.Equal(t, "string", mv.GetTypeName())
mv = FromDeferredType("abc")
assert.Equal(t, "string", mv.GetTypeName())
mv = FromInferredType("")
assert.Equal(t, "empty", mv.GetTypeName())
mv = FromDeferredType("")
assert.Equal(t, "empty", mv.GetTypeName())
}

View file

@ -0,0 +1,102 @@
package mlrval
import (
"regexp"
"strings"
"github.com/johnkerl/miller/internal/pkg/lib"
)
// TODO: no infer-bool from data files. Always false in this path.
// It's essential that we use mv.Type() not mv.mvtype since types are
// JIT-computed on first access for most data-file values. See type.go for more
// information.
func (mv *Mlrval) Type() MVType {
if mv.mvtype == MT_PENDING {
packageLevelInferrer(mv, mv.printrep, false)
}
return mv.mvtype
}
// Support for mlr -S, mlr -A, mlr -O.
type tInferrer func(mv *Mlrval, input string, inferBool bool) *Mlrval
var packageLevelInferrer tInferrer = inferNormally
func SetInferrerNoOctal() {
packageLevelInferrer = inferWithOctalSuppress
}
func SetInferrerIntAsFloat() {
packageLevelInferrer = inferWithIntAsFloat
}
func SetInferrerStringOnly() {
packageLevelInferrer = inferStringOnly
}
// When loading data files, don't scan these words into floats -- even though
// the Go library is willing to do so.
var downcasedFloatNamesToNotInfer = map[string]bool{
"inf": true,
"+inf": true,
"-inf": true,
"infinity": true,
"+infinity": true,
"-infinity": true,
"nan": true,
}
func inferNormally(mv *Mlrval, input string, inferBool bool) *Mlrval {
if input == "" {
return mv.SetFromVoid()
}
intval, iok := lib.TryIntFromString(input)
if iok {
return mv.SetFromPrevalidatedIntString(input, intval)
}
if downcasedFloatNamesToNotInfer[strings.ToLower(input)] == false {
floatval, fok := lib.TryFloatFromString(input)
if fok {
return mv.SetFromPrevalidatedFloatString(input, floatval)
}
}
if inferBool {
boolval, bok := lib.TryBoolFromBoolString(input)
if bok {
return mv.SetFromPrevalidatedBoolString(input, boolval)
}
}
return mv.SetFromString(input)
}
var octalDetector = regexp.MustCompile("^-?0[0-9]+")
func inferWithOctalSuppress(mv *Mlrval, input string, inferBool bool) *Mlrval {
inferNormally(mv, input, inferBool)
if mv.mvtype != MT_INT && mv.mvtype != MT_FLOAT {
return mv
}
if octalDetector.MatchString(mv.printrep) {
return mv.SetFromString(input)
} else {
return mv
}
}
func inferWithIntAsFloat(mv *Mlrval, input string, inferBool bool) *Mlrval {
inferNormally(mv, input, inferBool)
if mv.Type() == MT_INT {
mv.floatval = float64(mv.intval)
mv.mvtype = MT_FLOAT
}
return mv
}
func inferStringOnly(mv *Mlrval, input string, inferBool bool) *Mlrval {
return mv.SetFromString(input)
}

View file

@ -0,0 +1,135 @@
package mlrval
import (
"github.com/johnkerl/miller/internal/pkg/lib"
)
// It's essential that we use mv.Type() not mv.mvtype since types are
// JIT-computed on first access for most data-file values. See type.go for more
// information.
func (mv *Mlrval) IsLegit() bool {
return mv.Type() >= MT_VOID
}
// TODO: comment no JIT-infer here -- absent is non-inferrable and we needn't take the expense of JIT.
func (mv *Mlrval) IsErrorOrAbsent() bool {
t := mv.mvtype
return t == MT_ERROR || t == MT_ABSENT
}
func (mv *Mlrval) IsError() bool {
return mv.Type() == MT_ERROR
}
// TODO: comment no JIT-infer here -- absent is non-inferrable and we needn't take the expense of JIT.
func (mv *Mlrval) IsAbsent() bool {
return mv.mvtype == MT_ABSENT
}
// TODO: comment no JIT-infer here -- NULL is non-inferrable and we needn't take the expense of JIT.
// This is a literal in JSON files, or else explicitly set to NULL.
func (mv *Mlrval) IsNull() bool {
return mv.mvtype == MT_NULL
}
func (mv *Mlrval) IsVoid() bool {
if mv.mvtype == MT_VOID {
return true
}
if mv.mvtype == MT_PENDING && mv.printrep == "" {
lib.InternalCodingErrorIf(!mv.printrepValid)
return true
}
return false
}
func (mv *Mlrval) IsErrorOrVoid() bool {
return mv.IsError() || mv.IsVoid()
}
// * Error is non-empty
// * Absent is non-empty (shouldn't have been assigned in the first place; error should be surfaced)
// * Void is empty
// * Empty string is empty
// * Int/float/bool/array/map are all non-empty
func (mv *Mlrval) IsEmptyString() bool {
if mv.mvtype == MT_VOID {
return true
}
if mv.mvtype == MT_STRING && mv.printrep == "" {
return true
}
if mv.mvtype == MT_PENDING && mv.printrep == "" {
lib.InternalCodingErrorIf(!mv.printrepValid)
return true
}
return false
}
func (mv *Mlrval) IsString() bool {
return mv.Type() == MT_STRING
}
func (mv *Mlrval) IsStringOrVoid() bool {
t := mv.Type()
return t == MT_STRING || t == MT_VOID
}
func (mv *Mlrval) IsStringOrInt() bool {
t := mv.Type()
return t == MT_STRING || t == MT_VOID || t == MT_INT
}
func (mv *Mlrval) IsInt() bool {
return mv.Type() == MT_INT
}
func (mv *Mlrval) IsFloat() bool {
return mv.Type() == MT_FLOAT
}
func (mv *Mlrval) IsNumeric() bool {
t := mv.Type()
return t == MT_INT || t == MT_FLOAT
}
func (mv *Mlrval) IsIntZero() bool {
return mv.Type() == MT_INT && mv.intval == 0
}
func (mv *Mlrval) IsBool() bool {
return mv.Type() == MT_BOOL
}
func (mv *Mlrval) IsTrue() bool {
return mv.Type() == MT_BOOL && mv.boolval == true
}
func (mv *Mlrval) IsFalse() bool {
return mv.Type() == MT_BOOL && mv.boolval == false
}
func (mv *Mlrval) IsArray() bool {
// TODO: comment non-deferrable type -- don't force a (potentially
// expensive in bulk) JIT-infer of other types
// return mv.Type() == MT_ARRAY
return mv.mvtype == MT_ARRAY
}
func (mv *Mlrval) IsMap() bool {
// TODO: comment non-deferrable type -- don't force a (potentially
// expensive in bulk) JIT-infer of other types
// return mv.Type() == MT_ARRAY
return mv.mvtype == MT_MAP
}
func (mv *Mlrval) IsArrayOrMap() bool {
// TODO: comment why not
// In flatten we don't want to type-infer things that don't need to be jitted.
// Arrays & maps are never from deferred type.
// t := mv.Type()
t := mv.mvtype
return t == MT_ARRAY || t == MT_MAP
}
func (mv *Mlrval) IsFunction() bool {
return mv.mvtype == MT_FUNC
}

View file

@ -0,0 +1,149 @@
// ================================================================
// Tests mlrval constructors.
// ================================================================
package mlrval
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestIsLegit(t *testing.T) {
assert.False(t, ERROR.IsLegit())
assert.False(t, ABSENT.IsLegit())
assert.False(t, NULL.IsLegit())
assert.True(t, FromString("").IsLegit())
assert.True(t, FromString("abc").IsLegit())
assert.True(t, FromInt(123).IsLegit())
assert.True(t, FromFloat(123.4).IsLegit())
assert.True(t, FromBool(true).IsLegit())
assert.True(t, FromArray([]Mlrval{*FromInt(10)}).IsLegit())
assert.True(t, FromMap(NewMlrmap()).IsLegit())
}
func TestIsErrorOrAbsent(t *testing.T) {
assert.True(t, ERROR.IsErrorOrAbsent())
assert.True(t, ABSENT.IsErrorOrAbsent())
assert.False(t, NULL.IsErrorOrAbsent())
assert.False(t, FromString("").IsErrorOrAbsent())
}
func TestIsError(t *testing.T) {
assert.True(t, ERROR.IsError())
assert.False(t, ABSENT.IsError())
assert.False(t, NULL.IsError())
assert.False(t, FromString("").IsError())
}
func TestIsAbsent(t *testing.T) {
assert.False(t, ERROR.IsAbsent())
assert.True(t, ABSENT.IsAbsent())
assert.False(t, NULL.IsAbsent())
assert.False(t, FromString("").IsAbsent())
}
func TestIsNull(t *testing.T) {
assert.False(t, ERROR.IsNull())
assert.False(t, ABSENT.IsNull())
assert.True(t, NULL.IsNull())
assert.False(t, FromString("").IsNull())
}
func TestIsVoid(t *testing.T) {
assert.False(t, ERROR.IsVoid())
assert.False(t, ABSENT.IsVoid())
assert.False(t, NULL.IsVoid())
assert.True(t, FromString("").IsVoid())
assert.True(t, FromDeferredType("").IsVoid())
assert.True(t, FromInferredType("").IsVoid())
assert.False(t, FromDeferredType("abc").IsVoid())
assert.False(t, FromInferredType("abc").IsVoid())
}
func TestIsEmptyString(t *testing.T) {
assert.False(t, ERROR.IsEmptyString())
assert.False(t, ABSENT.IsEmptyString())
assert.False(t, NULL.IsEmptyString())
assert.True(t, FromString("").IsEmptyString())
assert.True(t, FromDeferredType("").IsEmptyString())
assert.True(t, FromInferredType("").IsEmptyString())
assert.False(t, FromDeferredType("abc").IsEmptyString())
assert.False(t, FromInferredType("abc").IsEmptyString())
}
func TestIsString(t *testing.T) {
assert.False(t, ERROR.IsString())
assert.False(t, ABSENT.IsString())
assert.False(t, NULL.IsString())
assert.False(t, FromString("").IsString())
assert.False(t, FromDeferredType("").IsString())
assert.False(t, FromInferredType("").IsString())
assert.True(t, FromDeferredType("abc").IsString())
assert.True(t, FromInferredType("abc").IsString())
}
func TestIsStringOrVoid(t *testing.T) {
assert.False(t, ERROR.IsStringOrVoid())
assert.False(t, ABSENT.IsStringOrVoid())
assert.False(t, NULL.IsStringOrVoid())
assert.True(t, FromString("").IsStringOrVoid())
assert.True(t, FromDeferredType("").IsStringOrVoid())
assert.True(t, FromInferredType("").IsStringOrVoid())
assert.True(t, FromDeferredType("abc").IsStringOrVoid())
assert.True(t, FromInferredType("abc").IsStringOrVoid())
}
func TestIsInt(t *testing.T) {
assert.True(t, FromDeferredType("123").IsInt())
assert.True(t, FromInferredType("123").IsInt())
assert.False(t, FromDeferredType("123.4").IsInt())
assert.False(t, FromInferredType("123.4").IsInt())
assert.False(t, FromDeferredType("abc").IsInt())
assert.False(t, FromInferredType("abc").IsInt())
}
func TestIsIntZero(t *testing.T) {
assert.True(t, FromDeferredType("0").IsIntZero())
assert.True(t, FromInferredType("0").IsIntZero())
assert.True(t, FromDeferredType("-0").IsIntZero())
assert.True(t, FromInferredType("-0").IsIntZero())
assert.False(t, FromDeferredType("123").IsIntZero())
assert.False(t, FromInferredType("123").IsIntZero())
assert.False(t, FromDeferredType("abc").IsIntZero())
assert.False(t, FromInferredType("abc").IsIntZero())
}
func TestIsFloat(t *testing.T) {
assert.False(t, FromDeferredType("123").IsFloat())
assert.False(t, FromInferredType("123").IsFloat())
assert.True(t, FromDeferredType("123.4").IsFloat())
assert.True(t, FromInferredType("123.4").IsFloat())
assert.False(t, FromDeferredType("abc").IsFloat())
assert.False(t, FromInferredType("abc").IsFloat())
}
func TestIsNumeric(t *testing.T) {
assert.True(t, FromDeferredType("123").IsNumeric())
assert.True(t, FromInferredType("123").IsNumeric())
assert.True(t, FromDeferredType("123.4").IsNumeric())
assert.True(t, FromInferredType("123.4").IsNumeric())
assert.False(t, FromDeferredType("abc").IsNumeric())
assert.False(t, FromInferredType("abc").IsNumeric())
}
func TestIsBool(t *testing.T) {
assert.False(t, FromDeferredType("123").IsBool())
assert.False(t, FromInferredType("123").IsBool())
assert.False(t, FromDeferredType("123.4").IsBool())
assert.False(t, FromInferredType("123.4").IsBool())
assert.False(t, FromDeferredType("abc").IsBool())
assert.False(t, FromInferredType("abc").IsBool())
assert.False(t, FromDeferredType("true").IsBool(), "from-data-file \"true\" should infer to string")
assert.True(t, FromDeferredType("true").IsString(), "from-data-file \"true\" should infer to string")
assert.True(t, FromInferredType("true").IsBool())
assert.False(t, FromDeferredType("false").IsBool(), "from-data-file \"false\" should infer to string")
assert.True(t, FromDeferredType("false").IsString(), "from-data-file \"false\" should infer to string")
assert.True(t, FromInferredType("false").IsBool())
}

View file

@ -6,7 +6,7 @@
// Please see also https://golang.org/pkg/encoding/json/
// ================================================================
package types
package mlrval
import (
"bytes"
@ -18,7 +18,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/lib"
)
const MLRVAL_JSON_INDENT_STRING string = " "
const JSON_INDENT_STRING string = " "
type TJSONFormatting int
@ -101,16 +101,16 @@ const (
// ----------------------------------------------------------------
func (mv *Mlrval) UnmarshalJSON(inputBytes []byte) error {
*mv = MlrvalFromPending()
*mv = *FromPending()
decoder := json.NewDecoder(bytes.NewReader(inputBytes))
mlrval, eof, err := MlrvalDecodeFromJSON(decoder)
pmv, eof, err := MlrvalDecodeFromJSON(decoder)
if eof {
return errors.New("Miller JSON parser: unexpected premature EOF.")
}
if err != nil {
return err
}
*mv = *mlrval
*mv = *pmv
return nil
}
@ -135,23 +135,23 @@ func MlrvalDecodeFromJSON(decoder *json.Decoder) (
delimiter, isDelim := startToken.(json.Delim)
if !isDelim {
if startToken == nil {
return MLRVAL_NULL, false, nil
return NULL, false, nil
}
sval, ok := startToken.(string)
if ok {
mlrval := MlrvalFromString(sval)
mlrval := FromString(sval)
return mlrval, false, nil
}
bval, ok := startToken.(bool)
if ok {
return MlrvalFromBool(bval), false, nil
return FromBool(bval), false, nil
}
nval, ok := startToken.(json.Number)
if ok {
mlrval := MlrvalFromInferredType(nval.String())
mlrval := FromInferredType(nval.String())
return mlrval, false, nil
}
@ -178,9 +178,9 @@ func MlrvalDecodeFromJSON(decoder *json.Decoder) (
)
}
mlrval := MlrvalFromPending()
mv := FromPending()
if isArray {
mlrval = MlrvalEmptyArray()
mv = FromEmptyArray()
for decoder.More() {
element, eof, err := MlrvalDecodeFromJSON(decoder)
@ -191,11 +191,11 @@ func MlrvalDecodeFromJSON(decoder *json.Decoder) (
if err != nil {
return nil, false, err
}
mlrval.ArrayAppend(element)
mv.ArrayAppend(element)
}
} else {
mlrval = *MlrvalFromEmptyMap()
mv = FromEmptyMap()
for decoder.More() {
key, eof, err := MlrvalDecodeFromJSON(decoder)
@ -223,7 +223,7 @@ func MlrvalDecodeFromJSON(decoder *json.Decoder) (
}
// xxx check here string-valued key
mlrval.MapPut(key, value)
mv.MapPut(key, value)
}
}
@ -252,7 +252,7 @@ func MlrvalDecodeFromJSON(decoder *json.Decoder) (
return nil, false, imbalanceError
}
return &mlrval, false, nil
return mv, false, nil
}
return nil, false, errors.New("unimplemented")
@ -271,7 +271,7 @@ func (mv *Mlrval) marshalJSONAux(
elementNestingDepth int,
outputIsStdout bool,
) (string, error) {
switch mv.mvtype {
switch mv.Type() {
case MT_PENDING:
return mv.marshalJSONPending(outputIsStdout)
break
@ -495,7 +495,7 @@ func (mv *Mlrval) marshalJSONArrayMultipleLines(
return "", err
}
for i := 0; i < elementNestingDepth; i++ {
buffer.WriteString(MLRVAL_JSON_INDENT_STRING)
buffer.WriteString(JSON_INDENT_STRING)
}
buffer.WriteString(elementString)
if i < n-1 {
@ -507,7 +507,7 @@ func (mv *Mlrval) marshalJSONArrayMultipleLines(
// Write empty array as '[]'
if n > 0 {
for i := 0; i < elementNestingDepth-1; i++ {
buffer.WriteString(MLRVAL_JSON_INDENT_STRING)
buffer.WriteString(JSON_INDENT_STRING)
}
}

View file

@ -0,0 +1,234 @@
// ================================================================
// Constructors
// ================================================================
package mlrval
import (
//"errors"
"github.com/johnkerl/miller/internal/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,
}
}
// 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 inferBool arg
packageLevelInferrer(mv, mv.printrep, true)
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 int) *Mlrval {
return &Mlrval{
mvtype: MT_INT,
printrepValid: false,
intval: 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 int) *Mlrval {
mv.printrep = input
mv.printrepValid = true
mv.intval = intval
mv.mvtype = MT_INT
return mv
}
// TODO: comment
func FromPrevalidatedIntString(input string, intval int) *Mlrval {
mv := &Mlrval{}
mv.SetFromPrevalidatedIntString(input, intval)
return mv
}
func FromFloat(input float64) *Mlrval {
return &Mlrval{
mvtype: MT_FLOAT,
printrepValid: false,
floatval: 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.floatval = 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 == true {
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.boolval = 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/internal/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,
funcval: funcval,
}
}
func FromArray(arrayval []Mlrval) *Mlrval {
return &Mlrval{
mvtype: MT_ARRAY,
printrep: "(bug-if-you-see-this:case-4)", // INVALID_PRINTREP,
printrepValid: false,
arrayval: CopyMlrvalArray(arrayval),
}
}
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,
mapval: mapval.Copy(),
}
}
func FromEmptyMap() *Mlrval {
return FromMap(NewMlrmap())
}

View file

@ -0,0 +1,142 @@
// ================================================================
// Tests mlrval constructors.
// ================================================================
package mlrval
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestFromDeferredType(t *testing.T) {
mv := FromDeferredType("123")
assert.Equal(t, MVType(MT_PENDING), MVType(mv.mvtype))
assert.Equal(t, "123", mv.printrep)
assert.True(t, mv.printrepValid)
mv = FromDeferredType("true")
assert.Equal(t, MVType(MT_PENDING), MVType(mv.mvtype))
assert.Equal(t, "true", mv.printrep)
assert.True(t, mv.printrepValid)
mv = FromDeferredType("abc")
assert.Equal(t, MVType(MT_PENDING), MVType(mv.mvtype))
assert.Equal(t, "abc", mv.printrep)
assert.True(t, mv.printrepValid)
mv = FromDeferredType("")
assert.Equal(t, MVType(MT_PENDING), MVType(mv.mvtype))
assert.Equal(t, "", mv.printrep)
assert.True(t, mv.printrepValid)
}
func TestFromInferredType(t *testing.T) {
mv := FromInferredType("123")
assert.Equal(t, MVType(MT_INT), MVType(mv.mvtype))
assert.Equal(t, "123", mv.printrep)
assert.True(t, mv.printrepValid)
assert.Equal(t, mv.intval, 123)
mv = FromInferredType("true")
assert.Equal(t, MVType(MT_BOOL), MVType(mv.mvtype))
assert.Equal(t, "true", mv.printrep)
assert.True(t, mv.printrepValid)
assert.Equal(t, mv.boolval, true)
mv = FromInferredType("abc")
assert.Equal(t, MVType(MT_STRING), MVType(mv.mvtype))
assert.Equal(t, "abc", mv.printrep)
assert.True(t, mv.printrepValid)
mv = FromInferredType("")
assert.Equal(t, MVType(MT_VOID), MVType(mv.mvtype))
assert.Equal(t, "", mv.printrep)
assert.True(t, mv.printrepValid)
}
func TestFromString(t *testing.T) {
mv := FromString("123")
assert.Equal(t, MVType(MT_STRING), MVType(mv.mvtype))
assert.Equal(t, "123", mv.printrep)
assert.True(t, mv.printrepValid)
mv = FromString("")
assert.Equal(t, MVType(MT_VOID), MVType(mv.mvtype))
assert.Equal(t, "", mv.printrep)
assert.True(t, mv.printrepValid)
}
func TestFromInt(t *testing.T) {
mv := FromInt(123)
assert.Equal(t, MVType(MT_INT), MVType(mv.mvtype))
assert.False(t, mv.printrepValid, "printrep should not be computed yet")
}
func TestTryFromIntString(t *testing.T) {
mv := TryFromIntString("123")
assert.Equal(t, MVType(MT_INT), MVType(mv.mvtype))
assert.True(t, mv.printrepValid, "printrep should be computed")
mv = TryFromIntString("[123]")
assert.Equal(t, MVType(MT_STRING), MVType(mv.mvtype))
assert.True(t, mv.printrepValid, "printrep should be computed")
}
func TestFromFloat(t *testing.T) {
mv := FromFloat(123.4)
assert.Equal(t, MVType(MT_FLOAT), MVType(mv.mvtype))
assert.False(t, mv.printrepValid, "printrep should not be computed yet")
}
func TestTryFromFloatString(t *testing.T) {
mv := TryFromFloatString("123.4")
assert.Equal(t, MVType(MT_FLOAT), MVType(mv.mvtype))
assert.True(t, mv.printrepValid, "printrep should be computed")
mv = TryFromIntString("[123.4]")
assert.Equal(t, MVType(MT_STRING), MVType(mv.mvtype))
assert.True(t, mv.printrepValid, "printrep should be computed")
}
func TestFromBool(t *testing.T) {
mv := FromBool(true)
assert.Equal(t, MVType(MT_BOOL), MVType(mv.mvtype))
assert.True(t, mv.printrepValid)
mv = FromBool(false)
assert.Equal(t, MVType(MT_BOOL), MVType(mv.mvtype))
assert.True(t, mv.printrepValid)
}
func TestFromBoolString(t *testing.T) {
mv := FromBoolString("true")
assert.Equal(t, MVType(MT_BOOL), MVType(mv.mvtype))
assert.True(t, mv.printrepValid)
mv = FromBoolString("false")
assert.Equal(t, MVType(MT_BOOL), MVType(mv.mvtype))
assert.True(t, mv.printrepValid)
}
func TestFromFunction(t *testing.T) {
mv := FromFunction("test data", "f001")
assert.Equal(t, MVType(MT_FUNC), MVType(mv.mvtype))
assert.True(t, mv.printrepValid)
assert.Equal(t, "test data", mv.funcval.(string))
}
func TestFromArray(t *testing.T) {
mv := FromArray([]Mlrval{*FromInt(10)})
assert.Equal(t, MVType(MT_ARRAY), MVType(mv.mvtype))
assert.True(t, mv.printrepValid)
assert.Equal(t, 1, len(mv.arrayval))
}
func TestFromMap(t *testing.T) {
mv := FromMap(NewMlrmap())
assert.Equal(t, MVType(MT_MAP), MVType(mv.mvtype))
assert.True(t, mv.printrepValid)
assert.True(t, mv.mapval.IsEmpty())
}

View file

@ -1,4 +1,4 @@
package types
package mlrval
import (
"fmt"
@ -6,52 +6,60 @@ import (
"strconv"
)
// Empty string means use default format.
// Set from the CLI parser using mlr --ofmt.
var mlrvalFloatOutputFormatter IMlrvalFormatter = nil
func SetMlrvalFloatOutputFormat(formatString string) error {
formatter, err := GetMlrvalFormatter(formatString)
if err != nil {
return err
// Must have non-pointer receiver in order to implement the fmt.Stringer
// interface to make this printable via fmt.Println et al.
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.floatval)
} else {
mv.setPrintRep()
return mv.printrep
}
mlrvalFloatOutputFormatter = formatter
return nil
}
// See mlrval.go for more about JIT-formatting of string backings
func (mv *Mlrval) setPrintRep() {
if !mv.printrepValid {
// xxx do it -- disposition vector
// xxx temp temp temp temp temp
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)" // xxx constdef at top of file
mv.printrep = "(bug-if-you-see-this:case=3)" // xxx constdef at top of file
break
case MT_ERROR:
mv.printrep = "(error)" // xxx constdef at top of file
break
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)" // xxx constdef at top of file
mv.printrep = "(bug-if-you-see-this:case=4)" // xxx constdef at top of file
break
case MT_VOID:
mv.printrep = "" // xxx constdef at top of file
break
case MT_STRING:
// panic i suppose
break
case MT_INT:
mv.printrep = strconv.Itoa(mv.intval)
break
case MT_FLOAT:
mv.printrep = strconv.FormatFloat(mv.floatval, 'f', -1, 64)
break
case MT_BOOL:
if mv.boolval == true {
mv.printrep = "true"
@ -59,9 +67,8 @@ func (mv *Mlrval) setPrintRep() {
mv.printrep = "false"
}
break
// TODO: handling indentation
case MT_ARRAY:
case MT_ARRAY:
bytes, err := mv.MarshalJSON(JSON_MULTILINE, false)
// maybe just InternalCodingErrorIf(err != nil)
if err != nil {
@ -71,8 +78,8 @@ func (mv *Mlrval) setPrintRep() {
mv.printrep = string(bytes)
break
case MT_MAP:
case MT_MAP:
bytes, err := mv.MarshalJSON(JSON_MULTILINE, false)
// maybe just InternalCodingErrorIf(err != nil)
if err != nil {
@ -86,15 +93,3 @@ func (mv *Mlrval) setPrintRep() {
mv.printrepValid = true
}
}
// Must have non-pointer receiver in order to implement the fmt.Stringer
// interface to make this printable via fmt.Println et al.
func (mv Mlrval) String() string {
if mv.mvtype == MT_FLOAT && mlrvalFloatOutputFormatter != nil {
// Use the format string from global --ofmt, if supplied
return mlrvalFloatOutputFormatter.FormatFloat(mv.floatval)
} else {
mv.setPrintRep()
return mv.printrep
}
}

View file

@ -0,0 +1,18 @@
package mlrval
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestString(t *testing.T) {
assert.Equal(t, "234", FromInferredType("234").String())
assert.Equal(t, "234", FromDeferredType("234").String())
assert.Equal(t, "234.5", FromInferredType("234.5").String())
assert.Equal(t, "234.5", FromDeferredType("234.5").String())
assert.Equal(t, "abc", FromInferredType("abc").String())
assert.Equal(t, "abc", FromDeferredType("abc").String())
assert.Equal(t, "", FromInferredType("").String())
assert.Equal(t, "", FromDeferredType("").String())
}

View file

@ -1,5 +1,5 @@
// ================================================================
// The `types.Mlrval` structure includes **string, int, float, boolean, void,
// The `Mlrval` structure includes **string, int, float, boolean, void,
// absent, and error** types (not unlike PHP's `zval`) as well as
// type-conversion logic for various operators.
//
@ -8,7 +8,50 @@
// that is a bug. It would be great to be able to somehow lint for this.
// ================================================================
package types
// TODO:
// * why here carefully fenced
// * why interface for recursive/external items
// * why optimizing:
// o def string-to-type, e.g. 17-column-wide, million-row CSV file,
// '$z = $x + $y' kind of thing -- don't need to type-infer
// column $a "1234" as int only to write it back non-modified
// o defer type-to-string, e.g. '$z = a*b + c*d' w/ a,b,c,d ints,
// string-rep not needed -- defer string-formatting until write-out.
// * Careful fencing: want things to "just work" for as much of the
// code as possible.
// o Hide x.mvtype as x.Type() and that function can JIT-infer printrep
// "1234" and mvtype MT_PENDING to mvtype MT_INT and intval 1234.
// o Similarly MT_INT, intval 1235, printrepValid = false, only
// on to-string do printrep = "1235" and printrepValid=true.
// * For all but JSON: everything is string/int/float/bool. Any
// array-valued/map-valued are JSON-encoded _as strings_.
// * For JSON: no defer; everything is explicitly typed as part of
// the decode.
// TODO: MERGE
// An int/float always starts from a string -- be it from record data from
// a file, or a literal within a DSL expression. The printrep is exactly
// that string, however the user formatted it, and the intval/floatval is
// computed from that -- and in sync with it -- at construction time.
//
// When a mlrval is computed from one or more others -- e.g. '$z = $x + 4'
// -- the printrep is not updated. That would be wasted CPU, since the
// string representation is not needed until when/if the value is printed
// as output. For computation methods the printrep is neglected and the
// printrepValid is set to false.
//
// In the String() method the printrep is computed from the intval/floatval
// and printrepValid is set back to true.
//
// Note that for MT_STRING, the printrep is always valid since it is the
// only payload for the mlrval.
//
// Thus we (a) keep user-specific input-formatting when possible, for the
// principle of least surprise; (b) avoid reformatting strings during
// intermediate arithmetic expressions; (c) resync arithmetic results to
// string formatting on a just-in-time basis when output is printed.
package mlrval
type Mlrval struct {
@ -16,46 +59,30 @@ type Mlrval struct {
// I would call this "type" not "mvtype" but "type" is a keyword in Go.
mvtype MVType
// An int/float always starts from a string -- be it from record data from
// a file, or a literal within a DSL expression. The printrep is exactly
// that string, however the user formatted it, and the intval/floatval is
// computed from that -- and in sync with it -- at construction time.
//
// When a mlrval is computed from one or more others -- e.g. '$z = $x + 4'
// -- the printrep is not updated. That would be wasted CPU, since the
// string representation is not needed until when/if the value is printed
// as output. For computation methods the printrep is neglected and the
// printrepValid is set to false.
//
// In the String() method the printrep is computed from the intval/floatval
// and printrepValid is set back to true.
//
// Note that for MT_STRING, the printrep is always valid since it is the
// only payload for the mlrval.
//
// Thus we (a) keep user-specific input-formatting when possible, for the
// principle of least surprise; (b) avoid reformatting strings during
// intermediate arithmetic expressions; (c) resync arithmetic results to
// string formatting on a just-in-time basis when output is printed.
printrep string
printrepValid bool
intval int
floatval float64
boolval bool
arrayval []Mlrval
mapval *Mlrmap
// These are first-class-function literals. Stored here as interface{} to
// avoid what would otherwise be a package-dependency cycle with the
// github.com/johnkerl/miller/internal/pkg/dsl/cst package.
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)"
// Enumeration for mlrval types
//
// There are two kinds of null: ABSENT (key not present in a record) and VOID
// (key present with empty value). Note void is an acceptable string (empty
// string) but not an acceptable number. (In Javascript, similarly, there are
// undefined and null, respectively.)
// There are three kinds of null: ABSENT (key not present in a record) and VOID
// (key present with empty value); thirdly NULL for JSON null. Note void is an
// acceptable string (empty string) but not an acceptable number. (In
// JavaScript, similarly, there are undefined and null, respectively --
// Miller's absent is more like JavaScript's undefined.)
type MVType int
@ -63,7 +90,7 @@ type MVType int
// matrices. If they are changed, it will break the disposition matrices, or
// they will all need manual re-indexing.
const (
// Type not yet determined, during JSON decode.
// Type not yet determined: during JSON decode or TODO comment.
MT_PENDING MVType = -1
// E.g. error encountered in one eval & it propagates up the AST at
@ -121,7 +148,6 @@ var TYPE_NAMES = [MT_DIM]string{
"funct",
}
// ----------------------------------------------------------------
// For typed assignments in the DSL
// TODO: comment more re typedecls
@ -166,7 +192,3 @@ func TypeNameToMask(typeName string) (mask int, present bool) {
return 0, false
}
}
func (mv *Mlrval) GetTypeBit() int {
return 1 << mv.mvtype
}

View file

@ -3,7 +3,7 @@ package output
import (
"bufio"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// IRecordWriter is the abstract interface for all record-writers. They are
@ -17,7 +17,7 @@ import (
// format.
type IRecordWriter interface {
Write(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
)

View file

@ -8,7 +8,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/colorizer"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
type RecordWriterCSV struct {
@ -37,7 +37,7 @@ func NewRecordWriterCSV(writerOptions *cli.TWriterOptions) (*RecordWriterCSV, er
}
func (writer *RecordWriterCSV) Write(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
) {

View file

@ -6,7 +6,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/colorizer"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
type RecordWriterCSVLite struct {
@ -26,7 +26,7 @@ func NewRecordWriterCSVLite(writerOptions *cli.TWriterOptions) (*RecordWriterCSV
}
func (writer *RecordWriterCSVLite) Write(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
) {

View file

@ -5,7 +5,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/colorizer"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
type RecordWriterDKVP struct {
@ -19,7 +19,7 @@ func NewRecordWriterDKVP(writerOptions *cli.TWriterOptions) (*RecordWriterDKVP,
}
func (writer *RecordWriterDKVP) Write(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
) {

View file

@ -6,14 +6,14 @@ import (
"os"
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// ----------------------------------------------------------------
type RecordWriterJSON struct {
// Parameters:
writerOptions *cli.TWriterOptions
jsonFormatting types.TJSONFormatting
jsonFormatting mlrval.TJSONFormatting
// State:
onFirst bool
@ -21,9 +21,9 @@ type RecordWriterJSON struct {
// ----------------------------------------------------------------
func NewRecordWriterJSON(writerOptions *cli.TWriterOptions) (*RecordWriterJSON, error) {
var jsonFormatting types.TJSONFormatting = types.JSON_SINGLE_LINE
var jsonFormatting mlrval.TJSONFormatting = mlrval.JSON_SINGLE_LINE
if writerOptions.JSONOutputMultiline {
jsonFormatting = types.JSON_MULTILINE
jsonFormatting = mlrval.JSON_MULTILINE
}
return &RecordWriterJSON{
writerOptions: writerOptions,
@ -34,7 +34,7 @@ func NewRecordWriterJSON(writerOptions *cli.TWriterOptions) (*RecordWriterJSON,
// ----------------------------------------------------------------
func (writer *RecordWriterJSON) Write(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
) {
@ -47,7 +47,7 @@ func (writer *RecordWriterJSON) Write(
// ----------------------------------------------------------------
func (writer *RecordWriterJSON) writeWithListWrap(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
) {
@ -82,7 +82,7 @@ func (writer *RecordWriterJSON) writeWithListWrap(
// ----------------------------------------------------------------
func (writer *RecordWriterJSON) writeWithoutListWrap(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
) {

View file

@ -6,7 +6,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/colorizer"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
type RecordWriterMarkdown struct {
@ -28,7 +28,7 @@ func NewRecordWriterMarkdown(writerOptions *cli.TWriterOptions) (*RecordWriterMa
// ----------------------------------------------------------------
func (writer *RecordWriterMarkdown) Write(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
) {

View file

@ -4,7 +4,7 @@ import (
"bufio"
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
type RecordWriterNIDX struct {
@ -20,7 +20,7 @@ func NewRecordWriterNIDX(writerOptions *cli.TWriterOptions) (*RecordWriterNIDX,
}
func (writer *RecordWriterNIDX) Write(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
) {

View file

@ -9,7 +9,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/colorizer"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
type RecordWriterPPRINT struct {
@ -34,7 +34,7 @@ func NewRecordWriterPPRINT(writerOptions *cli.TWriterOptions) (*RecordWriterPPRI
// ----------------------------------------------------------------
func (writer *RecordWriterPPRINT) Write(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
) {
@ -97,7 +97,7 @@ func (writer *RecordWriterPPRINT) writeHeterogenousList(
var maxNR int = 0
for e := records.Front(); e != nil; e = e.Next() {
outrec := e.Value.(*types.Mlrmap)
outrec := e.Value.(*mlrval.Mlrmap)
nr := outrec.FieldCount
if maxNR < nr {
maxNR = nr
@ -152,7 +152,7 @@ func (writer *RecordWriterPPRINT) writeHeterogenousListNonBarred(
onFirst := true
for e := records.Front(); e != nil; e = e.Next() {
outrec := e.Value.(*types.Mlrmap)
outrec := e.Value.(*mlrval.Mlrmap)
// Print header line
if onFirst && !writer.writerOptions.HeaderlessCSVOutput {
@ -254,7 +254,7 @@ func (writer *RecordWriterPPRINT) writeHeterogenousListBarred(
onFirst := true
for e := records.Front(); e != nil; e = e.Next() {
outrec := e.Value.(*types.Mlrmap)
outrec := e.Value.(*mlrval.Mlrmap)
// Print header line
if onFirst && !writer.writerOptions.HeaderlessCSVOutput {

View file

@ -7,7 +7,7 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/colorizer"
"github.com/johnkerl/miller/internal/pkg/types"
"github.com/johnkerl/miller/internal/pkg/mlrval"
)
// ----------------------------------------------------------------
@ -42,7 +42,7 @@ func NewRecordWriterXTAB(writerOptions *cli.TWriterOptions) (*RecordWriterXTAB,
}
func (writer *RecordWriterXTAB) Write(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
) {
@ -67,7 +67,7 @@ func (writer *RecordWriterXTAB) Write(
}
func (writer *RecordWriterXTAB) writeWithLeftAlignedValues(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
maxKeyLength int,
@ -100,7 +100,7 @@ func (writer *RecordWriterXTAB) writeWithLeftAlignedValues(
}
func (writer *RecordWriterXTAB) writeWithRightAlignedValues(
outrec *types.Mlrmap,
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
maxKeyLength int,

View file

@ -31,6 +31,7 @@ import (
"fmt"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -114,7 +115,7 @@ func (stack *Stack) PopStackFrame() {
// Returns nil on no-such
func (stack *Stack) Get(
stackVariable *StackVariable,
) *types.Mlrval {
) *mlrval.Mlrval {
return stack.head.get(stackVariable)
}
@ -124,7 +125,7 @@ func (stack *Stack) Get(
func (stack *Stack) DefineTypedAtScope(
stackVariable *StackVariable,
typeName string,
mlrval *types.Mlrval,
mlrval *mlrval.Mlrval,
) error {
return stack.head.defineTypedAtScope(stackVariable, typeName, mlrval)
}
@ -136,7 +137,7 @@ func (stack *Stack) DefineTypedAtScope(
// E.g. 'for (i = 0; i < 10; i += 1)' uses Set.
func (stack *Stack) SetAtScope(
stackVariable *StackVariable,
mlrval *types.Mlrval,
mlrval *mlrval.Mlrval,
) error {
return stack.head.setAtScope(stackVariable, mlrval)
}
@ -150,7 +151,7 @@ func (stack *Stack) SetAtScope(
// assignment is OK.
func (stack *Stack) Set(
stackVariable *StackVariable,
mlrval *types.Mlrval,
mlrval *mlrval.Mlrval,
) error {
return stack.head.set(stackVariable, mlrval)
}
@ -158,8 +159,8 @@ func (stack *Stack) Set(
// E.g. 'x[1] = 2' where the variable x may or may not have been already set.
func (stack *Stack) SetIndexed(
stackVariable *StackVariable,
indices []*types.Mlrval,
mlrval *types.Mlrval,
indices []*mlrval.Mlrval,
mlrval *mlrval.Mlrval,
) error {
return stack.head.setIndexed(stackVariable, indices, mlrval)
}
@ -174,7 +175,7 @@ func (stack *Stack) Unset(
// E.g. 'unset x[1]'
func (stack *Stack) UnsetIndexed(
stackVariable *StackVariable,
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
) {
stack.head.unsetIndexed(stackVariable, indices)
}
@ -225,7 +226,7 @@ func (frameset *StackFrameSet) dump() {
// Returns nil on no-such
func (frameset *StackFrameSet) get(
stackVariable *StackVariable,
) *types.Mlrval {
) *mlrval.Mlrval {
// Scope-walk
numStackFrames := len(frameset.stackFrames)
for offset := numStackFrames - 1; offset >= 0; offset-- {
@ -242,7 +243,7 @@ func (frameset *StackFrameSet) get(
func (frameset *StackFrameSet) defineTypedAtScope(
stackVariable *StackVariable,
typeName string,
mlrval *types.Mlrval,
mlrval *mlrval.Mlrval,
) error {
offset := len(frameset.stackFrames) - 1
// TODO: comment
@ -254,7 +255,7 @@ func (frameset *StackFrameSet) defineTypedAtScope(
// See Stack.SetAtScope comments above
func (frameset *StackFrameSet) setAtScope(
stackVariable *StackVariable,
mlrval *types.Mlrval,
mlrval *mlrval.Mlrval,
) error {
offset := len(frameset.stackFrames) - 1
return frameset.stackFrames[offset].set(stackVariable, mlrval)
@ -263,7 +264,7 @@ func (frameset *StackFrameSet) setAtScope(
// See Stack.Set comments above
func (frameset *StackFrameSet) set(
stackVariable *StackVariable,
mlrval *types.Mlrval,
mlrval *mlrval.Mlrval,
) error {
// Scope-walk
numStackFrames := len(frameset.stackFrames)
@ -279,8 +280,8 @@ func (frameset *StackFrameSet) set(
// See Stack.SetIndexed comments above
func (frameset *StackFrameSet) setIndexed(
stackVariable *StackVariable,
indices []*types.Mlrval,
mlrval *types.Mlrval,
indices []*mlrval.Mlrval,
mlrval *mlrval.Mlrval,
) error {
// Scope-walk
numStackFrames := len(frameset.stackFrames)
@ -312,7 +313,7 @@ func (frameset *StackFrameSet) unset(
// See Stack.UnsetIndexed comments above
func (frameset *StackFrameSet) unsetIndexed(
stackVariable *StackVariable,
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
) {
// Scope-walk
numStackFrames := len(frameset.stackFrames)
@ -353,7 +354,7 @@ func newStackFrame() *StackFrame {
// Returns nil on no such
func (frame *StackFrame) get(
stackVariable *StackVariable,
) *types.Mlrval {
) *mlrval.Mlrval {
offset, ok := frame.namesToOffsets[stackVariable.name]
if ok {
return frame.vars[offset].GetValue()
@ -372,7 +373,7 @@ func (frame *StackFrame) has(
// TODO: audit for honor of error-return at callsites
func (frame *StackFrame) set(
stackVariable *StackVariable,
mlrval *types.Mlrval,
mlrval *mlrval.Mlrval,
) error {
offset, ok := frame.namesToOffsets[stackVariable.name]
if !ok {
@ -393,7 +394,7 @@ func (frame *StackFrame) set(
func (frame *StackFrame) defineTyped(
stackVariable *StackVariable,
typeName string,
mlrval *types.Mlrval,
mlrval *mlrval.Mlrval,
) error {
_, ok := frame.namesToOffsets[stackVariable.name]
if !ok {
@ -418,16 +419,16 @@ func (frame *StackFrame) defineTyped(
// TODO: audit for honor of error-return at callsites
func (frame *StackFrame) setIndexed(
stackVariable *StackVariable,
indices []*types.Mlrval,
mlrval *types.Mlrval,
indices []*mlrval.Mlrval,
mv *mlrval.Mlrval,
) error {
value := frame.get(stackVariable)
if value == nil {
lib.InternalCodingErrorIf(len(indices) < 1)
leadingIndex := indices[0]
if leadingIndex.IsString() || leadingIndex.IsInt() {
newval := types.MlrvalFromEmptyMap()
newval.PutIndexed(indices, mlrval)
newval := mlrval.FromMap(mlrval.NewMlrmap())
newval.PutIndexed(indices, mv)
return frame.set(stackVariable, newval)
} else {
return errors.New(
@ -440,7 +441,7 @@ func (frame *StackFrame) setIndexed(
} else {
// For example maybe the variable exists and is an array but the
// leading index is a string.
return value.PutIndexed(indices, mlrval)
return value.PutIndexed(indices, mv)
}
}
@ -455,7 +456,7 @@ func (frame *StackFrame) unset(
func (frame *StackFrame) unsetIndexed(
stackVariable *StackVariable,
indices []*types.Mlrval,
indices []*mlrval.Mlrval,
) {
value := frame.get(stackVariable)
if value == nil {

View file

@ -11,16 +11,18 @@ import (
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
type State struct {
Inrec *types.Mlrmap
Inrec *mlrval.Mlrmap
Context *types.Context
Oosvars *types.Mlrmap
FilterExpression *types.Mlrval
Oosvars *mlrval.Mlrmap
FilterExpression *mlrval.Mlrval
Stack *Stack
OutputRecordsAndContexts *list.List // list of *types.RecordAndContext
// For holding "\0".."\9" between where they are set via things like
// '$x =~ "(..)_(...)"', and interpolated via things like '$y = "\2:\1"'.
RegexCaptures []string
@ -28,12 +30,12 @@ type State struct {
}
func NewEmptyState(options *cli.TOptions) *State {
oosvars := types.NewMlrmap()
oosvars := mlrval.NewMlrmap()
return &State{
Inrec: nil,
Context: nil,
Oosvars: oosvars,
FilterExpression: types.MLRVAL_TRUE,
FilterExpression: mlrval.TRUE,
Stack: NewStack(),
// OutputRecordsAndContexts is assigned after construction
@ -45,7 +47,7 @@ func NewEmptyState(options *cli.TOptions) *State {
}
func (state *State) Update(
inrec *types.Mlrmap,
inrec *mlrval.Mlrmap,
context *types.Context,
) {
state.Inrec = inrec

View file

@ -8,6 +8,7 @@ import (
"strings"
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -99,7 +100,7 @@ func (tr *TransformerAltkv) Transform(
HandleDefaultDownstreamDone(inputDownstreamDoneChannel, outputDownstreamDoneChannel)
if !inrecAndContext.EndOfStream {
inrec := inrecAndContext.Record
newrec := types.NewMlrmapAsRecord()
newrec := mlrval.NewMlrmapAsRecord()
outputFieldNumber := 1
for pe := inrec.Head; pe != nil; /* increment in loop body */ {

View file

@ -8,6 +8,7 @@ import (
"strings"
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -251,7 +252,7 @@ func (tr *TransformerBar) processNoAuto(
if idx > tr.width {
idx = tr.width
}
inrec.PutReference(fieldName, types.MlrvalFromString(tr.bars[idx]))
inrec.PutReference(fieldName, mlrval.FromString(tr.bars[idx]))
}
outputRecordsAndContexts.PushBack(inrecAndContext)
@ -339,7 +340,7 @@ func (tr *TransformerBar) processAuto(
buffer.WriteString("[")
buffer.WriteString(shi)
buffer.WriteString("]")
record.PutReference(fieldName, types.MlrvalFromString(buffer.String()))
record.PutReference(fieldName, mlrval.FromString(buffer.String()))
}
}

View file

@ -7,6 +7,7 @@ import (
"strings"
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/types"
)
@ -178,7 +179,7 @@ func (tr *TransformerCat) countersUngrouped(
inrec := inrecAndContext.Record
tr.counter++
key := tr.counterFieldName
inrec.PrependCopy(key, types.MlrvalFromInt(tr.counter))
inrec.PrependCopy(key, mlrval.FromInt(tr.counter))
}
outputRecordsAndContexts.PushBack(inrecAndContext)
}
@ -210,7 +211,7 @@ func (tr *TransformerCat) countersGrouped(
}
key := tr.counterFieldName
inrec.PrependCopy(key, types.MlrvalFromInt(counter))
inrec.PrependCopy(key, mlrval.FromInt(counter))
}
outputRecordsAndContexts.PushBack(inrecAndContext)
}

Some files were not shown because too many files have changed in this diff Show more