Made undefined variables return an error
All checks were successful
Build / build (push) Successful in 2m5s
All checks were successful
Build / build (push) Successful in 2m5s
Previously undefined variables would be set to nil, which introduced subtle errors. Changed this so that referencing an undefined variable will produce an error. This behaviour can changed as part of the instance configuration by declaring a missing-var handler.
This commit is contained in:
parent
2d56517de9
commit
c433e4bf53
11
ucl/eval.go
11
ucl/eval.go
|
@ -186,7 +186,16 @@ func (e evaluator) evalArg(ctx context.Context, ec *evalCtx, n astCmdArg) (Objec
|
|||
if v, ok := ec.getVar(*n.Var); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
if e.inst.missingVarHandler != nil {
|
||||
dv, err := e.inst.missingVarHandler(ctx, *n.Var)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fromGoValue(dv)
|
||||
}
|
||||
|
||||
return nil, errors.New("undefined variable: " + *n.Var)
|
||||
case n.MaybeSub != nil:
|
||||
sub := n.MaybeSub.Sub
|
||||
if sub == nil {
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
type Inst struct {
|
||||
out io.Writer
|
||||
missingBuiltinHandler MissingBuiltinHandler
|
||||
missingVarHandler MissingVarHandler
|
||||
echoPrinter EchoPrinter
|
||||
|
||||
rootEC *evalCtx
|
||||
|
@ -30,6 +31,12 @@ func WithMissingBuiltinHandler(handler MissingBuiltinHandler) InstOption {
|
|||
}
|
||||
}
|
||||
|
||||
func WithMissingVarHandler(handler MissingVarHandler) InstOption {
|
||||
return func(i *Inst) {
|
||||
i.missingVarHandler = handler
|
||||
}
|
||||
}
|
||||
|
||||
func WithModule(module Module) InstOption {
|
||||
return func(i *Inst) {
|
||||
for name, builtin := range module.Builtins {
|
||||
|
|
|
@ -119,6 +119,64 @@ func TestInst_Eval(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestInst_MissingVarHandler(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
expr string
|
||||
handler ucl.MissingVarHandler
|
||||
want any
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
desc: "default - error",
|
||||
expr: `$bla`,
|
||||
wantErr: "undefined variable: bla",
|
||||
},
|
||||
{
|
||||
desc: "handler - set to nil",
|
||||
handler: func(ctx context.Context, name string) (any, error) {
|
||||
return nil, nil
|
||||
},
|
||||
expr: `$bla`,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
desc: "handler - set to a string 1",
|
||||
handler: func(ctx context.Context, name string) (any, error) {
|
||||
return "I am " + name, nil
|
||||
},
|
||||
expr: `$bla`,
|
||||
want: "I am bla",
|
||||
},
|
||||
{
|
||||
desc: "handler - set to a string 2",
|
||||
handler: func(ctx context.Context, name string) (any, error) {
|
||||
return "I am " + name, nil
|
||||
},
|
||||
expr: `$something`,
|
||||
want: "I am something",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
outW := bytes.NewBuffer(nil)
|
||||
|
||||
inst := ucl.New(ucl.WithOut(outW), ucl.WithTestBuiltin(), ucl.WithMissingVarHandler(tt.handler))
|
||||
res, err := inst.Eval(ctx, tt.expr)
|
||||
|
||||
if tt.wantErr != "" {
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, err.Error(), tt.wantErr)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, res)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var parseComments1 = `
|
||||
proc lookup { |file|
|
||||
foreach { |toks|
|
||||
|
|
|
@ -197,7 +197,9 @@ func TestBuiltins_If(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
outW := bytes.NewBuffer(nil)
|
||||
|
||||
inst := New(WithOut(outW), WithTestBuiltin())
|
||||
inst := New(WithOut(outW), WithTestBuiltin(), WithMissingVarHandler(func(ctx context.Context, name string) (any, error) {
|
||||
return nil, nil
|
||||
}))
|
||||
err := evalAndDisplay(ctx, inst, tt.expr)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
@ -387,7 +389,9 @@ func TestBuiltins_Try(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
outW := bytes.NewBuffer(nil)
|
||||
|
||||
inst := New(WithOut(outW), WithTestBuiltin())
|
||||
inst := New(WithOut(outW), WithTestBuiltin(), WithMissingVarHandler(func(ctx context.Context, name string) (any, error) {
|
||||
return nil, nil
|
||||
}))
|
||||
err := evalAndDisplay(ctx, inst, tt.expr)
|
||||
|
||||
if tt.wantErr != "" {
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
type BuiltinHandler func(ctx context.Context, args CallArgs) (any, error)
|
||||
|
||||
type MissingBuiltinHandler func(ctx context.Context, name string, args CallArgs) (any, error)
|
||||
type MissingVarHandler func(ctx context.Context, name string) (any, error)
|
||||
|
||||
type CallArgs struct {
|
||||
args invocationArgs
|
||||
|
|
Loading…
Reference in a new issue