miller/pkg/runtime/state.go
Stephen Kitt f0a7c5832f
Performance and style fixes (#1981)
* Switch to integer ranges in for loops

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Switch to slices functions where appropriate

A number of utility functions can be replaced outright; since Miller
can technically be used as a library, these are deprecated rather than
removed. go:fix directives ensure that they can be replaced
automatically.

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Switch to reflect.TypeFor

This is slightly more efficient than TypeOf when the type is known at
compile time.

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Switch to strings.SplitSeq instead of strings.Split

SplitSeq results in fewer allocations.

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Drop obsolete build directives

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Use min/max instead of explicit comparisons

Signed-off-by: Stephen Kitt <steve@sk2.org>

* Append slices instead of looping

Signed-off-by: Stephen Kitt <steve@sk2.org>

---------

Signed-off-by: Stephen Kitt <steve@sk2.org>
2026-02-18 09:19:31 -05:00

96 lines
2.9 KiB
Go

// Tracks everything needed for statement evaluation/assignment in the Miller
// DSL runtimne: current record/context (the latter being NF, NR, etc);
// out-of-stream variables; local-variable stack; etc.
package runtime
import (
"slices"
"github.com/johnkerl/miller/v6/pkg/cli"
"github.com/johnkerl/miller/v6/pkg/lib"
"github.com/johnkerl/miller/v6/pkg/mlrval"
"github.com/johnkerl/miller/v6/pkg/types"
)
type State struct {
Inrec *mlrval.Mlrmap
Context *types.Context
Oosvars *mlrval.Mlrmap
FilterExpression *mlrval.Mlrval
Stack *Stack
OutputRecordsAndContexts *[]*types.RecordAndContext // 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"'.
//
// Each top-level block and user-defined function has its own captures.
//
// For example, in function `f()`, one can do `somevar =~ someregex`, then
// call some function `g()` which also uses `=~`, and then when `g()` returns,
// `f()` will have its "\1", "\2", etc intact.
//
// This is necessary for the stateful semantics of `=~` and "\1", "\2", etc.
// Those are avoided when the user calls `matchx`, which is newer, and
// stateless. However, `=~` exists in the Miller DSL and we must support it.
regexCapturesByFrame [][]string
Options *cli.TOptions
// StrictMode allows for runtime handling of absent-reads and untyped assignments.
StrictMode bool
// NoExitOnFunctionNotFound is used by the REPL: when true, a call to an
// undefined function returns an error mlrval instead of exiting the process.
NoExitOnFunctionNotFound bool
}
func NewEmptyState(options *cli.TOptions, strictMode bool) *State {
// See lib.MakeEmptyCaptures for context.
regexCapturesByFrame := make([][]string, 1)
regexCapturesByFrame[0] = lib.MakeEmptyCaptures()
oosvars := mlrval.NewMlrmap()
return &State{
Inrec: nil,
Context: nil,
Oosvars: oosvars,
FilterExpression: mlrval.NULL,
Stack: NewStack(),
regexCapturesByFrame: regexCapturesByFrame,
// OutputRecordsAndContexts is assigned after construction
Options: options,
StrictMode: strictMode,
}
}
func (state *State) Update(
inrec *mlrval.Mlrmap,
context *types.Context,
) {
state.Inrec = inrec
state.Context = context
state.regexCapturesByFrame[0] = lib.MakeEmptyCaptures()
}
func (state *State) SetRegexCaptures(
captures []string,
) {
state.regexCapturesByFrame[0] = slices.Clone(captures)
}
func (state *State) GetRegexCaptures() []string {
return slices.Clone(state.regexCapturesByFrame[0])
}
func (state *State) PushRegexCapturesFrame() {
state.regexCapturesByFrame = append([][]string{lib.MakeEmptyCaptures()}, state.regexCapturesByFrame...)
}
func (state *State) PopRegexCapturesFrame() {
state.regexCapturesByFrame = state.regexCapturesByFrame[1:]
}