Skip to content

Commit 9a89560

Browse files
feat: support onEmpty optional parameter on std.minArray,std.maxArray
1 parent 6a15a2f commit 9a89560

File tree

2 files changed

+62
-31
lines changed

2 files changed

+62
-31
lines changed

builtins.go

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2280,6 +2280,7 @@ func builtinExtVar(i *interpreter, name value) (value, error) {
22802280
func builtinMinArray(i *interpreter, arguments []value) (value, error) {
22812281
arrv := arguments[0]
22822282
keyFv := arguments[1]
2283+
onEmpty := arguments[2]
22832284

22842285
arr, err := i.getArray(arrv)
22852286
if err != nil {
@@ -2291,7 +2292,11 @@ func builtinMinArray(i *interpreter, arguments []value) (value, error) {
22912292
}
22922293
num := arr.length()
22932294
if num == 0 {
2294-
return nil, i.Error("Expected at least one element in array. Got none")
2295+
if onEmpty == nil {
2296+
return nil, i.Error("Expected at least one element in array. Got none")
2297+
} else {
2298+
return onEmpty, nil
2299+
}
22952300
}
22962301
minVal, err := arr.elements[0].getValue(i)
22972302
if err != nil {
@@ -2325,6 +2330,7 @@ func builtinMinArray(i *interpreter, arguments []value) (value, error) {
23252330
func builtinMaxArray(i *interpreter, arguments []value) (value, error) {
23262331
arrv := arguments[0]
23272332
keyFv := arguments[1]
2333+
onEmpty := arguments[2]
23282334

23292335
arr, err := i.getArray(arrv)
23302336
if err != nil {
@@ -2336,7 +2342,11 @@ func builtinMaxArray(i *interpreter, arguments []value) (value, error) {
23362342
}
23372343
num := arr.length()
23382344
if num == 0 {
2339-
return nil, i.Error("Expected at least one element in array. Got none")
2345+
if onEmpty == nil {
2346+
return nil, i.Error("Expected at least one element in array. Got none")
2347+
} else {
2348+
return onEmpty, nil
2349+
}
23402350
}
23412351
maxVal, err := arr.elements[0].getValue(i)
23422352
if err != nil {
@@ -2533,7 +2543,7 @@ func flattenArgs(args callArguments, params []namedParameter, defaults []value)
25332543
}
25342544
// Bind defaults for unsatisfied named parameters
25352545
for i := range params {
2536-
if flatArgs[i] == nil {
2546+
if flatArgs[i] == nil && defaults[i] != nil {
25372547
flatArgs[i] = readyThunk(defaults[i])
25382548
}
25392549
}
@@ -2551,9 +2561,13 @@ type unaryBuiltin struct {
25512561
func (b *unaryBuiltin) evalCall(args callArguments, i *interpreter) (value, error) {
25522562
flatArgs := flattenArgs(args, b.parameters(), []value{})
25532563

2554-
x, err := flatArgs[0].getValue(i)
2555-
if err != nil {
2556-
return nil, err
2564+
var x value
2565+
var err error
2566+
if flatArgs[0] != nil {
2567+
x, err = flatArgs[0].getValue(i)
2568+
if err != nil {
2569+
return nil, err
2570+
}
25572571
}
25582572
return b.function(i, x)
25592573
}
@@ -2581,13 +2595,19 @@ type binaryBuiltin struct {
25812595
func (b *binaryBuiltin) evalCall(args callArguments, i *interpreter) (value, error) {
25822596
flatArgs := flattenArgs(args, b.parameters(), []value{})
25832597

2584-
x, err := flatArgs[0].getValue(i)
2585-
if err != nil {
2586-
return nil, err
2598+
var err error
2599+
var x, y value
2600+
if flatArgs[0] != nil {
2601+
x, err = flatArgs[0].getValue(i)
2602+
if err != nil {
2603+
return nil, err
2604+
}
25872605
}
2588-
y, err := flatArgs[1].getValue(i)
2589-
if err != nil {
2590-
return nil, err
2606+
if flatArgs[1] != nil {
2607+
y, err = flatArgs[1].getValue(i)
2608+
if err != nil {
2609+
return nil, err
2610+
}
25912611
}
25922612
return b.function(i, x, y)
25932613
}
@@ -2615,17 +2635,25 @@ type ternaryBuiltin struct {
26152635
func (b *ternaryBuiltin) evalCall(args callArguments, i *interpreter) (value, error) {
26162636
flatArgs := flattenArgs(args, b.parameters(), []value{})
26172637

2618-
x, err := flatArgs[0].getValue(i)
2619-
if err != nil {
2620-
return nil, err
2638+
var err error
2639+
var x, y, z value
2640+
if flatArgs[0] != nil {
2641+
x, err = flatArgs[0].getValue(i)
2642+
if err != nil {
2643+
return nil, err
2644+
}
26212645
}
2622-
y, err := flatArgs[1].getValue(i)
2623-
if err != nil {
2624-
return nil, err
2646+
if flatArgs[1] != nil {
2647+
y, err = flatArgs[1].getValue(i)
2648+
if err != nil {
2649+
return nil, err
2650+
}
26252651
}
2626-
z, err := flatArgs[2].getValue(i)
2627-
if err != nil {
2628-
return nil, err
2652+
if flatArgs[2] != nil {
2653+
z, err = flatArgs[2].getValue(i)
2654+
if err != nil {
2655+
return nil, err
2656+
}
26292657
}
26302658
return b.function(i, x, y, z)
26312659
}
@@ -2647,8 +2675,9 @@ type generalBuiltinFunc func(*interpreter, []value) (value, error)
26472675
type generalBuiltinParameter struct {
26482676
// Note that the defaults are passed as values rather than AST nodes like in Parameters.
26492677
// This spares us unnecessary evaluation.
2650-
defaultValue value
2651-
name ast.Identifier
2678+
defaultValue value
2679+
name ast.Identifier
2680+
nonValueDefault bool
26522681
}
26532682

26542683
// generalBuiltin covers cases that other builtin structures do not,
@@ -2665,7 +2694,7 @@ func (b *generalBuiltin) parameters() []namedParameter {
26652694
ret := make([]namedParameter, len(b.params))
26662695
for i := range ret {
26672696
ret[i].name = b.params[i].name
2668-
if b.params[i].defaultValue != nil {
2697+
if b.params[i].defaultValue != nil || b.params[i].nonValueDefault {
26692698
// This is not actually used because the defaultValue is used instead.
26702699
// The only reason we don't leave it nil is because the checkArguments
26712700
// function uses the non-nil status to indicate that the parameter
@@ -2693,9 +2722,11 @@ func (b *generalBuiltin) evalCall(args callArguments, i *interpreter) (value, er
26932722
values := make([]value, len(flatArgs))
26942723
for j := 0; j < len(values); j++ {
26952724
var err error
2696-
values[j], err = flatArgs[j].getValue(i)
2697-
if err != nil {
2698-
return nil, err
2725+
if flatArgs[j] != nil {
2726+
values[j], err = flatArgs[j].getValue(i)
2727+
if err != nil {
2728+
return nil, err
2729+
}
26992730
}
27002731
}
27012732
return b.function(i, values)
@@ -2840,8 +2871,8 @@ var funcBuiltins = buildBuiltinMap([]builtin{
28402871
&unaryBuiltin{name: "encodeUTF8", function: builtinEncodeUTF8, params: ast.Identifiers{"str"}},
28412872
&unaryBuiltin{name: "decodeUTF8", function: builtinDecodeUTF8, params: ast.Identifiers{"arr"}},
28422873
&generalBuiltin{name: "sort", function: builtinSort, params: []generalBuiltinParameter{{name: "arr"}, {name: "keyF", defaultValue: functionID}}},
2843-
&generalBuiltin{name: "minArray", function: builtinMinArray, params: []generalBuiltinParameter{{name: "arr"}, {name: "keyF", defaultValue: functionID}}},
2844-
&generalBuiltin{name: "maxArray", function: builtinMaxArray, params: []generalBuiltinParameter{{name: "arr"}, {name: "keyF", defaultValue: functionID}}},
2874+
&generalBuiltin{name: "minArray", function: builtinMinArray, params: []generalBuiltinParameter{{name: "arr"}, {name: "keyF", defaultValue: functionID}, {name: "onEmpty", nonValueDefault: true}}},
2875+
&generalBuiltin{name: "maxArray", function: builtinMaxArray, params: []generalBuiltinParameter{{name: "arr"}, {name: "keyF", defaultValue: functionID}, {name: "onEmpty", nonValueDefault: true}}},
28452876
&unaryBuiltin{name: "native", function: builtinNative, params: ast.Identifiers{"x"}},
28462877
&unaryBuiltin{name: "sum", function: builtinSum, params: ast.Identifiers{"arr"}},
28472878
&unaryBuiltin{name: "avg", function: builtinAvg, params: ast.Identifiers{"arr"}},

linter/internal/types/stdlib.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ func prepareStdlib(g *typeGraph) {
150150
"sort": g.newFuncType(anyArrayType, []ast.Parameter{required("arr"), optional("keyF")}),
151151
"uniq": g.newFuncType(anyArrayType, []ast.Parameter{required("arr"), optional("keyF")}),
152152
"sum": g.newSimpleFuncType(numberType, "arr"),
153-
"minArray": g.newFuncType(anyArrayType, []ast.Parameter{required("arr"), optional("keyF")}),
154-
"maxArray": g.newFuncType(anyArrayType, []ast.Parameter{required("arr"), optional("keyF")}),
153+
"minArray": g.newFuncType(anyArrayType, []ast.Parameter{required("arr"), optional("keyF"), optional("onEmpty")}),
154+
"maxArray": g.newFuncType(anyArrayType, []ast.Parameter{required("arr"), optional("keyF"), optional("onEmpty")}),
155155
"contains": g.newSimpleFuncType(boolType, "arr", "elem"),
156156
"avg": g.newSimpleFuncType(numberType, "arr"),
157157
"all": g.newSimpleFuncType(boolArrayType, "arr"),

0 commit comments

Comments
 (0)