Skip to content

Commit

Permalink
Merge branch 'master' into string-trim
Browse files Browse the repository at this point in the history
  • Loading branch information
Tejesh-Raut committed May 29, 2023
2 parents f73c0cc + 44538a3 commit 7b87efa
Show file tree
Hide file tree
Showing 22 changed files with 183 additions and 20 deletions.
123 changes: 123 additions & 0 deletions builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -1289,6 +1289,18 @@ func builtinIsEmpty(i *interpreter, strv value) (value, error) {
return makeValueBoolean(len(sStr) == 0), nil
}

func builtinEqualsIgnoreCase(i *interpreter, sv1, sv2 value) (value, error) {
s1, err := i.getString(sv1)
if err != nil {
return nil, err
}
s2, err := i.getString(sv2)
if err != nil {
return nil, err
}
return makeValueBoolean(strings.EqualFold(s1.getGoString(), s2.getGoString())), nil
}

func builtinTrim(i *interpreter, strv value) (value, error) {
str, err := i.getString(strv)
if err != nil {
Expand Down Expand Up @@ -1950,6 +1962,42 @@ func builtinMinArray(i *interpreter, arguments []value) (value, error) {
return minVal, nil
}

func builtinMaxArray(i *interpreter, arguments []value) (value, error) {
arrv := arguments[0]
keyFv := arguments[1]

arr, err := i.getArray(arrv)
if err != nil {
return nil, err
}
keyF, err := i.getFunction(keyFv)
if err != nil {
return nil, err
}
num := arr.length()
if num == 0 {
return nil, i.Error("Expected at least one element in array. Got none")
}
maxVal, err := keyF.call(i, args(arr.elements[0]))
if err != nil {
return nil, err
}
for index := 1; index < num; index++ {
current, err := keyF.call(i, args(arr.elements[index]))
if err != nil {
return nil, err
}
cmp, err := valueCmp(i, maxVal, current)
if err != nil {
return nil, err
}
if cmp < 0 {
maxVal = current
}
}
return maxVal, nil
}

func builtinNative(i *interpreter, name value) (value, error) {
str, err := i.getString(name)
if err != nil {
Expand Down Expand Up @@ -1999,6 +2047,76 @@ func builtinContains(i *interpreter, arrv value, ev value) (value, error) {
return makeValueBoolean(false), nil
}

func builtinRemove(i *interpreter, arrv value, ev value) (value, error) {
arr, err := i.getArray(arrv)
if err != nil {
return nil, err
}
for idx, elem := range arr.elements {
val, err := elem.getValue(i)
if err != nil {
return nil, err
}
eq, err := rawEquals(i, val, ev)
if err != nil {
return nil, err
}
if eq {
return builtinRemoveAt(i, arrv, intToValue(idx))
}
}
return arr, nil
}

func builtinRemoveAt(i *interpreter, arrv value, idxv value) (value, error) {
arr, err := i.getArray(arrv)
if err != nil {
return nil, err
}
idx, err := i.getInt(idxv)
if err != nil {
return nil, err
}

newArr := append(arr.elements[:idx], arr.elements[idx+1:]...)
return makeValueArray(newArr), nil
}

func builtInObjectRemoveKey(i *interpreter, objv value, keyv value) (value, error) {
obj, err := i.getObject(objv)
if err != nil {
return nil, err
}
key, err := i.getString(keyv)
if err != nil {
return nil, err
}

newFields := make(simpleObjectFieldMap)
simpleObj := obj.uncached.(*simpleObject)
for fieldName, fieldVal := range simpleObj.fields {
if fieldName == key.getGoString() {
// skip the field which needs to be deleted
continue
}

newFields[fieldName] = simpleObjectField{
hide: fieldVal.hide,
field: &bindingsUnboundField{
inner: fieldVal.field,
bindings: simpleObj.upValues,
},
}
}

return makeValueSimpleObject(
nil,
newFields,
[]unboundField{}, // No asserts allowed
nil,
), nil
}

// Utils for builtins - TODO(sbarzowski) move to a separate file in another commit

type builtin interface {
Expand Down Expand Up @@ -2260,11 +2378,14 @@ var funcBuiltins = buildBuiltinMap([]builtin{
&ternaryBuiltin{name: "foldl", function: builtinFoldl, params: ast.Identifiers{"func", "arr", "init"}},
&ternaryBuiltin{name: "foldr", function: builtinFoldr, params: ast.Identifiers{"func", "arr", "init"}},
&binaryBuiltin{name: "member", function: builtinMember, params: ast.Identifiers{"arr", "x"}},
&binaryBuiltin{name: "remove", function: builtinRemove, params: ast.Identifiers{"arr", "elem"}},
&binaryBuiltin{name: "removeAt", function: builtinRemoveAt, params: ast.Identifiers{"arr", "i"}},
&binaryBuiltin{name: "range", function: builtinRange, params: ast.Identifiers{"from", "to"}},
&binaryBuiltin{name: "primitiveEquals", function: primitiveEquals, params: ast.Identifiers{"x", "y"}},
&binaryBuiltin{name: "equals", function: builtinEquals, params: ast.Identifiers{"x", "y"}},
&binaryBuiltin{name: "objectFieldsEx", function: builtinObjectFieldsEx, params: ast.Identifiers{"obj", "hidden"}},
&ternaryBuiltin{name: "objectHasEx", function: builtinObjectHasEx, params: ast.Identifiers{"obj", "fname", "hidden"}},
&binaryBuiltin{name: "objectRemoveKey", function: builtInObjectRemoveKey, params: ast.Identifiers{"obj", "key"}},
&unaryBuiltin{name: "type", function: builtinType, params: ast.Identifiers{"x"}},
&unaryBuiltin{name: "char", function: builtinChar, params: ast.Identifiers{"n"}},
&unaryBuiltin{name: "codepoint", function: builtinCodepoint, params: ast.Identifiers{"str"}},
Expand Down Expand Up @@ -2294,6 +2415,7 @@ var funcBuiltins = buildBuiltinMap([]builtin{
&ternaryBuiltin{name: "splitLimit", function: builtinSplitLimit, params: ast.Identifiers{"str", "c", "maxsplits"}},
&ternaryBuiltin{name: "strReplace", function: builtinStrReplace, params: ast.Identifiers{"str", "from", "to"}},
&unaryBuiltin{name: "isEmpty", function: builtinIsEmpty, params: ast.Identifiers{"str"}},
&binaryBuiltin{name: "equalsIgnoreCase", function: builtinEqualsIgnoreCase, params: ast.Identifiers{"str1", "str2"}},
&unaryBuiltin{name: "trim", function: builtinTrim, params: ast.Identifiers{"str"}},
&unaryBuiltin{name: "base64Decode", function: builtinBase64Decode, params: ast.Identifiers{"str"}},
&unaryBuiltin{name: "base64DecodeBytes", function: builtinBase64DecodeBytes, params: ast.Identifiers{"str"}},
Expand All @@ -2309,6 +2431,7 @@ var funcBuiltins = buildBuiltinMap([]builtin{
&unaryBuiltin{name: "decodeUTF8", function: builtinDecodeUTF8, params: ast.Identifiers{"arr"}},
&generalBuiltin{name: "sort", function: builtinSort, params: []generalBuiltinParameter{{name: "arr"}, {name: "keyF", defaultValue: functionID}}},
&generalBuiltin{name: "minArray", function: builtinMinArray, params: []generalBuiltinParameter{{name: "arr"}, {name: "keyF", defaultValue: functionID}}},
&generalBuiltin{name: "maxArray", function: builtinMaxArray, params: []generalBuiltinParameter{{name: "arr"}, {name: "keyF", defaultValue: functionID}}},
&unaryBuiltin{name: "native", function: builtinNative, params: ast.Identifiers{"x"}},
&unaryBuiltin{name: "sum", function: builtinSum, params: ast.Identifiers{"arr"}},
&binaryBuiltin{name: "contains", function: builtinContains, params: ast.Identifiers{"arr", "elem"}},
Expand Down
7 changes: 7 additions & 0 deletions linter/internal/types/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@ func newTypeGraph(importFunc ImportFunc) *typeGraph {
},
})

g.newPlaceholder()
g._placeholders[boolArrayType] = concreteTP(TypeDesc{
ArrayDesc: &arrayDesc{
furtherContain: []placeholderID{boolType},
},
})

g.newPlaceholder()
g._placeholders[anyObjectType] = concreteTP(TypeDesc{
ObjectDesc: anyObjectDesc,
Expand Down
1 change: 1 addition & 0 deletions linter/internal/types/placeholder.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
nullType
anyArrayType
numberArrayType
boolArrayType
anyObjectType
anyFunctionType
stdlibType
Expand Down
51 changes: 31 additions & 20 deletions linter/internal/types/stdlib.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,25 +72,26 @@ func prepareStdlib(g *typeGraph) {

// String Manipulation

"toString": g.newSimpleFuncType(stringType, "a"),
"codepoint": g.newSimpleFuncType(numberType, "str"),
"char": g.newSimpleFuncType(stringType, "n"),
"substr": g.newSimpleFuncType(stringType, "str", "from", "len"),
"findSubstr": g.newSimpleFuncType(numberArrayType, "pat", "str"),
"startsWith": g.newSimpleFuncType(boolType, "a", "b"),
"endsWith": g.newSimpleFuncType(boolType, "a", "b"),
"stripChars": g.newSimpleFuncType(stringType, "str", "chars"),
"lstripChars": g.newSimpleFuncType(stringType, "str", "chars"),
"rstripChars": g.newSimpleFuncType(stringType, "str", "chars"),
"split": g.newSimpleFuncType(arrayOfString, "str", "c"),
"splitLimit": g.newSimpleFuncType(arrayOfString, "str", "c", "maxsplits"),
"strReplace": g.newSimpleFuncType(stringType, "str", "from", "to"),
"asciiUpper": g.newSimpleFuncType(stringType, "str"),
"asciiLower": g.newSimpleFuncType(stringType, "str"),
"stringChars": g.newSimpleFuncType(stringType, "str"),
"format": g.newSimpleFuncType(stringType, "str", "vals"),
"isEmpty": g.newSimpleFuncType(boolType, "str"),
"trim": g.newSimpleFuncType(stringType, "str"),
"toString": g.newSimpleFuncType(stringType, "a"),
"codepoint": g.newSimpleFuncType(numberType, "str"),
"char": g.newSimpleFuncType(stringType, "n"),
"substr": g.newSimpleFuncType(stringType, "str", "from", "len"),
"findSubstr": g.newSimpleFuncType(numberArrayType, "pat", "str"),
"startsWith": g.newSimpleFuncType(boolType, "a", "b"),
"endsWith": g.newSimpleFuncType(boolType, "a", "b"),
"stripChars": g.newSimpleFuncType(stringType, "str", "chars"),
"lstripChars": g.newSimpleFuncType(stringType, "str", "chars"),
"rstripChars": g.newSimpleFuncType(stringType, "str", "chars"),
"split": g.newSimpleFuncType(arrayOfString, "str", "c"),
"splitLimit": g.newSimpleFuncType(arrayOfString, "str", "c", "maxsplits"),
"strReplace": g.newSimpleFuncType(stringType, "str", "from", "to"),
"asciiUpper": g.newSimpleFuncType(stringType, "str"),
"asciiLower": g.newSimpleFuncType(stringType, "str"),
"stringChars": g.newSimpleFuncType(stringType, "str"),
"format": g.newSimpleFuncType(stringType, "str", "vals"),
"isEmpty": g.newSimpleFuncType(boolType, "str"),
"equalsIgnoreCase": g.newSimpleFuncType(boolType, "str1", "str2"),
"trim": g.newSimpleFuncType(stringType, "str"),
// TODO(sbarzowski) Fix when they match the documentation
"escapeStringBash": g.newSimpleFuncType(stringType, "str_"),
"escapeStringDollars": g.newSimpleFuncType(stringType, "str_"),
Expand Down Expand Up @@ -141,8 +142,14 @@ func prepareStdlib(g *typeGraph) {
"sort": g.newFuncType(anyArrayType, []ast.Parameter{required("arr"), optional("keyF")}),
"uniq": g.newFuncType(anyArrayType, []ast.Parameter{required("arr"), optional("keyF")}),
"sum": g.newSimpleFuncType(numberType, "arr"),
"minArray": g.newSimpleFuncType(anyType, "arr"),
"minArray": g.newFuncType(anyArrayType, []ast.Parameter{required("arr"), optional("keyF")}),
"maxArray": g.newFuncType(anyArrayType, []ast.Parameter{required("arr"), optional("keyF")}),
"contains": g.newSimpleFuncType(boolType, "arr", "elem"),
// TODO these need test cases written by someone who understands how to make them
"all": g.newSimpleFuncType(boolArrayType, "arr"),
"any": g.newSimpleFuncType(boolArrayType, "arr"),
"remove": g.newSimpleFuncType(anyArrayType, "arr", "elem"),
"removeAt": g.newSimpleFuncType(anyArrayType, "arr", "i"),

// Sets

Expand All @@ -152,6 +159,10 @@ func prepareStdlib(g *typeGraph) {
"setDiff": g.newFuncType(anyArrayType, []ast.Parameter{required("a"), required("b"), optional("keyF")}),
"setMember": g.newFuncType(boolType, []ast.Parameter{required("x"), required("arr"), optional("keyF")}),

// Objects

"objectRemoveKey": g.newSimpleFuncType(anyObjectType, "obj", "key"),

// Encoding

"base64": g.newSimpleFuncType(stringType, "input"),
Expand Down
1 change: 1 addition & 0 deletions testdata/builtinEqualsIgnoreCase.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
true
1 change: 1 addition & 0 deletions testdata/builtinEqualsIgnoreCase.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
std.equalsIgnoreCase("foo", "FOO")
Empty file.
1 change: 1 addition & 0 deletions testdata/builtinEqualsIgnoreCase2.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
false
1 change: 1 addition & 0 deletions testdata/builtinEqualsIgnoreCase2.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
std.equalsIgnoreCase("foo", "bar")
Empty file.
1 change: 1 addition & 0 deletions testdata/builtinMaxArray.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
1 change: 1 addition & 0 deletions testdata/builtinMaxArray.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
std.maxArray([1,-1,0])
Empty file.
4 changes: 4 additions & 0 deletions testdata/builtinObjectRemoveKey.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"bar": 2,
"baz": 3
}
1 change: 1 addition & 0 deletions testdata/builtinObjectRemoveKey.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
std.objectRemoveKey({foo: 1, bar: 2, baz: 3}, "foo")
Empty file.
4 changes: 4 additions & 0 deletions testdata/builtinRemove.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[
1,
3
]
1 change: 1 addition & 0 deletions testdata/builtinRemove.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
std.remove([1,2,3],2)
Empty file.
4 changes: 4 additions & 0 deletions testdata/builtinRemoveAt.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[
1,
3
]
1 change: 1 addition & 0 deletions testdata/builtinRemoveAt.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
std.removeAt([1,2,3],1)
Empty file.

0 comments on commit 7b87efa

Please sign in to comment.