From 9ada769ce408a5ea892af3e30bb23f4bbea75df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Barzowski?= Date: Sun, 1 Mar 2020 20:19:23 +0100 Subject: [PATCH] Make golangci-lint happy Some of the suggestions are minor bug fixes (missing error handling). --- ast/ast.go | 14 +- ast/fodder.go | 2 +- ast/location.go | 5 +- builtins.go | 225 ++++++++++++++--------------- builtins_benchmark_test.go | 15 +- c-bindings/c-bindings.go | 14 +- cmd/dumpstdlibast/dumpstdlibast.go | 10 +- cmd/jsonnet/cmd.go | 49 +++++-- error_formatter.go | 2 +- internal/dump/dump.go | 89 ++++++------ internal/dump/utils.go | 28 ++-- internal/parser/lexer.go | 20 +-- internal/parser/lexer_test.go | 117 --------------- internal/parser/parser.go | 10 -- internal/program/desugarer.go | 5 +- interpreter.go | 17 +-- linter/jsonnet-lint/cmd.go | 5 +- linter/linter.go | 5 +- main_test.go | 16 +- testdata/std.sort4.golden | 6 +- thunks.go | 31 +--- value.go | 31 +--- 22 files changed, 290 insertions(+), 426 deletions(-) diff --git a/ast/ast.go b/ast/ast.go index 2bb6baa..5ba81a2 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -429,7 +429,8 @@ type Index struct { // When Index is being used, this is the fodder before the ']'. // When Id is being used, this is always empty. RightBracketFodder Fodder - Id *Identifier + //nolint: golint,stylecheck // keeping Id instead of ID for now to avoid breaking 3rd parties + Id *Identifier } // Slice represents an array slice a[begin:end:step]. @@ -576,9 +577,10 @@ type ObjectField struct { // If Method is set then Expr2 == Method.Body. // There is no base fodder in Method because there was no `function` // keyword. - Method *Function - Fodder1 Fodder - Expr1 Node // Not in scope of the object + Method *Function + Fodder1 Fodder + Expr1 Node // Not in scope of the object + //nolint: golint,stylecheck // keeping Id instead of ID for now to avoid breaking 3rd parties Id *Identifier Fodder2 Fodder OpFodder Fodder @@ -676,7 +678,8 @@ type SuperIndex struct { // If super.f, the fodder before the 'f' // If super[e], the fodder before the ']'. IDFodder Fodder - Id *Identifier + //nolint: golint,stylecheck // keeping Id instead of ID for now to avoid breaking 3rd parties + Id *Identifier } // InSuper represents the e in super construct. @@ -734,6 +737,7 @@ type Unary struct { // Var represents variables. type Var struct { NodeBase + //nolint: golint,stylecheck // keeping Id instead of ID for now to avoid breaking 3rd parties Id Identifier } diff --git a/ast/fodder.go b/ast/fodder.go index 22eaa13..ab6c2fe 100644 --- a/ast/fodder.go +++ b/ast/fodder.go @@ -87,7 +87,7 @@ func MakeFodderElement(kind FodderKind, blanks int, indent int, comment []string panic(fmt.Sprintf("FodderInterstitial but comment == %v.", comment)) } if kind == FodderParagraph && len(comment) == 0 { - panic(fmt.Sprintf("FodderParagraph but comment was empty")) + panic("FodderParagraph but comment was empty") } return FodderElement{Kind: kind, Blanks: blanks, Indent: indent, Comment: comment} } diff --git a/ast/location.go b/ast/location.go index 2ac8875..d99f48a 100644 --- a/ast/location.go +++ b/ast/location.go @@ -45,7 +45,10 @@ func (l *Location) String() string { return fmt.Sprintf("%v:%v", l.Line, l.Column) } -func locationBefore(a Location, b Location) bool { +// LocationBefore returns whether one code location +// refers to the location closer to the beginning +// of the file than the other one. +func LocationBefore(a Location, b Location) bool { if a.Line != b.Line { return a.Line < b.Line } diff --git a/builtins.go b/builtins.go index 37a8d1e..bafff2c 100644 --- a/builtins.go +++ b/builtins.go @@ -182,7 +182,7 @@ func builtinLength(i *interpreter, trace traceElement, x value) (value, error) { case valueString: num = x.length() case *valueFunction: - for _, param := range x.Parameters() { + for _, param := range x.parameters() { if param.defaultArg == nil { num++ } @@ -275,9 +275,7 @@ func builtinFlatMap(i *interpreter, trace traceElement, funcv, arrv value) (valu if err != nil { return nil, err } - for _, elem := range returned.elements { - elems = append(elems, elem) - } + elems = append(elems, returned.elements...) } return makeValueArray(elems), nil } @@ -295,13 +293,9 @@ func joinArrays(i *interpreter, trace traceElement, sep *valueArray, arr *valueA continue case *valueArray: if !first { - for _, subElem := range sep.elements { - result = append(result, subElem) - } - } - for _, subElem := range v.elements { - result = append(result, subElem) + result = append(result, sep.elements...) } + result = append(result, v.elements...) default: return nil, i.typeErrorSpecific(elemValue, &valueArray{}, trace) } @@ -435,14 +429,6 @@ func (d *sortData) Sort() (err error) { return } -func arrayFromThunks(vs []value) *valueArray { - thunks := make([]*cachedThunk, len(vs)) - for i := range vs { - thunks[i] = readyThunk(vs[i]) - } - return makeValueArray(thunks) -} - func builtinSort(i *interpreter, trace traceElement, arguments []value) (value, error) { arrv := arguments[0] keyFv := arguments[1] @@ -468,7 +454,10 @@ func builtinSort(i *interpreter, trace traceElement, arguments []value) (value, } } - data.Sort() + err = data.Sort() + if err != nil { + return nil, err + } return makeValueArray(data.thunks), nil } @@ -705,8 +694,8 @@ func builtinBase64(i *interpreter, trace traceElement, input value) (value, erro return nil, err } - runes := []rune(vStr.getGoString()) - for _, r := range runes { + str := vStr.getGoString() + for _, r := range str { n := int(r) msg, ok := sanityCheck(n) if !ok { @@ -714,7 +703,7 @@ func builtinBase64(i *interpreter, trace traceElement, input value) (value, erro } } - byteArr = []byte(string(vStr.getGoString())) + byteArr = []byte(str) case *valueArray: vArr, err := i.getArray(input, trace) if err != nil { @@ -1227,9 +1216,9 @@ func flattenArgs(args callArguments, params []namedParameter, defaults []value) type unaryBuiltinFunc func(*interpreter, traceElement, value) (value, error) type unaryBuiltin struct { - name ast.Identifier - function unaryBuiltinFunc - parameters ast.Identifiers + name ast.Identifier + function unaryBuiltinFunc + params ast.Identifiers } func getBuiltinTrace(trace traceElement, name ast.Identifier) traceElement { @@ -1238,7 +1227,7 @@ func getBuiltinTrace(trace traceElement, name ast.Identifier) traceElement { } func (b *unaryBuiltin) evalCall(args callArguments, i *interpreter, trace traceElement) (value, error) { - flatArgs := flattenArgs(args, b.Parameters(), []value{}) + flatArgs := flattenArgs(args, b.parameters(), []value{}) builtinTrace := getBuiltinTrace(trace, b.name) x, err := flatArgs[0].getValue(i, trace) if err != nil { @@ -1247,10 +1236,10 @@ func (b *unaryBuiltin) evalCall(args callArguments, i *interpreter, trace traceE return b.function(i, builtinTrace, x) } -func (b *unaryBuiltin) Parameters() []namedParameter { - ret := make([]namedParameter, len(b.parameters)) +func (b *unaryBuiltin) parameters() []namedParameter { + ret := make([]namedParameter, len(b.params)) for i := range ret { - ret[i].name = b.parameters[i] + ret[i].name = b.params[i] } return ret } @@ -1262,13 +1251,13 @@ func (b *unaryBuiltin) Name() ast.Identifier { type binaryBuiltinFunc func(*interpreter, traceElement, value, value) (value, error) type binaryBuiltin struct { - name ast.Identifier - function binaryBuiltinFunc - parameters ast.Identifiers + name ast.Identifier + function binaryBuiltinFunc + params ast.Identifiers } func (b *binaryBuiltin) evalCall(args callArguments, i *interpreter, trace traceElement) (value, error) { - flatArgs := flattenArgs(args, b.Parameters(), []value{}) + flatArgs := flattenArgs(args, b.parameters(), []value{}) builtinTrace := getBuiltinTrace(trace, b.name) x, err := flatArgs[0].getValue(i, trace) if err != nil { @@ -1281,10 +1270,10 @@ func (b *binaryBuiltin) evalCall(args callArguments, i *interpreter, trace trace return b.function(i, builtinTrace, x, y) } -func (b *binaryBuiltin) Parameters() []namedParameter { - ret := make([]namedParameter, len(b.parameters)) +func (b *binaryBuiltin) parameters() []namedParameter { + ret := make([]namedParameter, len(b.params)) for i := range ret { - ret[i].name = b.parameters[i] + ret[i].name = b.params[i] } return ret } @@ -1296,13 +1285,13 @@ func (b *binaryBuiltin) Name() ast.Identifier { type ternaryBuiltinFunc func(*interpreter, traceElement, value, value, value) (value, error) type ternaryBuiltin struct { - name ast.Identifier - function ternaryBuiltinFunc - parameters ast.Identifiers + name ast.Identifier + function ternaryBuiltinFunc + params ast.Identifiers } func (b *ternaryBuiltin) evalCall(args callArguments, i *interpreter, trace traceElement) (value, error) { - flatArgs := flattenArgs(args, b.Parameters(), []value{}) + flatArgs := flattenArgs(args, b.parameters(), []value{}) builtinTrace := getBuiltinTrace(trace, b.name) x, err := flatArgs[0].getValue(i, trace) if err != nil { @@ -1319,10 +1308,10 @@ func (b *ternaryBuiltin) evalCall(args callArguments, i *interpreter, trace trac return b.function(i, builtinTrace, x, y, z) } -func (b *ternaryBuiltin) Parameters() []namedParameter { - ret := make([]namedParameter, len(b.parameters)) +func (b *ternaryBuiltin) parameters() []namedParameter { + ret := make([]namedParameter, len(b.params)) for i := range ret { - ret[i].name = b.parameters[i] + ret[i].name = b.params[i] } return ret } @@ -1345,16 +1334,16 @@ type generalBuiltinParameter struct { // have optional parameters. The optional ones have non-nil defaultValues // at the same index. type generalBuiltin struct { - name ast.Identifier - parameters []generalBuiltinParameter - function generalBuiltinFunc + name ast.Identifier + params []generalBuiltinParameter + function generalBuiltinFunc } -func (b *generalBuiltin) Parameters() []namedParameter { - ret := make([]namedParameter, len(b.parameters)) +func (b *generalBuiltin) parameters() []namedParameter { + ret := make([]namedParameter, len(b.params)) for i := range ret { - ret[i].name = b.parameters[i].name - if b.parameters[i].defaultValue != nil { + ret[i].name = b.params[i].name + if b.params[i].defaultValue != nil { // This is not actually used because the defaultValue is used instead. // The only reason we don't leave it nil is because the checkArguments // function uses the non-nil status to indicate that the parameter @@ -1366,9 +1355,9 @@ func (b *generalBuiltin) Parameters() []namedParameter { } func (b *generalBuiltin) defaultValues() []value { - ret := make([]value, len(b.parameters)) + ret := make([]value, len(b.params)) for i := range ret { - ret[i] = b.parameters[i].defaultValue + ret[i] = b.params[i].defaultValue } return ret } @@ -1378,7 +1367,7 @@ func (b *generalBuiltin) Name() ast.Identifier { } func (b *generalBuiltin) evalCall(args callArguments, i *interpreter, trace traceElement) (value, error) { - flatArgs := flattenArgs(args, b.Parameters(), b.defaultValues()) + flatArgs := flattenArgs(args, b.parameters(), b.defaultValues()) builtinTrace := getBuiltinTrace(trace, b.name) values := make([]value, len(flatArgs)) for j := 0; j < len(values); j++ { @@ -1393,38 +1382,38 @@ func (b *generalBuiltin) evalCall(args callArguments, i *interpreter, trace trac // End of builtin utils -var builtinID = &unaryBuiltin{name: "id", function: builtinIdentity, parameters: ast.Identifiers{"x"}} +var builtinID = &unaryBuiltin{name: "id", function: builtinIdentity, params: ast.Identifiers{"x"}} var functionID = &valueFunction{ec: builtinID} var bopBuiltins = []*binaryBuiltin{ // Note that % and `in` are desugared instead of being handled here - ast.BopMult: &binaryBuiltin{name: "operator*", function: builtinMult, parameters: ast.Identifiers{"x", "y"}}, - ast.BopDiv: &binaryBuiltin{name: "operator/", function: builtinDiv, parameters: ast.Identifiers{"x", "y"}}, + ast.BopMult: &binaryBuiltin{name: "operator*", function: builtinMult, params: ast.Identifiers{"x", "y"}}, + ast.BopDiv: &binaryBuiltin{name: "operator/", function: builtinDiv, params: ast.Identifiers{"x", "y"}}, - ast.BopPlus: &binaryBuiltin{name: "operator+", function: builtinPlus, parameters: ast.Identifiers{"x", "y"}}, - ast.BopMinus: &binaryBuiltin{name: "operator-", function: builtinMinus, parameters: ast.Identifiers{"x", "y"}}, + ast.BopPlus: &binaryBuiltin{name: "operator+", function: builtinPlus, params: ast.Identifiers{"x", "y"}}, + ast.BopMinus: &binaryBuiltin{name: "operator-", function: builtinMinus, params: ast.Identifiers{"x", "y"}}, - ast.BopShiftL: &binaryBuiltin{name: "operator<<", function: builtinShiftL, parameters: ast.Identifiers{"x", "y"}}, - ast.BopShiftR: &binaryBuiltin{name: "operator>>", function: builtinShiftR, parameters: ast.Identifiers{"x", "y"}}, + ast.BopShiftL: &binaryBuiltin{name: "operator<<", function: builtinShiftL, params: ast.Identifiers{"x", "y"}}, + ast.BopShiftR: &binaryBuiltin{name: "operator>>", function: builtinShiftR, params: ast.Identifiers{"x", "y"}}, - ast.BopGreater: &binaryBuiltin{name: "operator>", function: builtinGreater, parameters: ast.Identifiers{"x", "y"}}, - ast.BopGreaterEq: &binaryBuiltin{name: "operator>=", function: builtinGreaterEq, parameters: ast.Identifiers{"x", "y"}}, - ast.BopLess: &binaryBuiltin{name: "operator<,", function: builtinLess, parameters: ast.Identifiers{"x", "y"}}, - ast.BopLessEq: &binaryBuiltin{name: "operator<=", function: builtinLessEq, parameters: ast.Identifiers{"x", "y"}}, + ast.BopGreater: &binaryBuiltin{name: "operator>", function: builtinGreater, params: ast.Identifiers{"x", "y"}}, + ast.BopGreaterEq: &binaryBuiltin{name: "operator>=", function: builtinGreaterEq, params: ast.Identifiers{"x", "y"}}, + ast.BopLess: &binaryBuiltin{name: "operator<,", function: builtinLess, params: ast.Identifiers{"x", "y"}}, + ast.BopLessEq: &binaryBuiltin{name: "operator<=", function: builtinLessEq, params: ast.Identifiers{"x", "y"}}, - ast.BopManifestEqual: &binaryBuiltin{name: "operator==", function: builtinEquals, parameters: ast.Identifiers{"x", "y"}}, - ast.BopManifestUnequal: &binaryBuiltin{name: "operator!=", function: builtinNotEquals, parameters: ast.Identifiers{"x", "y"}}, // Special case + ast.BopManifestEqual: &binaryBuiltin{name: "operator==", function: builtinEquals, params: ast.Identifiers{"x", "y"}}, + ast.BopManifestUnequal: &binaryBuiltin{name: "operator!=", function: builtinNotEquals, params: ast.Identifiers{"x", "y"}}, // Special case - ast.BopBitwiseAnd: &binaryBuiltin{name: "operator&", function: builtinBitwiseAnd, parameters: ast.Identifiers{"x", "y"}}, - ast.BopBitwiseXor: &binaryBuiltin{name: "operator^", function: builtinBitwiseXor, parameters: ast.Identifiers{"x", "y"}}, - ast.BopBitwiseOr: &binaryBuiltin{name: "operator|", function: builtinBitwiseOr, parameters: ast.Identifiers{"x", "y"}}, + ast.BopBitwiseAnd: &binaryBuiltin{name: "operator&", function: builtinBitwiseAnd, params: ast.Identifiers{"x", "y"}}, + ast.BopBitwiseXor: &binaryBuiltin{name: "operator^", function: builtinBitwiseXor, params: ast.Identifiers{"x", "y"}}, + ast.BopBitwiseOr: &binaryBuiltin{name: "operator|", function: builtinBitwiseOr, params: ast.Identifiers{"x", "y"}}, } var uopBuiltins = []*unaryBuiltin{ - ast.UopNot: &unaryBuiltin{name: "operator!", function: builtinNegation, parameters: ast.Identifiers{"x"}}, - ast.UopBitwiseNot: &unaryBuiltin{name: "operator~", function: builtinBitNeg, parameters: ast.Identifiers{"x"}}, - ast.UopPlus: &unaryBuiltin{name: "operator+ (unary)", function: builtinUnaryPlus, parameters: ast.Identifiers{"x"}}, - ast.UopMinus: &unaryBuiltin{name: "operator- (unary)", function: builtinUnaryMinus, parameters: ast.Identifiers{"x"}}, + ast.UopNot: &unaryBuiltin{name: "operator!", function: builtinNegation, params: ast.Identifiers{"x"}}, + ast.UopBitwiseNot: &unaryBuiltin{name: "operator~", function: builtinBitNeg, params: ast.Identifiers{"x"}}, + ast.UopPlus: &unaryBuiltin{name: "operator+ (unary)", function: builtinUnaryPlus, params: ast.Identifiers{"x"}}, + ast.UopMinus: &unaryBuiltin{name: "operator- (unary)", function: builtinUnaryMinus, params: ast.Identifiers{"x"}}, } func buildBuiltinMap(builtins []builtin) map[string]evalCallable { @@ -1437,51 +1426,51 @@ func buildBuiltinMap(builtins []builtin) map[string]evalCallable { var funcBuiltins = buildBuiltinMap([]builtin{ builtinID, - &unaryBuiltin{name: "extVar", function: builtinExtVar, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "length", function: builtinLength, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "toString", function: builtinToString, parameters: ast.Identifiers{"a"}}, - &binaryBuiltin{name: "trace", function: builtinTrace, parameters: ast.Identifiers{"str", "rest"}}, - &binaryBuiltin{name: "makeArray", function: builtinMakeArray, parameters: ast.Identifiers{"sz", "func"}}, - &binaryBuiltin{name: "flatMap", function: builtinFlatMap, parameters: ast.Identifiers{"func", "arr"}}, - &binaryBuiltin{name: "join", function: builtinJoin, parameters: ast.Identifiers{"sep", "arr"}}, - &unaryBuiltin{name: "reverse", function: builtinReverse, parameters: ast.Identifiers{"arr"}}, - &binaryBuiltin{name: "filter", function: builtinFilter, parameters: ast.Identifiers{"func", "arr"}}, - &binaryBuiltin{name: "range", function: builtinRange, parameters: ast.Identifiers{"from", "to"}}, - &binaryBuiltin{name: "primitiveEquals", function: primitiveEquals, parameters: ast.Identifiers{"x", "y"}}, - &binaryBuiltin{name: "equals", function: builtinEquals, parameters: ast.Identifiers{"x", "y"}}, - &binaryBuiltin{name: "objectFieldsEx", function: builtinObjectFieldsEx, parameters: ast.Identifiers{"obj", "hidden"}}, - &ternaryBuiltin{name: "objectHasEx", function: builtinObjectHasEx, parameters: ast.Identifiers{"obj", "fname", "hidden"}}, - &unaryBuiltin{name: "type", function: builtinType, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "char", function: builtinChar, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "codepoint", function: builtinCodepoint, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "ceil", function: builtinCeil, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "floor", function: builtinFloor, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "sqrt", function: builtinSqrt, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "sin", function: builtinSin, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "cos", function: builtinCos, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "tan", function: builtinTan, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "asin", function: builtinAsin, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "acos", function: builtinAcos, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "atan", function: builtinAtan, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "log", function: builtinLog, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "exp", function: builtinExp, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "mantissa", function: builtinMantissa, parameters: ast.Identifiers{"x"}}, - &unaryBuiltin{name: "exponent", function: builtinExponent, parameters: ast.Identifiers{"x"}}, - &binaryBuiltin{name: "pow", function: builtinPow, parameters: ast.Identifiers{"base", "exp"}}, - &binaryBuiltin{name: "modulo", function: builtinModulo, parameters: ast.Identifiers{"x", "y"}}, - &unaryBuiltin{name: "md5", function: builtinMd5, parameters: ast.Identifiers{"x"}}, - &ternaryBuiltin{name: "substr", function: builtinSubstr, parameters: ast.Identifiers{"str", "from", "len"}}, - &ternaryBuiltin{name: "splitLimit", function: builtinSplitLimit, parameters: ast.Identifiers{"str", "c", "maxsplits"}}, - &ternaryBuiltin{name: "strReplace", function: builtinStrReplace, parameters: ast.Identifiers{"str", "from", "to"}}, - &unaryBuiltin{name: "base64Decode", function: builtinBase64Decode, parameters: ast.Identifiers{"str"}}, - &unaryBuiltin{name: "base64DecodeBytes", function: builtinBase64DecodeBytes, parameters: ast.Identifiers{"str"}}, - &unaryBuiltin{name: "parseJson", function: builtinParseJSON, parameters: ast.Identifiers{"str"}}, - &unaryBuiltin{name: "base64", function: builtinBase64, parameters: ast.Identifiers{"input"}}, - &unaryBuiltin{name: "encodeUTF8", function: builtinEncodeUTF8, parameters: ast.Identifiers{"str"}}, - &unaryBuiltin{name: "decodeUTF8", function: builtinDecodeUTF8, parameters: ast.Identifiers{"arr"}}, - &generalBuiltin{name: "sort", function: builtinSort, parameters: []generalBuiltinParameter{{name: "arr"}, {name: "keyF", defaultValue: functionID}}}, - &unaryBuiltin{name: "native", function: builtinNative, parameters: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "extVar", function: builtinExtVar, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "length", function: builtinLength, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "toString", function: builtinToString, params: ast.Identifiers{"a"}}, + &binaryBuiltin{name: "trace", function: builtinTrace, params: ast.Identifiers{"str", "rest"}}, + &binaryBuiltin{name: "makeArray", function: builtinMakeArray, params: ast.Identifiers{"sz", "func"}}, + &binaryBuiltin{name: "flatMap", function: builtinFlatMap, params: ast.Identifiers{"func", "arr"}}, + &binaryBuiltin{name: "join", function: builtinJoin, params: ast.Identifiers{"sep", "arr"}}, + &unaryBuiltin{name: "reverse", function: builtinReverse, params: ast.Identifiers{"arr"}}, + &binaryBuiltin{name: "filter", function: builtinFilter, params: ast.Identifiers{"func", "arr"}}, + &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"}}, + &unaryBuiltin{name: "type", function: builtinType, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "char", function: builtinChar, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "codepoint", function: builtinCodepoint, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "ceil", function: builtinCeil, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "floor", function: builtinFloor, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "sqrt", function: builtinSqrt, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "sin", function: builtinSin, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "cos", function: builtinCos, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "tan", function: builtinTan, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "asin", function: builtinAsin, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "acos", function: builtinAcos, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "atan", function: builtinAtan, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "log", function: builtinLog, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "exp", function: builtinExp, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "mantissa", function: builtinMantissa, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "exponent", function: builtinExponent, params: ast.Identifiers{"x"}}, + &binaryBuiltin{name: "pow", function: builtinPow, params: ast.Identifiers{"base", "exp"}}, + &binaryBuiltin{name: "modulo", function: builtinModulo, params: ast.Identifiers{"x", "y"}}, + &unaryBuiltin{name: "md5", function: builtinMd5, params: ast.Identifiers{"x"}}, + &ternaryBuiltin{name: "substr", function: builtinSubstr, params: ast.Identifiers{"str", "from", "len"}}, + &ternaryBuiltin{name: "splitLimit", function: builtinSplitLimit, params: ast.Identifiers{"str", "c", "maxsplits"}}, + &ternaryBuiltin{name: "strReplace", function: builtinStrReplace, params: ast.Identifiers{"str", "from", "to"}}, + &unaryBuiltin{name: "base64Decode", function: builtinBase64Decode, params: ast.Identifiers{"str"}}, + &unaryBuiltin{name: "base64DecodeBytes", function: builtinBase64DecodeBytes, params: ast.Identifiers{"str"}}, + &unaryBuiltin{name: "parseJson", function: builtinParseJSON, params: ast.Identifiers{"str"}}, + &unaryBuiltin{name: "base64", function: builtinBase64, params: ast.Identifiers{"input"}}, + &unaryBuiltin{name: "encodeUTF8", function: builtinEncodeUTF8, params: ast.Identifiers{"str"}}, + &unaryBuiltin{name: "decodeUTF8", function: builtinDecodeUTF8, params: ast.Identifiers{"arr"}}, + &generalBuiltin{name: "sort", function: builtinSort, params: []generalBuiltinParameter{{name: "arr"}, {name: "keyF", defaultValue: functionID}}}, + &unaryBuiltin{name: "native", function: builtinNative, params: ast.Identifiers{"x"}}, // internal - &unaryBuiltin{name: "$objectFlatMerge", function: builtinUglyObjectFlatMerge, parameters: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "$objectFlatMerge", function: builtinUglyObjectFlatMerge, params: ast.Identifiers{"x"}}, }) diff --git a/builtins_benchmark_test.go b/builtins_benchmark_test.go index 68d9cb4..7585d4c 100644 --- a/builtins_benchmark_test.go +++ b/builtins_benchmark_test.go @@ -8,18 +8,15 @@ import ( "testing" ) -var jsonnetPath string -var outputPassthru bool - -func init() { - flag.StringVar(&jsonnetPath, "jsonnetPath", "./jsonnet", "Path to jsonnet binary") - flag.BoolVar(&outputPassthru, "outputPassthru", false, "Pass stdout/err from jsonnet") -} +var ( + jsonnetPath = flag.String("jsonnetPath", "./jsonnet", "Path to jsonnet binary") + outputPassthru = flag.Bool("outputPassthru", false, "Pass stdout/err from jsonnet") +) func RunBenchmark(b *testing.B, name string) { for n := 0; n < b.N; n++ { - cmd := exec.Command(jsonnetPath, fmt.Sprintf("./builtin-benchmarks/%s.jsonnet", name)) - if outputPassthru { + cmd := exec.Command(*jsonnetPath, fmt.Sprintf("./builtin-benchmarks/%s.jsonnet", name)) + if *outputPassthru { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr } diff --git a/c-bindings/c-bindings.go b/c-bindings/c-bindings.go index ac1d18f..970d581 100644 --- a/c-bindings/c-bindings.go +++ b/c-bindings/c-bindings.go @@ -103,7 +103,7 @@ func jsonnet_make() *C.struct_JsonnetVm { id, err := handles.make(newVM) if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) + fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } @@ -113,7 +113,7 @@ func jsonnet_make() *C.struct_JsonnetVm { //export jsonnet_destroy func jsonnet_destroy(vmRef *C.struct_JsonnetVm) { if err := handles.free(uint32(vmRef.id)); err != nil { - fmt.Fprintf(os.Stderr, err.Error()) + fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } @@ -124,14 +124,14 @@ func getVM(vmRef *C.struct_JsonnetVm) *vm { ref, err := handles.get(uint32(vmRef.id)) if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) + fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } v, ok := ref.(*vm) if !ok { - fmt.Fprintf(os.Stderr, "provided handle has a different type") + fmt.Fprintln(os.Stderr, "provided handle has a different type") os.Exit(1) } @@ -413,7 +413,7 @@ func jsonnet_json_destroy(vmRef *C.struct_JsonnetVm, v *C.struct_JsonnetJsonValu } if err := handles.free(uint32(v.id)); err != nil { - fmt.Fprintf(os.Stderr, err.Error()) + fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } @@ -424,7 +424,7 @@ func createJSONValue(vmRef *C.struct_JsonnetVm, val interface{}) *C.struct_Jsonn id, err := handles.make(&jsonValue{val: val}) if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) + fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } @@ -435,7 +435,7 @@ func getJSONValue(jsonRef *C.struct_JsonnetJsonValue) *jsonValue { ref, err := handles.get(uint32(jsonRef.id)) if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) + fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } diff --git a/cmd/dumpstdlibast/dumpstdlibast.go b/cmd/dumpstdlibast/dumpstdlibast.go index 6627c4f..c9b5d43 100644 --- a/cmd/dumpstdlibast/dumpstdlibast.go +++ b/cmd/dumpstdlibast/dumpstdlibast.go @@ -44,8 +44,14 @@ func main() { ast := dump.Sdump(node) dst := os.Stdout - dst.WriteString(header) - dst.WriteString(ast) + _, err = dst.WriteString(header) + if err != nil { + panic(err) + } + _, err = dst.WriteString(ast) + if err != nil { + panic(err) + } } var header = ` diff --git a/cmd/jsonnet/cmd.go b/cmd/jsonnet/cmd.go index 0c6a9d2..2503ed0 100644 --- a/cmd/jsonnet/cmd.go +++ b/cmd/jsonnet/cmd.go @@ -341,7 +341,7 @@ func readInput(config config, filename *string) (input string, err error) { return } -func writeMultiOutputFiles(output map[string]string, outputDir, outputFile string, createDirs bool) error { +func writeMultiOutputFiles(output map[string]string, outputDir, outputFile string, createDirs bool) (err error) { // If multiple file output is used, then iterate over each string from // the sequence of strings returned by jsonnet_evaluate_snippet_multi, // construct pairs of filename and content, and write each output file. @@ -351,12 +351,15 @@ func writeMultiOutputFiles(output map[string]string, outputDir, outputFile strin if outputFile == "" { manifest = os.Stdout } else { - var err error manifest, err = os.Create(outputFile) if err != nil { return err } - defer manifest.Close() + defer func() { + if ferr := manifest.Close(); err != nil { + err = ferr + } + }() } // Iterate through the map in order. @@ -401,7 +404,11 @@ func writeMultiOutputFiles(output map[string]string, outputDir, outputFile strin if err != nil { return err } - defer f.Close() + defer func() { + if ferr := f.Close(); err != nil { + err = ferr + } + }() _, err = f.WriteString(newContent) if err != nil { @@ -413,18 +420,21 @@ func writeMultiOutputFiles(output map[string]string, outputDir, outputFile strin } // writeOutputStream writes the output as a YAML stream. -func writeOutputStream(output []string, outputFile string) error { +func writeOutputStream(output []string, outputFile string) (err error) { var f *os.File if outputFile == "" { f = os.Stdout } else { - var err error f, err = os.Create(outputFile) if err != nil { return err } - defer f.Close() + defer func() { + if ferr := f.Close(); err != nil { + err = ferr + } + }() } for _, doc := range output { @@ -448,7 +458,7 @@ func writeOutputStream(output []string, outputFile string) error { return nil } -func writeOutputFile(output string, outputFile string, createDirs bool) error { +func writeOutputFile(output string, outputFile string, createDirs bool) (err error) { if outputFile == "" { fmt.Print(output) return nil @@ -460,11 +470,15 @@ func writeOutputFile(output string, outputFile string, createDirs bool) error { } } - f, err := os.Create(outputFile) - if err != nil { + f, createErr := os.Create(outputFile) + if createErr != nil { return err } - defer f.Close() + defer func() { + if ferr := f.Close(); err != nil { + err = ferr + } + }() _, err = f.WriteString(output) return err @@ -478,7 +492,10 @@ func main() { if err != nil { log.Fatal(err) } - pprof.StartCPUProfile(f) + err = pprof.StartCPUProfile(f) + if err != nil { + log.Fatal(err) + } defer pprof.StopCPUProfile() } @@ -519,7 +536,7 @@ func main() { if len(config.inputFiles) != 1 { // Should already have been caught by processArgs. - panic(fmt.Sprintf("Internal error: expected a single input file.")) + panic("Internal error: expected a single input file.") } filename := config.inputFiles[0] input, err := readInput(config, &filename) @@ -560,7 +577,11 @@ func main() { if err := pprof.WriteHeapProfile(f); err != nil { log.Fatal("could not write memory profile: ", err) } - f.Close() + defer func() { + if err := f.Close(); err != nil { + log.Fatal("Failed to close the memprofile: ", err) + } + }() } if err != nil { diff --git a/error_formatter.go b/error_formatter.go index 042e2c0..f9a3976 100644 --- a/error_formatter.go +++ b/error_formatter.go @@ -105,7 +105,7 @@ func (ef *termErrorFormatter) showCode(buf *bytes.Buffer, loc ast.LocationRange) beginning := ast.LineBeginning(&loc) ending := ast.LineEnding(&loc) fmt.Fprintf(buf, "%v", ef.sp.GetSnippet(beginning)) - errFprintf(buf, "%v", ef.sp.GetSnippet(loc)) + errFprintf(buf, "%v", ef.sp.GetSnippet(loc)) //nolint:errcheck fmt.Fprintf(buf, "%v", ef.sp.GetSnippet(ending)) buf.WriteByte('\n') } diff --git a/internal/dump/dump.go b/internal/dump/dump.go index 53345aa..308e294 100644 --- a/internal/dump/dump.go +++ b/internal/dump/dump.go @@ -29,7 +29,7 @@ import ( "strconv" ) -var packageNameStripperRegexp = regexp.MustCompile("\\b[a-zA-Z_]+[a-zA-Z_0-9]+\\.") +var packageNameStripperRegexp = regexp.MustCompile(`\b[a-zA-Z_]+[a-zA-Z_0-9]+\.`) // Options represents configuration option type Options struct { @@ -59,16 +59,22 @@ type dumpState struct { reusedPointers []uintptr primitivePointers []uintptr - currentPointerName string - homePackageRegexp *regexp.Regexp + homePackageRegexp *regexp.Regexp +} + +func mustWrite(w io.Writer, data []byte) { + _, err := w.Write(data) + if err != nil { + panic(err) + } } func (s *dumpState) indent() { - s.w.Write(bytes.Repeat([]byte("\t"), s.depth)) + mustWrite(s.w, bytes.Repeat([]byte("\t"), s.depth)) } func (s *dumpState) newline() { - s.w.Write([]byte("\n")) + mustWrite(s.w, []byte("\n")) } func (s *dumpState) dumpType(v reflect.Value) { @@ -78,34 +84,34 @@ func (s *dumpState) dumpType(v reflect.Value) { } else if s.homePackageRegexp != nil { typeName = s.homePackageRegexp.ReplaceAllLiteralString(typeName, "") } - s.w.Write([]byte(typeName)) + mustWrite(s.w, []byte(typeName)) } func (s *dumpState) dumpSlice(v reflect.Value) { s.dumpType(v) numEntries := v.Len() if numEntries == 0 { - s.w.Write([]byte("{}")) + mustWrite(s.w, []byte("{}")) return } - s.w.Write([]byte("{")) + mustWrite(s.w, []byte("{")) s.newline() s.depth++ for i := 0; i < numEntries; i++ { s.indent() s.dumpVal(v.Index(i)) - s.w.Write([]byte(",")) + mustWrite(s.w, []byte(",")) s.newline() } s.depth-- s.indent() - s.w.Write([]byte("}")) + mustWrite(s.w, []byte("}")) } func (s *dumpState) dumpStruct(v reflect.Value) { dumpPreamble := func() { s.dumpType(v) - s.w.Write([]byte("{")) + mustWrite(s.w, []byte("{")) s.newline() s.depth++ } @@ -122,26 +128,26 @@ func (s *dumpState) dumpStruct(v reflect.Value) { preambleDumped = true } s.indent() - s.w.Write([]byte(vtf.Name)) - s.w.Write([]byte(": ")) + mustWrite(s.w, []byte(vtf.Name)) + mustWrite(s.w, []byte(": ")) s.dumpVal(v.Field(i)) - s.w.Write([]byte(",")) + mustWrite(s.w, []byte(",")) s.newline() } if preambleDumped { s.depth-- s.indent() - s.w.Write([]byte("}")) + mustWrite(s.w, []byte("}")) } else { // There were no fields dumped s.dumpType(v) - s.w.Write([]byte("{}")) + mustWrite(s.w, []byte("{}")) } } func (s *dumpState) dumpMap(v reflect.Value) { s.dumpType(v) - s.w.Write([]byte("{")) + mustWrite(s.w, []byte("{")) s.newline() s.depth++ keys := v.MapKeys() @@ -149,14 +155,14 @@ func (s *dumpState) dumpMap(v reflect.Value) { for _, key := range keys { s.indent() s.dumpVal(key) - s.w.Write([]byte(": ")) + mustWrite(s.w, []byte(": ")) s.dumpVal(v.MapIndex(key)) - s.w.Write([]byte(",")) + mustWrite(s.w, []byte(",")) s.newline() } s.depth-- s.indent() - s.w.Write([]byte("}")) + mustWrite(s.w, []byte("}")) } func (s *dumpState) dump(value interface{}) { @@ -164,7 +170,7 @@ func (s *dumpState) dump(value interface{}) { if s.config.VariableDescription != "" { fmt.Fprintf(s.w, "\n// %s\n", s.config.VariableDescription) } - s.w.Write([]byte("var " + s.config.VariableName + " = ")) + mustWrite(s.w, []byte("var "+s.config.VariableName+" = ")) } if value == nil { @@ -194,11 +200,11 @@ func (s *dumpState) dump(value interface{}) { s.dumpVal(v) s.w = oldWriter if buf.Len() > 100 { - s.w.Write([]byte("_" + s.config.VariableName)) + mustWrite(s.w, []byte("_"+s.config.VariableName)) s.newline() - s.w.Write([]byte("var _" + s.config.VariableName + " = ")) + mustWrite(s.w, []byte("var _"+s.config.VariableName+" = ")) } - s.w.Write(buf.Bytes()) + mustWrite(s.w, buf.Bytes()) } s.newline() } @@ -206,7 +212,7 @@ func (s *dumpState) dump(value interface{}) { func (s *dumpState) printPrimitivePointer(value reflect.Value, pointerName string) { v := deInterface(value) - s.w.Write([]byte("var " + pointerName + "Var" + " = ")) + mustWrite(s.w, []byte("var "+pointerName+"Var"+" = ")) switch v.Kind() { case reflect.Bool: printBool(s.w, v.Bool()) @@ -244,11 +250,11 @@ func (s *dumpState) printPrimitivePointer(value reflect.Value, pointerName strin printComplex(s.w, v.Complex(), 64) case reflect.String: - s.w.Write([]byte(strconv.Quote(v.String()))) + mustWrite(s.w, []byte(strconv.Quote(v.String()))) } s.newline() - s.w.Write([]byte("var " + pointerName + " = &" + pointerName + "Var")) + mustWrite(s.w, []byte("var "+pointerName+" = &"+pointerName+"Var")) s.newline() } @@ -263,7 +269,7 @@ func (s *dumpState) dumpPrimitivePointerVal(value reflect.Value) { case reflect.Invalid: // Do nothing. We should never get here since invalid has already // been handled above. - s.w.Write([]byte("")) + mustWrite(s.w, []byte("")) case reflect.Slice: if v.IsNil() { @@ -310,7 +316,7 @@ func (s *dumpState) dumpReusedPointerVal(value reflect.Value) { case reflect.Invalid: // Do nothing. We should never get here since invalid has already // been handled above. - s.w.Write([]byte("")) + mustWrite(s.w, []byte("")) case reflect.Slice: if v.IsNil() { @@ -338,7 +344,7 @@ func (s *dumpState) dumpReusedPointerVal(value reflect.Value) { case reflect.Ptr: pointerName, isReused, isPrimitive, isFirstVisit := s.nameForPointer(v), s.isReusedPointer(v), s.isPrimitivePointer(v), s.visitPointerAndCheckIfFirstTime(v) if isReused && !isPrimitive && isFirstVisit { - s.w.Write([]byte("var " + pointerName + " = &")) + mustWrite(s.w, []byte("var "+pointerName+" = &")) s.dumpVal(v.Elem()) s.newline() } else { @@ -349,7 +355,7 @@ func (s *dumpState) dumpReusedPointerVal(value reflect.Value) { func (s *dumpState) dumpVal(value reflect.Value) { if value.Kind() == reflect.Ptr && value.IsNil() { - s.w.Write([]byte("nil")) + mustWrite(s.w, []byte("nil")) return } @@ -359,7 +365,7 @@ func (s *dumpState) dumpVal(value reflect.Value) { case reflect.Invalid: // Do nothing. We should never get here since invalid has already // been handled above. - s.w.Write([]byte("")) + mustWrite(s.w, []byte("")) case reflect.Bool: printBool(s.w, v.Bool()) @@ -397,7 +403,7 @@ func (s *dumpState) dumpVal(value reflect.Value) { printComplex(s.w, v.Complex(), 64) case reflect.String: - s.w.Write([]byte(strconv.Quote(v.String()))) + mustWrite(s.w, []byte(strconv.Quote(v.String()))) case reflect.Slice: if v.IsNil() { @@ -419,9 +425,9 @@ func (s *dumpState) dumpVal(value reflect.Value) { case reflect.Ptr: pointerName, isPrimitive, isReused := s.nameForPointer(v), s.isPrimitivePointer(v), s.isReusedPointer(v) if isPrimitive || isReused { - s.w.Write([]byte(pointerName)) + mustWrite(s.w, []byte(pointerName)) } else { - s.w.Write([]byte("&")) + mustWrite(s.w, []byte("&")) s.dumpVal(v.Elem()) } @@ -440,19 +446,6 @@ func (s *dumpState) dumpVal(value reflect.Value) { } } -// call to signal that the pointer is being visited, returns true if this is the -// first visit to that pointer. Used to detect when to output the entire contents -// behind a pointer (the first time), and when to just emit a name (all other times) -func (s *dumpState) visitPointerAndCheckIfItIsTheFirstTime(ptr uintptr) bool { - for _, addr := range s.visitedPointers { - if addr == ptr { - return false - } - } - s.visitedPointers = append(s.visitedPointers, ptr) - return true -} - func (s *dumpState) nameForPointer(v reflect.Value) string { if isPointerValue(v) { ptr := v.Pointer() diff --git a/internal/dump/utils.go b/internal/dump/utils.go index e8bfb64..36ae50f 100644 --- a/internal/dump/utils.go +++ b/internal/dump/utils.go @@ -25,42 +25,42 @@ import ( ) func printBool(w io.Writer, value bool) { - w.Write([]byte(strconv.FormatBool(value))) + mustWrite(w, []byte(strconv.FormatBool(value))) } func printInt(w io.Writer, val reflect.Value, stripPackageName bool) { - typeName := fmt.Sprintf("%s", val.Type()) + typeName := val.Type().String() if stripPackageName && strings.HasPrefix(typeName, "ast.") { typeName = typeName[4:] } - w.Write([]byte(fmt.Sprintf("%s(%s)", typeName, strconv.FormatInt(val.Int(), 10)))) + mustWrite(w, []byte(fmt.Sprintf("%s(%s)", typeName, strconv.FormatInt(val.Int(), 10)))) } func printUint(w io.Writer, val reflect.Value) { - typeName := fmt.Sprintf("%s", val.Type()) - w.Write([]byte(fmt.Sprintf("%s(%s)", typeName, strconv.FormatUint(val.Uint(), 10)))) + typeName := val.Type().String() + mustWrite(w, []byte(fmt.Sprintf("%s(%s)", typeName, strconv.FormatUint(val.Uint(), 10)))) } func printFloat(w io.Writer, val float64, precision int, floatType string) { - w.Write([]byte(fmt.Sprintf("%s(%s)", floatType, strconv.FormatFloat(val, 'g', -1, precision)))) + mustWrite(w, []byte(fmt.Sprintf("%s(%s)", floatType, strconv.FormatFloat(val, 'g', -1, precision)))) } func printComplex(w io.Writer, c complex128, floatPrecision int) { - w.Write([]byte("complex")) - w.Write([]byte(fmt.Sprintf("%d", floatPrecision*2))) + mustWrite(w, []byte("complex")) + mustWrite(w, []byte(fmt.Sprintf("%d", floatPrecision*2))) r := real(c) - w.Write([]byte("(")) - w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) + mustWrite(w, []byte("(")) + mustWrite(w, []byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) i := imag(c) if i >= 0 { - w.Write([]byte("+")) + mustWrite(w, []byte("+")) } - w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) - w.Write([]byte("i)")) + mustWrite(w, []byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) + mustWrite(w, []byte("i)")) } func printNil(w io.Writer) { - w.Write([]byte("nil")) + mustWrite(w, []byte("nil")) } // deInterface returns values inside of non-nil interfaces when possible. diff --git a/internal/parser/lexer.go b/internal/parser/lexer.go index f309d23..b001807 100644 --- a/internal/parser/lexer.go +++ b/internal/parser/lexer.go @@ -412,16 +412,13 @@ func (l *lexer) lexWhitespace() (int, int) { switch r { case '\r': // Ignore. - break case '\n': indent = 0 newLines++ - break case ' ': indent++ - break // This only works for \t at the beginning of lines, but we strip it everywhere else // anyway. The only case where this will cause a problem is spaces followed by \t @@ -429,7 +426,6 @@ func (l *lexer) lexWhitespace() (int, int) { // is enabled it will be fixed later. case '\t': indent += 8 - break } } l.backup() @@ -489,7 +485,7 @@ func (l *lexer) lexNumber() error { state := numBegin outerLoop: - for true { + for { r := l.next() switch state { case numBegin: @@ -654,6 +650,7 @@ func (l *lexer) lexSymbol() error { margin := l.pos.byteNo - l.pos.lineStart commentStartLoc := l.tokenStartLoc + //nolint:ineffassign,staticcheck r := l.next() // consume the initial '*' for r = l.next(); r != '*' || l.peek() != '/'; r = l.next() { if r == lexEOF { @@ -687,9 +684,9 @@ func (l *lexer) lexSymbol() error { } } if allStar { - for _, l := range lines { - if l[0] == '*' { - l = " " + l + for i := range lines { + if lines[i][0] == '*' { + lines[i] = " " + lines[i] } } } @@ -813,7 +810,7 @@ func Lex(fn string, input string) (Tokens, error) { l := makeLexer(fn, input) var err error - for true { + for { newLines, indent := l.lexWhitespace() // If it's the end of the file, discard final whitespace. if l.peek() == lexEOF { @@ -855,7 +852,8 @@ func Lex(fn string, input string) (Tokens, error) { return nil, err } - // String literals + // String literals + case '"': stringStartLoc := l.prevLocation() for r = l.next(); ; r = l.next() { @@ -869,6 +867,7 @@ func Lex(fn string, input string) (Tokens, error) { break } if r == '\\' && l.peek() != lexEOF { + //nolint:ineffassign,staticcheck r = l.next() } } @@ -885,6 +884,7 @@ func Lex(fn string, input string) (Tokens, error) { break } if r == '\\' && l.peek() != lexEOF { + //nolint:ineffassign,staticcheck r = l.next() } } diff --git a/internal/parser/lexer_test.go b/internal/parser/lexer_test.go index 994e0db..1943601 100644 --- a/internal/parser/lexer_test.go +++ b/internal/parser/lexer_test.go @@ -21,127 +21,10 @@ import ( "github.com/google/go-jsonnet/ast" ) -type lexTest struct { - name string - input string - tokens Tokens - errString string -} - var ( tEOF = token{kind: tokenEndOfFile} ) -var lexTests = []lexTest{ - { - "block string spaces", - `||| - test - more - ||| - foo -|||`, - Tokens{ - { - kind: tokenStringBlock, - data: "test\n more\n|||\n foo\n", - stringBlockIndent: " ", - stringBlockTermIndent: "", - }, - }, - "", - }, - { - "block string tabs", - `||| - test - more - ||| - foo -|||`, - Tokens{ - { - kind: tokenStringBlock, - data: "test\n more\n|||\n foo\n", - stringBlockIndent: "\t", - stringBlockTermIndent: "", - }, - }, - "", - }, - { - "block string mixed", - `||| - test - more - ||| - foo -|||`, - Tokens{ - { - kind: tokenStringBlock, - data: "test\n more\n|||\n foo\n", - stringBlockIndent: "\t \t", - stringBlockTermIndent: "", - }, - }, - "", - }, - { - "block string blanks", - `||| - - test - - - more - ||| - foo -|||`, - Tokens{ - { - kind: tokenStringBlock, - data: "\ntest\n\n\n more\n|||\n foo\n", - stringBlockIndent: " ", - stringBlockTermIndent: "", - }, - }, - "", - }, - { - "block string bad indent", - `||| - test - foo -|||`, - Tokens{}, - "block string bad indent:1:1 Text block not terminated with |||", - }, - { - "block string eof", - `||| - test`, - Tokens{}, - "block string eof:1:1 Unexpected EOF", - }, - { - "block string not term", - `||| - test -`, - Tokens{}, - "block string not term:1:1 Text block not terminated with |||", - }, - { - "block string no ws", - `||| -test -|||`, - Tokens{}, - "block string no ws:1:1 Text block's first line must start with whitespace", - }, -} - func fodderEqual(f1 ast.Fodder, f2 ast.Fodder) bool { if len(f1) != len(f2) { return false diff --git a/internal/parser/parser.go b/internal/parser/parser.go index d63c13d..efff0cf 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -120,16 +120,6 @@ func (p *parser) doublePeek() *token { return &p.t[p.currT+1] } -// in some cases it's convenient to parse something as an expression, and later -// decide that it should be just an identifer -func astVarToIdentifier(node ast.Node) (ast.Fodder, *ast.Identifier, bool) { - v, ok := node.(*ast.Var) - if ok { - return v.NodeBase.Fodder, &v.Id, true - } - return nil, nil, false -} - // parseArgument parses either id = expr or just expr. // It returns either (, id, , expr) or (nil, nil, nil, expr) // respectively. diff --git a/internal/program/desugarer.go b/internal/program/desugarer.go index 761476a..0c254da 100644 --- a/internal/program/desugarer.go +++ b/internal/program/desugarer.go @@ -167,7 +167,10 @@ func desugarFields(nodeBase ast.NodeBase, fields *ast.ObjectFields, objLevel int return nil, err } } - desugarLocalBinds(locals, objLevel+1) + err := desugarLocalBinds(locals, objLevel+1) + if err != nil { + return nil, err + } for i := range desugaredFields { field := &(desugaredFields[i]) if field.Name != nil { diff --git a/interpreter.go b/interpreter.go index 81abff9..adfaf97 100644 --- a/interpreter.go +++ b/interpreter.go @@ -205,14 +205,6 @@ func (s *callStack) getCurrentEnv(ast ast.Node) environment { ) } -func (s *callStack) getTopEnv() environment { - top := s.stack[len(s.stack)-1] - if !top.isCall { - panic("getTopEnv is allowed only for artifical nodes which are called in new environment") - } - return top.env -} - // Build a binding frame containing specified variables. func (s *callStack) capture(freeVars ast.Identifiers) bindingFrame { env := make(bindingFrame) @@ -482,7 +474,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) { // too large to fit in a double. num, err := strconv.ParseFloat(node.OriginalString, 64) if err != nil { - return nil, i.Error(fmt.Sprintf("overflow"), trace) + return nil, i.Error("overflow", trace) } return makeValueNumber(num), nil @@ -968,6 +960,7 @@ func (i *interpreter) getNumber(val value, trace traceElement) (*valueNumber, er } } +//nolint:unused func (i *interpreter) evaluateNumber(pv potentialValue, trace traceElement) (*valueNumber, error) { v, err := i.evaluatePV(pv, trace) if err != nil { @@ -998,6 +991,7 @@ func (i *interpreter) evaluateInt(pv potentialValue, trace traceElement) (int, e return i.getInt(v, trace) } +//nolint:unused func (i *interpreter) getInt64(val value, trace traceElement) (int64, error) { num, err := i.getNumber(val, trace) if err != nil { @@ -1010,6 +1004,7 @@ func (i *interpreter) getInt64(val value, trace traceElement) (int64, error) { return intNum, nil } +//nolint:unused func (i *interpreter) evaluateInt64(pv potentialValue, trace traceElement) (int64, error) { v, err := i.evaluatePV(pv, trace) if err != nil { @@ -1027,6 +1022,7 @@ func (i *interpreter) getString(val value, trace traceElement) (valueString, err } } +//nolint:unused func (i *interpreter) evaluateString(pv potentialValue, trace traceElement) (valueString, error) { v, err := i.evaluatePV(pv, trace) if err != nil { @@ -1044,6 +1040,7 @@ func (i *interpreter) getBoolean(val value, trace traceElement) (*valueBoolean, } } +//nolint:unused func (i *interpreter) evaluateBoolean(pv potentialValue, trace traceElement) (*valueBoolean, error) { v, err := i.evaluatePV(pv, trace) if err != nil { @@ -1061,6 +1058,7 @@ func (i *interpreter) getArray(val value, trace traceElement) (*valueArray, erro } } +//nolint:unused func (i *interpreter) evaluateArray(pv potentialValue, trace traceElement) (*valueArray, error) { v, err := i.evaluatePV(pv, trace) if err != nil { @@ -1078,6 +1076,7 @@ func (i *interpreter) getFunction(val value, trace traceElement) (*valueFunction } } +//nolint:unused func (i *interpreter) evaluateFunction(pv potentialValue, trace traceElement) (*valueFunction, error) { v, err := i.evaluatePV(pv, trace) if err != nil { diff --git a/linter/jsonnet-lint/cmd.go b/linter/jsonnet-lint/cmd.go index de7f6bd..25d128a 100644 --- a/linter/jsonnet-lint/cmd.go +++ b/linter/jsonnet-lint/cmd.go @@ -39,7 +39,10 @@ func main() { if err != nil { die(err) } - inputFile.Close() + err = inputFile.Close() + if err != nil { + die(err) + } node, err := jsonnet.SnippetToAST(p, string(data)) if err != nil { die(err) diff --git a/linter/linter.go b/linter/linter.go index e432623..9396da0 100644 --- a/linter/linter.go +++ b/linter/linter.go @@ -17,7 +17,10 @@ type ErrorWriter struct { func (e *ErrorWriter) writeError(err errors.StaticError) { e.ErrorsFound = true - e.Writer.Write([]byte(err.Error() + "\n")) + _, writeErr := e.Writer.Write([]byte(err.Error() + "\n")) + if writeErr != nil { + panic(writeErr) + } } type variable struct { diff --git a/main_test.go b/main_test.go index 966ee55..a0f85e6 100644 --- a/main_test.go +++ b/main_test.go @@ -398,7 +398,7 @@ func TestEval(t *testing.T) { } } -func withinWorkingDirectory(t *testing.T, dir string) func() error { +func withinWorkingDirectory(t *testing.T, dir string) func() { t.Helper() cwd, err := os.Getwd() if err != nil { @@ -407,8 +407,11 @@ func withinWorkingDirectory(t *testing.T, dir string) func() error { if err := os.Chdir(dir); err != nil { t.Fatal(err) } - return func() error { - return os.Chdir(cwd) + return func() { + err := os.Chdir(cwd) + if err != nil { + t.Fatal(err) + } } } @@ -426,7 +429,12 @@ func TestEvalUnusualFilenames(t *testing.T) { if dir, err = ioutil.TempDir("", "jsonnet"); err != nil { t.Fatal(err) } - defer os.RemoveAll(dir) + defer func() { + err := os.RemoveAll(dir) + if err != nil { + panic(err) + } + }() } copySmallFile := func(t *testing.T, dst, src string) { diff --git a/testdata/std.sort4.golden b/testdata/std.sort4.golden index 19205ba..c519d9a 100644 --- a/testdata/std.sort4.golden +++ b/testdata/std.sort4.golden @@ -1,10 +1,10 @@ -RUNTIME ERROR: foo +RUNTIME ERROR: Unexpected type array ------------------------------------------------- - testdata/std.sort4:1:15-26 thunk from >> + testdata/std.sort4:1:1-29 builtin function std.sort([1, [error "foo"]]) ------------------------------------------------- - During manifestation + During evaluation diff --git a/thunks.go b/thunks.go index 4370d07..cb21769 100644 --- a/thunks.go +++ b/thunks.go @@ -36,19 +36,9 @@ func (rv *readyValue) evaluate(i *interpreter, trace traceElement, sb selfBindin return rv.content, nil } -func (rv *readyValue) aPotentialValue() {} - // potentialValues // ------------------------------------- -// evaluable is something that can be evaluated and the result is always the same -// It may require computation every time evaluation is requested (in contrast with -// potentialValue which guarantees that computation happens at most once). -type evaluable interface { - // fromWhere keeps the information from where the evaluation was requested. - getValue(i *interpreter, fromWhere traceElement) (value, error) -} - // cachedThunk is a wrapper that caches the value of a potentialValue after // the first evaluation. // Note: All potentialValues are required to provide the same value every time, @@ -110,8 +100,7 @@ type bindingsUnboundField struct { } func (f *bindingsUnboundField) evaluate(i *interpreter, trace traceElement, sb selfBinding, origBindings bindingFrame, fieldName string) (value, error) { - var upValues bindingFrame - upValues = make(bindingFrame) + upValues := make(bindingFrame) for variable, pvalue := range origBindings { upValues[variable] = pvalue } @@ -164,7 +153,7 @@ func forceThunks(i *interpreter, trace traceElement, args *bindingFrame) error { func (closure *closure) evalCall(arguments callArguments, i *interpreter, trace traceElement) (value, error) { argThunks := make(bindingFrame) - parameters := closure.Parameters() + parameters := closure.parameters() for i, arg := range arguments.positional { argThunks[parameters[i].name] = arg } @@ -199,7 +188,7 @@ func (closure *closure) evalCall(arguments callArguments, i *interpreter, trace return i.EvalInCleanEnv(trace, &calledEnvironment, closure.function.Body, arguments.tailstrict) } -func (closure *closure) Parameters() []namedParameter { +func (closure *closure) parameters() []namedParameter { return closure.params } @@ -232,7 +221,7 @@ type NativeFunction struct { // evalCall evaluates a call to a NativeFunction and returns the result. func (native *NativeFunction) evalCall(arguments callArguments, i *interpreter, trace traceElement) (value, error) { - flatArgs := flattenArgs(arguments, native.Parameters(), []value{}) + flatArgs := flattenArgs(arguments, native.parameters(), []value{}) nativeArgs := make([]interface{}, 0, len(flatArgs)) for _, arg := range flatArgs { v, err := i.evaluatePV(arg, trace) @@ -253,20 +242,10 @@ func (native *NativeFunction) evalCall(arguments callArguments, i *interpreter, } // Parameters returns a NativeFunction's parameters. -func (native *NativeFunction) Parameters() []namedParameter { +func (native *NativeFunction) parameters() []namedParameter { ret := make([]namedParameter, len(native.Params)) for i := range ret { ret[i].name = native.Params[i] } return ret } - -// ------------------------------------- - -type defaultArgument struct { - body ast.Node -} - -func (da *defaultArgument) inEnv(env *environment) potentialValue { - return &cachedThunk{env: env, body: da.body} -} diff --git a/value.go b/value.go index d35152a..ee299a8 100644 --- a/value.go +++ b/value.go @@ -313,9 +313,7 @@ func makeValueArray(elements []*cachedThunk) *valueArray { arrayElems = elements } else { arrayElems = make([]*cachedThunk, len(elements)) - for i := range elements { - arrayElems[i] = elements[i] - } + copy(arrayElems, elements) } return &valueArray{ elements: arrayElems, @@ -324,12 +322,8 @@ func makeValueArray(elements []*cachedThunk) *valueArray { func concatArrays(a, b *valueArray) *valueArray { result := make([]*cachedThunk, 0, len(a.elements)+len(b.elements)) - for _, r := range a.elements { - result = append(result, r) - } - for _, r := range b.elements { - result = append(result, r) - } + result = append(result, a.elements...) + result = append(result, b.elements...) return &valueArray{elements: result} } @@ -348,19 +342,19 @@ type valueFunction struct { // TODO(sbarzowski) better name? type evalCallable interface { evalCall(args callArguments, i *interpreter, trace traceElement) (value, error) - Parameters() []namedParameter + parameters() []namedParameter } func (f *valueFunction) call(i *interpreter, trace traceElement, args callArguments) (value, error) { - err := checkArguments(i, trace, args, f.Parameters()) + err := checkArguments(i, trace, args, f.parameters()) if err != nil { return nil, err } return f.ec.evalCall(args, i, trace) } -func (f *valueFunction) Parameters() []namedParameter { - return f.ec.Parameters() +func (f *valueFunction) parameters() []namedParameter { + return f.ec.parameters() } func checkArguments(i *interpreter, trace traceElement, args callArguments, params []namedParameter) error { @@ -406,22 +400,11 @@ func (f *valueFunction) getType() *valueType { return functionType } -// parameters represents required position and optional named parameters for a -// function definition. -type parameters struct { - required ast.Identifiers - optional []namedParameter -} - type namedParameter struct { name ast.Identifier defaultArg ast.Node } -type potentialValueInEnv interface { - inEnv(env *environment) *cachedThunk -} - type callArguments struct { positional []*cachedThunk named []namedCallArgument