From 2655afd2bd0200186aff32cd679ebc7f1f18e6ed Mon Sep 17 00:00:00 2001 From: Jesse <3723654+Jesse-Cameron@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:19:15 +1100 Subject: [PATCH] memory align structs (#635) feat: align most structs and add lint rule to enforce struct alignment --- .golangci.yml | 13 +++ ast/ast.go | 177 ++++++++++++++--------------- ast/fodder.go | 2 +- ast/location.go | 28 ++--- builtins.go | 10 +- c-bindings/handles.go | 2 +- cmd/jsonnet/cmd.go | 11 +- cmd/jsonnetfmt/cmd.go | 6 +- error_formatter.go | 10 +- imports.go | 5 +- internal/dump/dump.go | 6 +- internal/errors/static_error.go | 2 +- internal/formatter/sort_imports.go | 4 +- internal/parser/context.go | 3 +- internal/parser/lexer.go | 10 +- interpreter.go | 37 +++--- runtime_error.go | 4 +- thunks.go | 3 +- value.go | 19 ++-- vm.go | 10 +- 20 files changed, 186 insertions(+), 176 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 3e5a3cf..99f9de4 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -5,11 +5,24 @@ linters: - stylecheck - gochecknoinits - golint + - govet issues: exclude-use-default: false exclude: - "should have a package comment, unless it's in another file for this package" - "the surrounding loop is unconditionally terminated" + exclude-rules: + # ignore govet on non-critical files + - path: 'linter/*' + linters: + - govet + - path: '(.+)_test\.go' + linters: + - govet linters-settings: golint: min-confidence: 0 + govet: + enable-all: true + disable: + - shadow diff --git a/ast/ast.go b/ast/ast.go index 3269f44..90e970f 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -22,7 +22,7 @@ import ( ) // Identifier represents a variable / parameter / field name. -//+gen set +// +gen set type Identifier string // Identifiers represents an Identifier slice. @@ -59,13 +59,13 @@ type Nodes []Node // NodeBase holds fields common to all node types. type NodeBase struct { - LocRange LocationRange // This is the fodder that precedes the first token of the node. // If the node is left-recursive, i.e. the first token is actually // a token of a sub-expression, then Fodder is nil. Fodder Fodder Ctx Context FreeVars Identifiers + LocRange LocationRange } // NewNodeBase creates a new NodeBase from initial LocationRange and @@ -117,8 +117,8 @@ func (n *NodeBase) SetContext(context Context) { // IfSpec represents an if-specification in a comprehension. type IfSpec struct { - IfFodder Fodder Expr Node + IfFodder Fodder } // ForSpec represents a for-specification in a comprehension. @@ -135,34 +135,35 @@ type IfSpec struct { // The if is attached to the y forspec. // // It desugares to: -// flatMap(\x -> -// flatMap(\y -> -// flatMap(\z -> [expr], arr3) -// arr2) -// arr3) +// +// flatMap(\x -> +// flatMap(\y -> +// flatMap(\z -> [expr], arr3) +// arr2) +// arr3) type ForSpec struct { ForFodder Fodder VarFodder Fodder - VarName Identifier - InFodder Fodder - Expr Node Conditions []IfSpec Outer *ForSpec + Expr Node + VarName Identifier + InFodder Fodder } // --------------------------------------------------------------------------- // Apply represents a function call type Apply struct { - NodeBase - Target Node - FodderLeft Fodder - Arguments Arguments - // Always false if there were no arguments. - TrailingComma bool - TailStrict bool + Target Node + FodderLeft Fodder + Arguments Arguments FodderRight Fodder TailStrictFodder Fodder + NodeBase + // Always false if there were no arguments. + TrailingComma bool + TailStrict bool } // NamedArgument represents a named argument to function call x=1. @@ -193,20 +194,20 @@ type Arguments struct { // ApplyBrace represents e { }. Desugared to e + { }. type ApplyBrace struct { - NodeBase Left Node Right Node + NodeBase } // --------------------------------------------------------------------------- // Array represents array constructors [1, 2, 3]. type Array struct { + Elements []CommaSeparatedExpr + CloseFodder Fodder NodeBase - Elements []CommaSeparatedExpr // Always false if there were no elements. TrailingComma bool - CloseFodder Fodder } // --------------------------------------------------------------------------- @@ -214,12 +215,12 @@ type Array struct { // ArrayComp represents array comprehensions (which are like Python list // comprehensions) type ArrayComp struct { - NodeBase Body Node - TrailingComma bool TrailingCommaFodder Fodder Spec ForSpec CloseFodder Fodder + NodeBase + TrailingComma bool } // --------------------------------------------------------------------------- @@ -229,12 +230,12 @@ type ArrayComp struct { // After parsing, message can be nil indicating that no message was // specified. This AST is elimiated by desugaring. type Assert struct { - NodeBase Cond Node - ColonFodder Fodder Message Node - SemicolonFodder Fodder Rest Node + ColonFodder Fodder + SemicolonFodder Fodder + NodeBase } // --------------------------------------------------------------------------- @@ -337,11 +338,11 @@ func (b BinaryOp) String() string { // Binary represents binary operators. type Binary struct { - NodeBase + Right Node Left Node OpFodder Fodder - Op BinaryOp - Right Node + NodeBase + Op BinaryOp } // --------------------------------------------------------------------------- @@ -351,12 +352,12 @@ type Binary struct { // After parsing, branchFalse can be nil indicating that no else branch // was specified. The desugarer fills this in with a LiteralNull type Conditional struct { - NodeBase Cond Node - ThenFodder Fodder BranchTrue Node - ElseFodder Fodder BranchFalse Node + ThenFodder Fodder + ElseFodder Fodder + NodeBase } // --------------------------------------------------------------------------- @@ -368,21 +369,21 @@ type Dollar struct{ NodeBase } // Error represents the error e. type Error struct { - NodeBase Expr Node + NodeBase } // --------------------------------------------------------------------------- // Function represents a function definition type Function struct { - NodeBase - ParenLeftFodder Fodder - Parameters []Parameter - // Always false if there were no parameters. - TrailingComma bool + ParenLeftFodder Fodder ParenRightFodder Fodder Body Node + Parameters []Parameter + NodeBase + // Always false if there were no parameters. + TrailingComma bool } // Parameter represents a parameter of function. @@ -391,9 +392,9 @@ type Function struct { type Parameter struct { NameFodder Fodder Name Identifier + CommaFodder Fodder EqFodder Fodder DefaultArg Node - CommaFodder Fodder LocRange LocationRange } @@ -409,24 +410,24 @@ type CommaSeparatedID struct { // Import represents import "file". type Import struct { - NodeBase File *LiteralString + NodeBase } // --------------------------------------------------------------------------- // ImportStr represents importstr "file". type ImportStr struct { - NodeBase File *LiteralString + NodeBase } // --------------------------------------------------------------------------- // ImportBin represents importbin "file". type ImportBin struct { - NodeBase File *LiteralString + NodeBase } // --------------------------------------------------------------------------- @@ -436,24 +437,22 @@ type ImportBin struct { // One of index and id will be nil before desugaring. After desugaring id // will be nil. type Index struct { - NodeBase Target Node - // When Index is being used, this is the fodder before the '['. - // When Id is being used, this is the fodder before the '.'. - LeftBracketFodder Fodder - Index Node + Index Node // When Index is being used, this is the fodder before the ']'. // When Id is being used, this is the fodder before the id. RightBracketFodder Fodder + // When Index is being used, this is the fodder before the '['. + // When Id is being used, this is the fodder before the '.'. + LeftBracketFodder Fodder //nolint: golint,stylecheck // keeping Id instead of ID for now to avoid breaking 3rd parties Id *Identifier + NodeBase } // Slice represents an array slice a[begin:end:step]. type Slice struct { - NodeBase - Target Node - + Target Node LeftBracketFodder Fodder // Each of these can be nil BeginIndex Node @@ -462,6 +461,7 @@ type Slice struct { StepColonFodder Fodder Step Node RightBracketFodder Fodder + NodeBase } // --------------------------------------------------------------------------- @@ -469,15 +469,14 @@ type Slice struct { // LocalBind is a helper struct for astLocal type LocalBind struct { VarFodder Fodder - Variable Identifier - EqFodder Fodder // If Fun is set then its body == Body. - Body Node - // There is no base fodder in Fun because there was no `function` keyword. - Fun *Function + Body Node + EqFodder Fodder + Variable Identifier // The fodder before the closing ',' or ';' (whichever it is) CloseFodder Fodder - + // There is no base fodder in Fun because there was no `function` keyword. + Fun *Function LocRange LocationRange } @@ -486,9 +485,9 @@ type LocalBinds []LocalBind // Local represents local x = e; e. After desugaring, functionSugar is false. type Local struct { - NodeBase Binds LocalBinds Body Node + NodeBase } // --------------------------------------------------------------------------- @@ -508,8 +507,8 @@ type LiteralNull struct{ NodeBase } // LiteralNumber represents a JSON number type LiteralNumber struct { - NodeBase OriginalString string + NodeBase } // --------------------------------------------------------------------------- @@ -540,11 +539,11 @@ func (k LiteralStringKind) FullyEscaped() bool { // LiteralString represents a JSON string type LiteralString struct { - NodeBase Value string - Kind LiteralStringKind BlockIndent string BlockTermIndent string + NodeBase + Kind LiteralStringKind } // --------------------------------------------------------------------------- @@ -588,24 +587,23 @@ const ( // ObjectField represents a field of an object or object comprehension. // TODO(sbarzowski) consider having separate types for various kinds type ObjectField struct { - Kind ObjectFieldKind - Hide ObjectFieldHide // (ignore if kind != astObjectFieldID/Expr/Str) - SuperSugar bool // +: (ignore if kind != astObjectFieldID/Expr/Str) - // f(x, y, z): ... (ignore if kind == astObjectAssert) // 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 //nolint: golint,stylecheck // keeping Id instead of ID for now to avoid breaking 3rd parties Id *Identifier Fodder2 Fodder + Fodder1 Fodder OpFodder Fodder - Expr2, Expr3 Node // In scope of the object (can see self). CommaFodder Fodder + Expr1 Node // Not in scope of the object + Expr2, Expr3 Node // In scope of the object (can see self). LocRange LocationRange + Kind ObjectFieldKind + Hide ObjectFieldHide // (ignore if kind != astObjectFieldID/Expr/Str) + SuperSugar bool // +: (ignore if kind != astObjectFieldID/Expr/Str) } // ObjectFieldLocalNoMethod creates a non-method local object field. @@ -627,22 +625,21 @@ type ObjectFields []ObjectField // The trailing comma is only allowed if len(fields) > 0. Converted to // DesugaredObject during desugaring. type Object struct { + Fields ObjectFields + CloseFodder Fodder NodeBase - Fields ObjectFields TrailingComma bool - CloseFodder Fodder } // --------------------------------------------------------------------------- // DesugaredObjectField represents a desugared object field. type DesugaredObjectField struct { - Hide ObjectFieldHide Name Node Body Node + LocRange LocationRange + Hide ObjectFieldHide PlusSuper bool - - LocRange LocationRange } // DesugaredObjectFields represents a DesugaredObjectField slice. @@ -653,33 +650,35 @@ type DesugaredObjectFields []DesugaredObjectField // // The assertions either return true or raise an error. type DesugaredObject struct { - NodeBase Asserts Nodes Fields DesugaredObjectFields Locals LocalBinds + NodeBase } // --------------------------------------------------------------------------- // ObjectComp represents object comprehension -// { [e]: e for x in e for.. if... }. +// +// { [e]: e for x in e for.. if... }. type ObjectComp struct { - NodeBase Fields ObjectFields TrailingCommaFodder Fodder - TrailingComma bool - Spec ForSpec CloseFodder Fodder + Spec ForSpec + NodeBase + TrailingComma bool } // --------------------------------------------------------------------------- // Parens represents parentheses -// ( e ) +// +// ( e ) type Parens struct { - NodeBase Inner Node CloseFodder Fodder + NodeBase } // --------------------------------------------------------------------------- @@ -694,24 +693,24 @@ type Self struct{ NodeBase } // Either index or identifier will be set before desugaring. After desugaring, id will be // nil. type SuperIndex struct { - NodeBase - // If super.f, the fodder before the '.' - // If super[e], the fodder before the '['. - DotFodder Fodder - Index Node // If super.f, the fodder before the 'f' // If super[e], the fodder before the ']'. IDFodder Fodder + Index Node + // If super.f, the fodder before the '.' + // If super[e], the fodder before the '['. + DotFodder Fodder //nolint: golint,stylecheck // keeping Id instead of ID for now to avoid breaking 3rd parties Id *Identifier + NodeBase } // InSuper represents the e in super construct. type InSuper struct { - NodeBase Index Node InFodder Fodder SuperFodder Fodder + NodeBase } // --------------------------------------------------------------------------- @@ -751,18 +750,18 @@ func (u UnaryOp) String() string { // Unary represents unary operators. type Unary struct { - NodeBase - Op UnaryOp Expr Node + NodeBase + Op UnaryOp } // --------------------------------------------------------------------------- // Var represents variables. type Var struct { - NodeBase //nolint: golint,stylecheck // keeping Id instead of ID for now to avoid breaking 3rd parties Id Identifier + NodeBase } // --------------------------------------------------------------------------- diff --git a/ast/fodder.go b/ast/fodder.go index ab6c2fe..7fa5405 100644 --- a/ast/fodder.go +++ b/ast/fodder.go @@ -66,10 +66,10 @@ const ( // FodderElement is a single piece of fodder. type FodderElement struct { + Comment []string Kind FodderKind Blanks int Indent int - Comment []string } // MakeFodderElement is a helper function that checks some preconditions. diff --git a/ast/location.go b/ast/location.go index e7d08f8..7ce2600 100644 --- a/ast/location.go +++ b/ast/location.go @@ -28,10 +28,10 @@ type DiagnosticFileName string // Source represents a source file. type Source struct { - Lines []string // DiagnosticFileName is the imported path or a special string // for indicating stdin, extvars and other non-imported sources. DiagnosticFileName DiagnosticFileName + Lines []string } ////////////////////////////////////////////////////////////////////////////// @@ -68,11 +68,11 @@ func LocationBefore(a Location, b Location) bool { // LocationRange represents a range of a source file. type LocationRange struct { + File *Source // FileName should be the imported path or "" for snippets etc. FileName string Begin Location End Location // TODO(sbarzowski) inclusive? exclusive? a gap? - File *Source } // LocationRangeBetween returns a LocationRange containing both a and b. @@ -164,7 +164,7 @@ func BuildSource(dFilename DiagnosticFileName, s string) *Source { rest := lineBuf.String() // Stuff after last end-of-line (EOF or some more code) result = append(result, rest+"\n") - return &Source{result, dFilename} + return &Source{dFilename, result} } func trimToLine(loc LocationRange, line int) LocationRange { @@ -187,11 +187,12 @@ func trimToLine(loc LocationRange, line int) LocationRange { // LineBeginning returns the part of a line directly before LocationRange // for example: -// local x = foo() -// ^^^^^ <- LocationRange loc -// then -// local x = foo() -// ^^^^^^^^^^ <- lineBeginning(loc) +// +// local x = foo() +// ^^^^^ <- LocationRange loc +// then +// local x = foo() +// ^^^^^^^^^^ <- lineBeginning(loc) func LineBeginning(loc *LocationRange) LocationRange { return LocationRange{ Begin: Location{Line: loc.Begin.Line, Column: 1}, @@ -203,11 +204,12 @@ func LineBeginning(loc *LocationRange) LocationRange { // LineEnding returns the part of a line directly after LocationRange // for example: -// local x = foo() + test -// ^^^^^ <- LocationRange loc -// then -// local x = foo() + test -// ^^^^^^^ <- lineEnding(loc) +// +// local x = foo() + test +// ^^^^^ <- LocationRange loc +// then +// local x = foo() + test +// ^^^^^^^ <- lineEnding(loc) func LineEnding(loc *LocationRange) LocationRange { return LocationRange{ Begin: loc.End, diff --git a/builtins.go b/builtins.go index 3bae03c..4f7ec40 100644 --- a/builtins.go +++ b/builtins.go @@ -260,9 +260,9 @@ func builtinTrace(i *interpreter, x value, y value) (value, error) { // time. It is equivalent to `local i = 42; func(i)`. It therefore has no // free variables and needs only an empty environment to execute. type astMakeArrayElement struct { - ast.NodeBase function *valueFunction - index int + ast.NodeBase + index int } func builtinMakeArray(i *interpreter, szv, funcv value) (value, error) { @@ -506,10 +506,10 @@ func builtinFilter(i *interpreter, funcv, arrv value) (value, error) { } type sortData struct { + err error i *interpreter thunks []*cachedThunk keys []value - err error } func (d *sortData) Len() int { @@ -1917,10 +1917,10 @@ func (b *ternaryBuiltin) Name() ast.Identifier { type generalBuiltinFunc func(*interpreter, []value) (value, error) type generalBuiltinParameter struct { - name ast.Identifier // Note that the defaults are passed as values rather than AST nodes like in Parameters. // This spares us unnecessary evaluation. defaultValue value + name ast.Identifier } // generalBuiltin covers cases that other builtin structures do not, @@ -1929,8 +1929,8 @@ type generalBuiltinParameter struct { // at the same index. type generalBuiltin struct { name ast.Identifier - params []generalBuiltinParameter function generalBuiltinFunc + params []generalBuiltinParameter } func (b *generalBuiltin) parameters() []namedParameter { diff --git a/c-bindings/handles.go b/c-bindings/handles.go index 3865bbb..98fef99 100644 --- a/c-bindings/handles.go +++ b/c-bindings/handles.go @@ -16,8 +16,8 @@ import ( // handlesTable is the set of active, valid Jsonnet allocated handles type handlesTable struct { - mu sync.Mutex handles map[uintptr]*handle + mu sync.Mutex } type handle struct { diff --git a/cmd/jsonnet/cmd.go b/cmd/jsonnet/cmd.go index ca217ab..49c1f9b 100644 --- a/cmd/jsonnet/cmd.go +++ b/cmd/jsonnet/cmd.go @@ -93,15 +93,14 @@ func usage(o io.Writer) { } type config struct { - inputFiles []string - outputFile string - filenameIsCode bool - + outputFile string + evalMultiOutputDir string + inputFiles []string + evalJpath []string + filenameIsCode bool evalMulti bool evalStream bool - evalMultiOutputDir string evalCreateOutputDirs bool - evalJpath []string } func makeConfig() config { diff --git a/cmd/jsonnetfmt/cmd.go b/cmd/jsonnetfmt/cmd.go index 0dda49c..88420e3 100644 --- a/cmd/jsonnetfmt/cmd.go +++ b/cmd/jsonnetfmt/cmd.go @@ -71,13 +71,13 @@ func usage(o io.Writer) { } type config struct { + outputFile string + inputFiles []string evalCreateOutputDirs bool filenameIsCode bool inPlace bool - inputFiles []string - options formatter.Options - outputFile string test bool + options formatter.Options } func makeConfig() config { diff --git a/error_formatter.go b/error_formatter.go index f9a3976..03a803a 100644 --- a/error_formatter.go +++ b/error_formatter.go @@ -43,17 +43,15 @@ type ColorFormatter func(w io.Writer, f string, a ...interface{}) (n int, err er var _ ErrorFormatter = &termErrorFormatter{} type termErrorFormatter struct { - // maxStackTraceSize is the maximum length of stack trace before cropping - maxStackTraceSize int - // Examples of current state of the art. // http://elm-lang.org/blog/compiler-errors-for-humans // https://clang.llvm.org/diagnostics.html - color ColorFormatter - pretty bool - + color ColorFormatter // sp is currently never set, but is used to format locations. sp *ast.SourceProvider + // maxStackTraceSize is the maximum length of stack trace before cropping + maxStackTraceSize int + pretty bool } func (ef *termErrorFormatter) SetMaxStackTraceSize(size int) { diff --git a/imports.go b/imports.go index 97f748c..de93b0b 100644 --- a/imports.go +++ b/imports.go @@ -70,6 +70,7 @@ func (c Contents) String() string { return *(*string)(unsafe.Pointer(c.data)) } +// Data returns content bytes func (c Contents) Data() []byte { return *c.data } @@ -217,13 +218,13 @@ func (cache *importCache) importCode(importedFrom, importedPath string, i *inter // FileImporter imports data from the filesystem. type FileImporter struct { - JPaths []string fsCache map[string]*fsCacheEntry + JPaths []string } type fsCacheEntry struct { - exists bool contents Contents + exists bool } func (importer *FileImporter) tryPath(dir, importedPath string) (found bool, contents Contents, foundHere string, err error) { diff --git a/internal/dump/dump.go b/internal/dump/dump.go index 308e294..55060ce 100644 --- a/internal/dump/dump.go +++ b/internal/dump/dump.go @@ -33,11 +33,11 @@ var packageNameStripperRegexp = regexp.MustCompile(`\b[a-zA-Z_]+[a-zA-Z_0-9]+\.` // Options represents configuration option type Options struct { - StripPackageNames bool - HidePrivateFields bool HomePackage string VariableName string VariableDescription string + StripPackageNames bool + HidePrivateFields bool } // Config is the default config used when calling Dump @@ -48,7 +48,7 @@ var Config = Options{ VariableDescription: "", } -type dumpState struct { +type dumpState struct { // nolint:govet w io.Writer depth int config *Options diff --git a/internal/errors/static_error.go b/internal/errors/static_error.go index 535da5e..cd5f293 100644 --- a/internal/errors/static_error.go +++ b/internal/errors/static_error.go @@ -38,8 +38,8 @@ type StaticError interface { } type staticError struct { - loc ast.LocationRange msg string + loc ast.LocationRange } func (err staticError) WithContext(context string) StaticError { diff --git a/internal/formatter/sort_imports.go b/internal/formatter/sort_imports.go index 0982e3d..773e60c 100644 --- a/internal/formatter/sort_imports.go +++ b/internal/formatter/sort_imports.go @@ -23,8 +23,8 @@ import ( ) type importElem struct { - key string adjacentFodder ast.Fodder + key string bind ast.LocalBind } @@ -123,7 +123,7 @@ func extractImportElems(binds ast.LocalBinds, after ast.Fodder) []importElem { newBind.VarFodder = before theImport := bind.Body.(*ast.Import) result = append(result, - importElem{theImport.File.Value, adjacent, newBind}) + importElem{key: theImport.File.Value, adjacentFodder: adjacent, bind: newBind}) before = beforeNext } return result diff --git a/internal/parser/context.go b/internal/parser/context.go index 1cca48b..245e53e 100644 --- a/internal/parser/context.go +++ b/internal/parser/context.go @@ -144,7 +144,8 @@ func DirectChildren(node ast.Node) []ast.Node { // It supports ASTs before and after desugaring. // // TODO(sbarzowski) Make sure it works well with boundary cases like tailstrict arguments, -// make it more precise. +// make it more precise. +// // Rules: // * (same-environment) They must be evaluated in the same environment as their parent // * (not-direct) If they can be direct children, they should (and cannot be thunked). diff --git a/internal/parser/lexer.go b/internal/parser/lexer.go index facc1b2..3743436 100644 --- a/internal/parser/lexer.go +++ b/internal/parser/lexer.go @@ -147,15 +147,13 @@ func (tk tokenKind) String() string { } type token struct { - kind tokenKind // The type of the token fodder ast.Fodder // Any fodder that occurs before this token data string // Content of the token if it is not a keyword - // Extra info for when kind == tokenStringBlock stringBlockIndent string // The sequence of whitespace that indented the block. stringBlockTermIndent string // This is always fewer whitespace characters than in stringBlockIndent. - - loc ast.LocationRange + loc ast.LocationRange + kind tokenKind // The type of the token } // Tokens is a slice of token structs. @@ -283,8 +281,6 @@ type lexer struct { input string // The input string source *ast.Source - pos position // Current position in input - tokens Tokens // The tokens that we've generated so far // Information about the token we are working on right now @@ -294,6 +290,8 @@ type lexer struct { // Was the last rune the first rune on a line (ignoring initial whitespace). freshLine bool + + pos position // Current position in input } const lexEOF = -1 diff --git a/interpreter.go b/interpreter.go index 500b0e2..4a62b37 100644 --- a/interpreter.go +++ b/interpreter.go @@ -32,15 +32,14 @@ import ( // TODO(sbarzowski) use it as a pointer in most places b/c it can sometimes be shared // for example it can be shared between array elements and function arguments type environment struct { - selfBinding selfBinding - // Bindings introduced in this frame. The way previous bindings are treated // depends on the type of a frame. // If cleanEnv == true then previous bindings are ignored (it's a clean // environment with just the variables we have here). // If cleanEnv == false then if this frame doesn't contain a binding // previous bindings will be used. - upValues bindingFrame + upValues bindingFrame + selfBinding selfBinding } func makeEnvironment(upValues bindingFrame, sb selfBinding) environment { @@ -64,20 +63,20 @@ func (i *interpreter) getCurrentStackTrace() []traceFrame { } type callFrame struct { + // Tracing information about the place where it was called from. + trace traceElement + + env environment + // True if it switches to a clean environment (function call or array element) // False otherwise, e.g. for local cleanEnv bool - // Tracing information about the place where it was called from. - trace traceElement - // Whether this frame can be removed from the stack when it doesn't affect // the evaluation result, but in case of an error, it won't appear on the // stack trace. // It's used for tail call optimization. trimmable bool - - env environment } func dumpCallFrame(c *callFrame) string { @@ -95,10 +94,10 @@ func dumpCallFrame(c *callFrame) string { } type callStack struct { + currentTrace traceElement + stack []*callFrame calls int limit int - stack []*callFrame - currentTrace traceElement } func dumpCallStack(c *callStack) string { @@ -242,10 +241,8 @@ func makeCallStack(limit int) callStack { // Keeps current execution context and evaluates things type interpreter struct { - // Current stack. It is used for: - // 1) Keeping environment (object we're in, variables) - // 2) Diagnostic information in case of failure - stack callStack + // Output stream for trace() for + traceOut io.Writer // External variables extVars map[string]*cachedThunk @@ -259,8 +256,10 @@ type interpreter struct { // Keeps imports importCache *importCache - // Output stream for trace() for - traceOut io.Writer + // Current stack. It is used for: + // 1) Keeping environment (object we're in, variables) + // 2) Diagnostic information in case of failure + stack callStack } // Map union, b takes precedence when keys collide. @@ -414,7 +413,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) { if field.PlusSuper { f = &plusSuperUnboundField{f} } - fields[fieldName] = simpleObjectField{field.Hide, f} + fields[fieldName] = simpleObjectField{f, field.Hide} } var asserts []unboundField for _, assert := range node.Asserts { @@ -1181,7 +1180,7 @@ func buildStdObject(i *interpreter) (*valueObject, error) { } for name, value := range builtinFields { - obj.fields[name] = simpleObjectField{ast.ObjectFieldHidden, value} + obj.fields[name] = simpleObjectField{value, ast.ObjectFieldHidden} } return objVal.(*valueObject), nil } @@ -1231,7 +1230,7 @@ func prepareExtVars(i *interpreter, ext vmExtMap, kind string) map[string]*cache func buildObject(hide ast.ObjectFieldHide, fields map[string]value) *valueObject { fieldMap := simpleObjectFieldMap{} for name, v := range fields { - fieldMap[name] = simpleObjectField{hide, &readyValue{v}} + fieldMap[name] = simpleObjectField{&readyValue{v}, hide} } return makeValueSimpleObject(bindingFrame{}, fieldMap, nil, nil) } diff --git a/runtime_error.go b/runtime_error.go index bc40b50..40a705b 100644 --- a/runtime_error.go +++ b/runtime_error.go @@ -20,8 +20,8 @@ import "github.com/google/go-jsonnet/ast" // RuntimeError is an error discovered during evaluation of the program type RuntimeError struct { - StackTrace []traceFrame Msg string + StackTrace []traceFrame } func makeRuntimeError(msg string, stackTrace []traceFrame) RuntimeError { @@ -40,8 +40,8 @@ func (err RuntimeError) Error() string { // traceFrame is tracing information about a single frame of the call stack. // TODO(sbarzowski) the difference from traceElement. Do we even need this? type traceFrame struct { - Loc ast.LocationRange Name string + Loc ast.LocationRange } func traceElementToTraceFrame(trace traceElement) traceFrame { diff --git a/thunks.go b/thunks.go index d6750ba..1cccadb 100644 --- a/thunks.go +++ b/thunks.go @@ -18,6 +18,7 @@ package jsonnet import ( "fmt" + "github.com/google/go-jsonnet/ast" ) @@ -254,9 +255,9 @@ func makeClosure(env environment, function *ast.Function) *closure { // NativeFunction represents a function implemented in Go. type NativeFunction struct { + Name string Func func([]interface{}) (interface{}, error) Params ast.Identifiers - Name string } // evalCall evaluates a call to a NativeFunction and returns the result. diff --git a/value.go b/value.go index e86d10f..f3b760d 100644 --- a/value.go +++ b/value.go @@ -397,8 +397,8 @@ func (f *valueFunction) getType() *valueType { } type namedParameter struct { - name ast.Identifier defaultArg ast.Node + name ast.Identifier } type callArguments struct { @@ -408,8 +408,8 @@ type callArguments struct { } type namedCallArgument struct { - name ast.Identifier pv *cachedThunk + name ast.Identifier } func args(xs ...*cachedThunk) callArguments { @@ -525,9 +525,9 @@ type uncachedObject interface { } type objectLocal struct { - name ast.Identifier // Locals may depend on self and super so they are unbound fields and not simply thunks node ast.Node + name ast.Identifier } // simpleObject represents a flat object (no inheritance). @@ -605,8 +605,8 @@ func makeValueSimpleObject(b bindingFrame, fields simpleObjectFieldMap, asserts type simpleObjectFieldMap map[string]simpleObjectField type simpleObjectField struct { - hide ast.ObjectFieldHide field unboundField + hide ast.ObjectFieldHide } // unboundField is a field that doesn't know yet in which object it is. @@ -620,11 +620,11 @@ type unboundField interface { // Example: // (A + B) + C // -// + -// / \ -// + C -// / \ -// A B +// + +// / \ +// + C +// / \ +// A B // // It is possible to create an arbitrary binary tree. // Note however, that because + is associative the only thing that matters @@ -632,7 +632,6 @@ type unboundField interface { // // This represenation allows us to implement "+" in O(1), // but requires going through the tree and trying subsequent leafs for field access. -// type extendedObject struct { left, right uncachedObject totalInheritanceSize int diff --git a/vm.go b/vm.go index d1fd467..7275b1a 100644 --- a/vm.go +++ b/vm.go @@ -36,7 +36,7 @@ import ( // VM is the core interpreter and is the touchpoint used to parse and execute // Jsonnet. -type VM struct { +type VM struct { //nolint:govet MaxStack int ext vmExtMap tla vmExtMap @@ -59,12 +59,12 @@ const ( // External variable or top level argument provided before execution type vmExt struct { - // the kind of external variable that is specified. - kind extKind - // jsonnet code to evaluate (kind=extKindCode) or string to pass (kind=extKindVar) - value string // the specified node for kind=extKindNode node ast.Node + // jsonnet code to evaluate (kind=extKindCode) or string to pass (kind=extKindVar) + value string + // the kind of external variable that is specified. + kind extKind } type vmExtMap map[string]vmExt