Skip to content

refactor(lang): remove dependency on runtime #2596

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 6, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cmd/flux/cmd/compile.go
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import (

_ "github.com/influxdata/flux/builtin"
"github.com/influxdata/flux/lang"
"github.com/influxdata/flux/runtime"
"github.com/spf13/cobra"
)

@@ -45,7 +46,7 @@ func compile(cmd *cobra.Command, args []string) error {
Query: script,
}

spec, err := c.Compile(context.Background())
spec, err := c.Compile(context.Background(), runtime.Default)
if err != nil {
return err
}
2 changes: 1 addition & 1 deletion compiler.go
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ import (
// Compiler produces a specification for the query.
type Compiler interface {
// Compile produces a specification for the query.
Compile(ctx context.Context) (Program, error)
Compile(ctx context.Context, runtime Runtime) (Program, error)
CompilerType() CompilerType
}

6 changes: 0 additions & 6 deletions complete/complete.go
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@ import (
"fmt"
"sort"

"github.com/influxdata/flux/runtime"
"github.com/influxdata/flux/semantic"
"github.com/influxdata/flux/values"
)
@@ -100,11 +99,6 @@ func (c Completer) FunctionSuggestion(name string) (FunctionSuggestion, error) {
return s, nil
}

// DefaultCompleter creates a completer with builtin scope
func DefaultCompleter() Completer {
return NewCompleter(runtime.Prelude())
}

func isFunction(v values.Value) bool {
return v.Type().Nature() == semantic.Function
}
2 changes: 1 addition & 1 deletion internal/cmd/refactortests/cmd/refactortests.go
Original file line number Diff line number Diff line change
@@ -178,7 +178,7 @@ func executeScript(pkg *ast.Package) (string, string, error) {
}

ctx := flux.NewDefaultDependencies().Inject(context.Background())
program, err := c.Compile(ctx)
program, err := c.Compile(ctx, runtime.Default)
if err != nil {
fmt.Println(ast.Format(testPkg))
return "", "", errors.Wrap(err, codes.Inherit, "error during compilation, check your script and retry")
3 changes: 2 additions & 1 deletion internal/cmd/test_rewriter/main.go
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ import (
"github.com/influxdata/flux/lang"
"github.com/influxdata/flux/memory"
"github.com/influxdata/flux/parser"
"github.com/influxdata/flux/runtime"
"github.com/spf13/cobra"
)

@@ -78,7 +79,7 @@ func runQuery(query string) (flux.ResultIterator, error) {
deps.Deps.FilesystemService = filesystem.SystemFS

ctx := deps.Inject(context.Background())
program, err := c.Compile(ctx)
program, err := c.Compile(ctx, runtime.Default)
if err != nil {
return nil, err
}
5 changes: 2 additions & 3 deletions internal/spec/build.go
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@ import (

"github.com/influxdata/flux"
"github.com/influxdata/flux/interpreter"
"github.com/influxdata/flux/runtime"
"github.com/opentracing/opentracing-go"
)

@@ -128,7 +127,7 @@ func FromTableObject(ctx context.Context, to *flux.TableObject, now time.Time) (
// FromScript returns a spec from a script expressed as a raw string.
// This is duplicate logic for what happens when a flux.Program runs.
// This function is used in tests that compare flux.Specs (e.g. in planner tests).
func FromScript(ctx context.Context, now time.Time, script string) (*flux.Spec, error) {
func FromScript(ctx context.Context, runtime flux.Runtime, now time.Time, script string) (*flux.Spec, error) {
s, _ := opentracing.StartSpanFromContext(ctx, "parse")
astPkg, err := runtime.Parse(script)
if err != nil {
@@ -137,7 +136,7 @@ func FromScript(ctx context.Context, now time.Time, script string) (*flux.Spec,
s.Finish()

s, cctx := opentracing.StartSpanFromContext(ctx, "eval")
sideEffects, scope, err := runtime.EvalAST(cctx, astPkg, runtime.SetNowOption(now))
sideEffects, scope, err := runtime.Eval(cctx, astPkg, flux.SetNowOption(now))
if err != nil {
return nil, err
}
3 changes: 2 additions & 1 deletion internal/spec/build_test.go
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import (
_ "github.com/influxdata/flux/builtin"
"github.com/influxdata/flux/dependencies/dependenciestest"
"github.com/influxdata/flux/internal/spec"
"github.com/influxdata/flux/runtime"
)

func Benchmark_FromScript(b *testing.B) {
@@ -35,7 +36,7 @@ check |> yield(name: "mean")
ctx := dependenciestest.Default().Inject(context.Background())
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := spec.FromScript(ctx, time.Now(), query); err != nil {
if _, err := spec.FromScript(ctx, runtime.Default, time.Now(), query); err != nil {
b.Fatal(err)
}
}
37 changes: 13 additions & 24 deletions lang/compiler.go
Original file line number Diff line number Diff line change
@@ -14,7 +14,6 @@ import (
"github.com/influxdata/flux/internal/spec"
"github.com/influxdata/flux/memory"
"github.com/influxdata/flux/plan"
"github.com/influxdata/flux/runtime"
"github.com/influxdata/flux/semantic"
"github.com/influxdata/flux/values"
"github.com/opentracing/opentracing-go"
@@ -97,20 +96,21 @@ func Verbose(v bool) CompileOption {

// Compile evaluates a Flux script producing a flux.Program.
// now parameter must be non-zero, that is the default now time should be set before compiling.
func Compile(q string, now time.Time, opts ...CompileOption) (*AstProgram, error) {
func Compile(q string, runtime flux.Runtime, now time.Time, opts ...CompileOption) (*AstProgram, error) {
astPkg, err := runtime.Parse(q)
if err != nil {
return nil, err
}
return CompileAST(astPkg, now, opts...), nil
return CompileAST(astPkg, runtime, now, opts...), nil
}

// CompileAST evaluates a Flux AST and produces a flux.Program.
// now parameter must be non-zero, that is the default now time should be set before compiling.
func CompileAST(astPkg *ast.Package, now time.Time, opts ...CompileOption) *AstProgram {
func CompileAST(astPkg *ast.Package, runtime flux.Runtime, now time.Time, opts ...CompileOption) *AstProgram {
return &AstProgram{
Program: &Program{
opts: applyOptions(opts...),
Runtime: runtime,
opts: applyOptions(opts...),
},
Ast: astPkg,
Now: now,
@@ -165,9 +165,9 @@ type FluxCompiler struct {
Query string `json:"query"`
}

func (c FluxCompiler) Compile(ctx context.Context) (flux.Program, error) {
func (c FluxCompiler) Compile(ctx context.Context, runtime flux.Runtime) (flux.Program, error) {
// Ignore context, it will be provided upon Program Start.
return Compile(c.Query, c.Now, WithExtern(c.Extern))
return Compile(c.Query, runtime, c.Now, WithExtern(c.Extern))
}

func (c FluxCompiler) CompilerType() flux.CompilerType {
@@ -180,13 +180,13 @@ type ASTCompiler struct {
Now time.Time
}

func (c ASTCompiler) Compile(ctx context.Context) (flux.Program, error) {
func (c ASTCompiler) Compile(ctx context.Context, runtime flux.Runtime) (flux.Program, error) {
now := c.Now
if now.IsZero() {
now = time.Now()
}
// Ignore context, it will be provided upon Program Start.
return CompileAST(c.AST, now), nil
return CompileAST(c.AST, runtime, now), nil
}

func (ASTCompiler) CompilerType() flux.CompilerType {
@@ -224,6 +224,7 @@ type LoggingProgram interface {
type Program struct {
Logger *zap.Logger
PlanSpec *plan.Spec
Runtime flux.Runtime

opts *compileOptions
}
@@ -296,7 +297,7 @@ type AstProgram struct {
Now time.Time
}

func (p *AstProgram) getSpec(ctx context.Context, alloc *memory.Allocator) (*flux.Spec, values.Scope, error) {
func (p *AstProgram) getSpec(ctx context.Context, runtime flux.Runtime, alloc *memory.Allocator) (*flux.Spec, values.Scope, error) {
if p.opts == nil {
p.opts = defaultOptions()
}
@@ -314,7 +315,7 @@ func (p *AstProgram) getSpec(ctx context.Context, alloc *memory.Allocator) (*flu
}
ctx = deps.Inject(ctx)
s, cctx := opentracing.StartSpanFromContext(ctx, "eval")
sideEffects, scope, err := runtime.EvalAST(cctx, p.Ast, runtime.SetNowOption(p.Now))
sideEffects, scope, err := runtime.Eval(cctx, p.Ast, flux.SetNowOption(p.Now))
if err != nil {
return nil, nil, err
}
@@ -339,7 +340,7 @@ func (p *AstProgram) getSpec(ctx context.Context, alloc *memory.Allocator) (*flu
}

func (p *AstProgram) Start(ctx context.Context, alloc *memory.Allocator) (flux.Query, error) {
sp, scope, err := p.getSpec(ctx, alloc)
sp, scope, err := p.getSpec(ctx, p.Runtime, alloc)
if err != nil {
return nil, err
}
@@ -450,15 +451,3 @@ func getRules(plannerPkg values.Object, optionName string) ([]string, error) {
})
return rs, nil
}

// WalkIR applies the function `f` to each operation in the compiled spec.
// WARNING: this function evaluates the AST using an unlimited allocator.
// In case of dynamic queries this could lead to unexpected memory usage.
func WalkIR(ctx context.Context, astPkg *ast.Package, f func(o *flux.Operation) error) error {
p := CompileAST(astPkg, time.Now())
if sp, _, err := p.getSpec(ctx, new(memory.Allocator)); err != nil {
return err
} else {
return sp.Walk(f)
}
}
10 changes: 5 additions & 5 deletions lang/compiler_test.go
Original file line number Diff line number Diff line change
@@ -133,7 +133,7 @@ func TestFluxCompiler(t *testing.T) {
t.Errorf("compiler serialized/deserialized does not match: -want/+got:\n%v", diff)
}

program, err := c.Compile(ctx)
program, err := c.Compile(ctx, runtime.Default)
if err != nil {
if tc.err != "" {
if !strings.Contains(err.Error(), tc.err) {
@@ -164,7 +164,7 @@ func TestFluxCompiler(t *testing.T) {
}

func TestCompilationError(t *testing.T) {
program, err := lang.Compile(`illegal query`, time.Unix(0, 0))
program, err := lang.Compile(`illegal query`, runtime.Default, time.Unix(0, 0))
if err != nil {
// This shouldn't happen, has the script should be evaluated at program Start.
t.Fatal(err)
@@ -293,7 +293,7 @@ csv.from(csv: "foo,bar") |> range(start: 2017-10-10T00:00:00Z)
c.PrependFile(tc.file)
}

program, err := c.Compile(context.Background())
program, err := c.Compile(context.Background(), runtime.Default)
if err != nil {
t.Fatalf("failed to compile AST: %v", err)
}
@@ -322,7 +322,7 @@ func TestCompileOptions(t *testing.T) {

opt := lang.WithLogPlanOpts(plan.OnlyLogicalRules(removeCount{}))

program, err := lang.Compile(src, now, opt)
program, err := lang.Compile(src, runtime.Default, now, opt)
if err != nil {
t.Fatalf("failed to compile script: %v", err)
}
@@ -654,7 +654,7 @@ option planner.disableLogicalRules = ["removeCountRule"]`},
}
}

program := lang.CompileAST(astPkg, nowFn())
program := lang.CompileAST(astPkg, runtime.Default, nowFn())
ctx := executetest.NewTestExecuteDependencies().Inject(context.Background())
if _, err := program.Start(ctx, &memory.Allocator{}); err != nil {
if tc.wantErr == "" {
1 change: 0 additions & 1 deletion lang/dependencies.go
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@ import (
"context"

"github.com/influxdata/flux/memory"

"go.uber.org/zap"
)

3 changes: 2 additions & 1 deletion lang/query_test.go
Original file line number Diff line number Diff line change
@@ -10,10 +10,11 @@ import (
"github.com/influxdata/flux/execute/executetest"
"github.com/influxdata/flux/lang"
"github.com/influxdata/flux/memory"
"github.com/influxdata/flux/runtime"
)

func runQuery(script string) (flux.Query, error) {
program, err := lang.Compile(script, time.Unix(0, 0))
program, err := lang.Compile(script, runtime.Default, time.Unix(0, 0))
if err != nil {
return nil, err
}
3 changes: 2 additions & 1 deletion plan/logical_test.go
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ import (
"github.com/influxdata/flux/parser"
"github.com/influxdata/flux/plan"
"github.com/influxdata/flux/plan/plantest"
"github.com/influxdata/flux/runtime"
"github.com/influxdata/flux/semantic"
"github.com/influxdata/flux/stdlib/influxdata/influxdb"
"github.com/influxdata/flux/stdlib/kafka"
@@ -22,7 +23,7 @@ import (
)

func compile(fluxText string, now time.Time) (*flux.Spec, error) {
return spec.FromScript(dependenciestest.Default().Inject(context.Background()), now, fluxText)
return spec.FromScript(dependenciestest.Default().Inject(context.Background()), runtime.Default, now, fluxText)
}

func TestPlan_LogicalPlanFromSpec(t *testing.T) {
3 changes: 2 additions & 1 deletion plan/rules_test.go
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import (
"github.com/influxdata/flux/internal/spec"
"github.com/influxdata/flux/plan"
"github.com/influxdata/flux/plan/plantest"
"github.com/influxdata/flux/runtime"
"github.com/influxdata/flux/stdlib/influxdata/influxdb"
)

@@ -30,7 +31,7 @@ func TestRuleRegistration(t *testing.T) {
plan.RegisterLogicalRules(&simpleRule)

now := time.Now().UTC()
fluxSpec, err := spec.FromScript(dependenciestest.Default().Inject(context.Background()), now, `from(bucket: "telegraf") |> range(start: -5m)`)
fluxSpec, err := spec.FromScript(dependenciestest.Default().Inject(context.Background()), runtime.Default, now, `from(bucket: "telegraf") |> range(start: -5m)`)
if err != nil {
t.Fatalf("could not compile very simple Flux query: %v", err)
}
3 changes: 2 additions & 1 deletion querytest/compile.go
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ import (
"github.com/influxdata/flux"
"github.com/influxdata/flux/dependencies/dependenciestest"
"github.com/influxdata/flux/internal/spec"
"github.com/influxdata/flux/runtime"
"github.com/influxdata/flux/semantic/semantictest"
"github.com/influxdata/flux/stdlib/universe"
"github.com/influxdata/flux/values/valuestest"
@@ -38,7 +39,7 @@ func NewQueryTestHelper(t *testing.T, tc NewQueryTestCase) {
t.Helper()

now := time.Now().UTC()
got, err := spec.FromScript(dependenciestest.Default().Inject(context.Background()), now, tc.Raw)
got, err := spec.FromScript(dependenciestest.Default().Inject(context.Background()), runtime.Default, now, tc.Raw)
if (err != nil) != tc.WantErr {
t.Errorf("error compiling spec error = %v, wantErr %v", err, tc.WantErr)
return
3 changes: 2 additions & 1 deletion querytest/execute.go
Original file line number Diff line number Diff line change
@@ -7,12 +7,13 @@ import (
"github.com/influxdata/flux"
"github.com/influxdata/flux/execute/executetest"
"github.com/influxdata/flux/memory"
"github.com/influxdata/flux/runtime"
)

type Querier struct{}

func (q *Querier) Query(ctx context.Context, w io.Writer, c flux.Compiler, d flux.Dialect) (int64, error) {
program, err := c.Compile(ctx)
program, err := c.Compile(ctx, runtime.Default)
if err != nil {
return 0, err
}
2 changes: 1 addition & 1 deletion repl/compiler.go
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ type Compiler struct {
Spec *flux.Spec `json:"spec"`
}

func (c Compiler) Compile(ctx context.Context) (flux.Program, error) {
func (c Compiler) Compile(ctx context.Context, runtime flux.Runtime) (flux.Program, error) {
planner := plan.PlannerBuilder{}.Build()
ps, err := planner.Plan(c.Spec)
if err != nil {
2 changes: 1 addition & 1 deletion repl/repl.go
Original file line number Diff line number Diff line change
@@ -220,7 +220,7 @@ func (r *REPL) doQuery(ctx context.Context, spec *flux.Spec, deps flux.Dependenc
Spec: spec,
}

program, err := c.Compile(ctx)
program, err := c.Compile(ctx, runtime.Default)
if err != nil {
return err
}
70 changes: 70 additions & 0 deletions runtime.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package flux

import (
"context"
"time"

"github.com/influxdata/flux/ast"
"github.com/influxdata/flux/interpreter"
"github.com/influxdata/flux/semantic"
"github.com/influxdata/flux/values"
)

// Runtime encapsulates the operations supported by the flux runtime.
type Runtime interface {
// Parse parses a Flux script and produces an ast.Package.
Parse(flux string) (*ast.Package, error)

// Eval accepts a Flux AST and evaluates it to produce a set of side effects (as a slice of values) and a scope.
Eval(ctx context.Context, astPkg *ast.Package, opts ...ScopeMutator) ([]interpreter.SideEffect, values.Scope, error)

// IsPreludePackage will return if the named package is part
// of the prelude for this runtime.
IsPreludePackage(pkg string) bool

// LookupBuiltinType returns the type of the builtin value for a given
// Flux stdlib package. Returns an error if lookup fails.
LookupBuiltinType(pkg, name string) (semantic.MonoType, error)
}

// ScopeMutator is any function that mutates the scope of an identifier.
type ScopeMutator = func(r Runtime, scope values.Scope)

// SetOption returns a func that adds a var binding to a scope.
func SetOption(pkg, name string, fn func(r Runtime) values.Value) ScopeMutator {
return func(r Runtime, scope values.Scope) {
v := fn(r)
p, ok := scope.Lookup(pkg)
if ok {
if p, ok := p.(values.Package); ok {
values.SetOption(p, name, v)
}
} else if r.IsPreludePackage(pkg) {
opt, ok := scope.Lookup(name)
if ok {
if opt, ok := opt.(*values.Option); ok {
opt.Value = v
}
}
}
}
}

// SetNowOption returns a ScopeMutator that sets the `now` option to the given time.
func SetNowOption(now time.Time) ScopeMutator {
return SetOption(nowPkg, NowOption, generateNowFunc(now))
}

func generateNowFunc(now time.Time) func(r Runtime) values.Value {
return func(r Runtime) values.Value {
timeVal := values.NewTime(values.ConvertTime(now))
ftype, err := r.LookupBuiltinType("universe", "now")
if err != nil {
panic(err)
}
call := func(ctx context.Context, args values.Object) (values.Value, error) {
return timeVal, nil
}
return values.NewFunction(NowOption, ftype, call, false)
}
}
23 changes: 12 additions & 11 deletions runtime/global.go
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ package runtime
import (
"context"

"github.com/influxdata/flux"
"github.com/influxdata/flux/ast"
"github.com/influxdata/flux/interpreter"
"github.com/influxdata/flux/parser"
@@ -11,48 +12,48 @@ import (

// RegisterPackage adds a builtin package
func RegisterPackage(pkg *ast.Package) {
if err := defaultRuntime.RegisterPackage(pkg); err != nil {
if err := Default.RegisterPackage(pkg); err != nil {
panic(err)
}
}

// RegisterPackageValue adds a value for an identifier in a builtin package
func RegisterPackageValue(pkgpath, name string, value values.Value) {
if err := defaultRuntime.RegisterPackageValue(pkgpath, name, value); err != nil {
if err := Default.RegisterPackageValue(pkgpath, name, value); err != nil {
panic(err)
}
}

// ReplacePackageValue replaces a value for an identifier in a builtin package
func ReplacePackageValue(pkgpath, name string, value values.Value) {
if err := defaultRuntime.ReplacePackageValue(pkgpath, name, value); err != nil {
if err := Default.ReplacePackageValue(pkgpath, name, value); err != nil {
panic(err)
}
}

// StdLib returns an importer for the Flux standard library.
func StdLib() interpreter.Importer {
return defaultRuntime.Stdlib()
return Default.Stdlib()
}

// Prelude returns a scope object representing the Flux universe block
func Prelude() values.Scope {
return defaultRuntime.Prelude()
return Default.Prelude()
}

// Eval accepts a Flux script and evaluates it to produce a set of side effects (as a slice of values) and a scope.
func Eval(ctx context.Context, flux string, opts ...ScopeMutator) ([]interpreter.SideEffect, values.Scope, error) {
func Eval(ctx context.Context, flux string, opts ...flux.ScopeMutator) ([]interpreter.SideEffect, values.Scope, error) {
h := parser.ParseToHandle([]byte(flux))
return defaultRuntime.evalHandle(ctx, h, opts...)
return Default.evalHandle(ctx, h, opts...)
}

// EvalAST accepts a Flux AST and evaluates it to produce a set of side effects (as a slice of values) and a scope.
func EvalAST(ctx context.Context, astPkg *ast.Package, opts ...ScopeMutator) ([]interpreter.SideEffect, values.Scope, error) {
return defaultRuntime.Eval(ctx, astPkg, opts...)
func EvalAST(ctx context.Context, astPkg *ast.Package, opts ...flux.ScopeMutator) ([]interpreter.SideEffect, values.Scope, error) {
return Default.Eval(ctx, astPkg, opts...)
}

// EvalOptions is like EvalAST, but only evaluates options.
func EvalOptions(ctx context.Context, astPkg *ast.Package, opts ...ScopeMutator) ([]interpreter.SideEffect, values.Scope, error) {
func EvalOptions(ctx context.Context, astPkg *ast.Package, opts ...flux.ScopeMutator) ([]interpreter.SideEffect, values.Scope, error) {
return EvalAST(ctx, options(astPkg), opts...)
}

@@ -87,7 +88,7 @@ func options(astPkg *ast.Package) *ast.Package {
// FinalizeBuiltIns must be called to complete registration.
// Future calls to RegisterFunction or RegisterPackageValue will panic.
func FinalizeBuiltIns() {
if err := defaultRuntime.Finalize(); err != nil {
if err := Default.Finalize(); err != nil {
panic(err)
}
}
80 changes: 23 additions & 57 deletions runtime/runtime.go
Original file line number Diff line number Diff line change
@@ -2,8 +2,8 @@ package runtime

import (
"context"
"time"

"github.com/influxdata/flux"
"github.com/influxdata/flux/ast"
"github.com/influxdata/flux/codes"
"github.com/influxdata/flux/internal/errors"
@@ -14,9 +14,9 @@ import (
"github.com/influxdata/flux/values"
)

// defaultRuntime contains the preregistered packages and builtin values
// Default contains the preregistered packages and builtin values
// required to execute a flux script.
var defaultRuntime = &runtime{}
var Default = &runtime{}

// runtime contains the flux runtime for interpreting and
// executing queries.
@@ -26,6 +26,23 @@ type runtime struct {
finalized bool
}

func (r *runtime) Parse(flux string) (*ast.Package, error) {
return Parse(flux)
}

func (r *runtime) IsPreludePackage(pkg string) bool {
for _, p := range prelude {
if p == pkg {
return true
}
}
return false
}

func (r *runtime) LookupBuiltinType(pkg, name string) (semantic.MonoType, error) {
return LookupBuiltinType(pkg, name)
}

func (r *runtime) RegisterPackage(pkg *ast.Package) error {
if r.finalized {
return errors.New(codes.Internal, "already finalized, cannot register builtin package")
@@ -101,15 +118,15 @@ func (r *runtime) Prelude() values.Scope {
return scope
}

func (r *runtime) Eval(ctx context.Context, astPkg *ast.Package, opts ...ScopeMutator) ([]interpreter.SideEffect, values.Scope, error) {
func (r *runtime) Eval(ctx context.Context, astPkg *ast.Package, opts ...flux.ScopeMutator) ([]interpreter.SideEffect, values.Scope, error) {
h, err := parser.ToHandle(astPkg)
if err != nil {
return nil, nil, err
}
return r.evalHandle(ctx, h, opts...)
}

func (r *runtime) evalHandle(ctx context.Context, h *libflux.ASTPkg, opts ...ScopeMutator) ([]interpreter.SideEffect, values.Scope, error) {
func (r *runtime) evalHandle(ctx context.Context, h *libflux.ASTPkg, opts ...flux.ScopeMutator) ([]interpreter.SideEffect, values.Scope, error) {
semPkg, err := AnalyzePackage(h)
if err != nil {
return nil, nil, err
@@ -124,7 +141,7 @@ func (r *runtime) evalHandle(ctx context.Context, h *libflux.ASTPkg, opts ...Sco

// Mutate the scope with any additional options.
for _, opt := range opts {
opt(scope)
opt(r, scope)
}

// Execute the interpreter over the package.
@@ -189,57 +206,6 @@ func (r *runtime) Finalize() error {
return nil
}

func isPreludePackage(pkg string) bool {
for _, p := range prelude {
if p == pkg {
return true
}
}
return false
}

// ScopeMutator is any function that mutates the scope of an identifier.
type ScopeMutator = func(values.Scope)

// SetOption returns a func that adds a var binding to a scope.
func SetOption(pkg, name string, v values.Value) ScopeMutator {
return func(scope values.Scope) {
p, ok := scope.Lookup(pkg)
if ok {
if p, ok := p.(values.Package); ok {
values.SetOption(p, name, v)
}
} else if isPreludePackage(pkg) {
opt, ok := scope.Lookup(name)
if ok {
if opt, ok := opt.(*values.Option); ok {
opt.Value = v
}
}

}
}
}

var (
NowOption = "now"
nowPkg = "universe"
)

// SetNowOption returns a ScopeMutator that sets the `now` option to the given time.
func SetNowOption(now time.Time) ScopeMutator {
return SetOption(nowPkg, NowOption, generateNowFunc(now))
}

func generateNowFunc(now time.Time) values.Function {
timeVal := values.NewTime(values.ConvertTime(now))
ftype := MustLookupBuiltinType("universe", "now")
call := func(ctx context.Context, args values.Object) (values.Value, error) {
return timeVal, nil
}
return values.NewFunction(NowOption, ftype, call, false)
}

// validatePackageBuiltins ensures that all package builtins have both an AST builtin statement and a registered value.
func validatePackageBuiltins(pkg map[string]values.Value, semPkg *semantic.Package) error {
builtinStmts := make(map[string]*semantic.BuiltinStatement)
4 changes: 2 additions & 2 deletions stdlib/flux_test.go
Original file line number Diff line number Diff line change
@@ -156,7 +156,7 @@ func testFlux(t testing.TB, file *ast.File) flux.Statistics {
}

func doTestRun(t testing.TB, c flux.Compiler) flux.Statistics {
program, err := c.Compile(context.Background())
program, err := c.Compile(context.Background(), runtime.Default)
if err != nil {
t.Fatalf("unexpected error while compiling query: %v", err)
}
@@ -186,7 +186,7 @@ func doTestRun(t testing.TB, c flux.Compiler) flux.Statistics {
}

func doTestInspect(t testing.TB, c flux.Compiler) flux.Statistics {
program, err := c.Compile(context.Background())
program, err := c.Compile(context.Background(), runtime.Default)
if err != nil {
t.Fatalf("unexpected error while compiling query: %v", err)
}
2 changes: 1 addition & 1 deletion stdlib/pagerduty/pagerduty_test.go
Original file line number Diff line number Diff line change
@@ -207,7 +207,7 @@ endpoint = pagerduty.endpoint(url:url)(mapFn: (r) => {
csv.from(csv:data) |> endpoint()
`

prog, err := lang.Compile(fluxString, time.Now(), lang.WithExtern(&ast.File{Body: []ast.Statement{
prog, err := lang.Compile(fluxString, runtime.Default, time.Now(), lang.WithExtern(&ast.File{Body: []ast.Statement{
&ast.VariableAssignment{
ID: &ast.Identifier{
Name: "url",
2 changes: 1 addition & 1 deletion stdlib/slack/slack_test.go
Original file line number Diff line number Diff line change
@@ -155,7 +155,7 @@ endpoint = slack.endpoint(url:url, token:token)(mapFn: (r) => {
})
csv.from(csv:data) |> endpoint()`
prog, err := lang.Compile(fluxString, time.Now(), lang.WithExtern(&ast.File{Body: []ast.Statement{
prog, err := lang.Compile(fluxString, runtime.Default, time.Now(), lang.WithExtern(&ast.File{Body: []ast.Statement{
&ast.VariableAssignment{
ID: &ast.Identifier{
Name: "url",
6 changes: 3 additions & 3 deletions stdlib/universe/typeconv.go
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ import (

"github.com/influxdata/flux/codes"
"github.com/influxdata/flux/internal/errors"
"github.com/influxdata/flux/parser"
"github.com/influxdata/flux/internal/parser"
"github.com/influxdata/flux/runtime"
"github.com/influxdata/flux/semantic"
"github.com/influxdata/flux/values"
@@ -573,11 +573,11 @@ func (c *timeConv) Call(ctx context.Context, args values.Object) (values.Value,
}
switch v.Type().Nature() {
case semantic.String:
ast, err := parser.ParseTime(v.Str())
ts, err := parser.ParseTime(v.Str())
if err != nil {
return nil, err
}
t = values.Time(ast.Value.UnixNano())
t = values.Time(ts.UnixNano())
case semantic.Int:
t = values.Time(v.Int())
case semantic.UInt: