mirror of
https://github.com/google/go-jsonnet.git
synced 2025-08-07 14:57:24 +02:00
Better handling of stack traces.
Fixes multiple issues with stack traces leading to missing stack trace lines. Also, we no longer put builtin context on the line which *calls* the builtin as if it was a part of the builtin itself. Code for stack trace handling was centralized. We no longer need traceElement argument in ~every function. Now the stack trace state is kept solely in the interpreter.
This commit is contained in:
parent
e120148a45
commit
797bfd89ed
503
builtins.go
503
builtins.go
File diff suppressed because it is too large
Load Diff
10
imports.go
10
imports.go
@ -131,10 +131,10 @@ func (cache *importCache) importAST(importedFrom, importedPath string) (ast.Node
|
||||
}
|
||||
|
||||
// ImportString imports a string, caches it and then returns it.
|
||||
func (cache *importCache) importString(importedFrom, importedPath string, i *interpreter, trace traceElement) (valueString, error) {
|
||||
func (cache *importCache) importString(importedFrom, importedPath string, i *interpreter) (valueString, error) {
|
||||
data, _, err := cache.importData(importedFrom, importedPath)
|
||||
if err != nil {
|
||||
return nil, i.Error(err.Error(), trace)
|
||||
return nil, i.Error(err.Error())
|
||||
}
|
||||
return makeValueString(data.String()), nil
|
||||
}
|
||||
@ -158,10 +158,10 @@ func codeToPV(i *interpreter, filename string, code string) *cachedThunk {
|
||||
}
|
||||
|
||||
// ImportCode imports code from a path.
|
||||
func (cache *importCache) importCode(importedFrom, importedPath string, i *interpreter, trace traceElement) (value, error) {
|
||||
func (cache *importCache) importCode(importedFrom, importedPath string, i *interpreter) (value, error) {
|
||||
node, foundAt, err := cache.importAST(importedFrom, importedPath)
|
||||
if err != nil {
|
||||
return nil, i.Error(err.Error(), trace)
|
||||
return nil, i.Error(err.Error())
|
||||
}
|
||||
var pv potentialValue
|
||||
if cachedPV, isCached := cache.codeCache[foundAt]; !isCached {
|
||||
@ -176,7 +176,7 @@ func (cache *importCache) importCode(importedFrom, importedPath string, i *inter
|
||||
} else {
|
||||
pv = cachedPV
|
||||
}
|
||||
return i.evaluatePV(pv, trace)
|
||||
return i.evaluatePV(pv)
|
||||
}
|
||||
|
||||
// Concrete importers
|
||||
|
@ -155,7 +155,7 @@ func buildAnd(left ast.Node, right ast.Node) ast.Node {
|
||||
}
|
||||
|
||||
// inside is assumed to be already desugared (and cannot be desugared again)
|
||||
func desugarForSpec(inside ast.Node, forSpec *ast.ForSpec, objLevel int) (ast.Node, error) {
|
||||
func desugarForSpec(inside ast.Node, loc ast.LocationRange, forSpec *ast.ForSpec, objLevel int) (ast.Node, error) {
|
||||
var body ast.Node
|
||||
if len(forSpec.Conditions) > 0 {
|
||||
cond := forSpec.Conditions[0].Expr
|
||||
@ -179,11 +179,11 @@ func desugarForSpec(inside ast.Node, forSpec *ast.ForSpec, objLevel int) (ast.No
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
current := buildStdCall("flatMap", function, forSpec.Expr)
|
||||
current := buildStdCall("flatMap", loc, function, forSpec.Expr)
|
||||
if forSpec.Outer == nil {
|
||||
return current, nil
|
||||
}
|
||||
return desugarForSpec(current, forSpec.Outer, objLevel)
|
||||
return desugarForSpec(current, loc, forSpec.Outer, objLevel)
|
||||
}
|
||||
|
||||
func wrapInArray(inside ast.Node) ast.Node {
|
||||
@ -195,7 +195,7 @@ func desugarArrayComp(comp *ast.ArrayComp, objLevel int) (ast.Node, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return desugarForSpec(wrapInArray(comp.Body), &comp.Spec, objLevel)
|
||||
return desugarForSpec(wrapInArray(comp.Body), *comp.Loc(), &comp.Spec, objLevel)
|
||||
}
|
||||
|
||||
func desugarObjectComp(comp *ast.ObjectComp, objLevel int) (ast.Node, error) {
|
||||
@ -222,12 +222,12 @@ func desugarObjectComp(comp *ast.ObjectComp, objLevel int) (ast.Node, error) {
|
||||
panic("Wrong number of fields in object comprehension, it should have been caught during parsing")
|
||||
}
|
||||
|
||||
desugaredArrayComp, err := desugarForSpec(wrapInArray(obj), &comp.Spec, objLevel)
|
||||
desugaredArrayComp, err := desugarForSpec(wrapInArray(obj), *comp.Loc(), &comp.Spec, objLevel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
desugaredComp := buildStdCall("$objectFlatMerge", desugaredArrayComp)
|
||||
desugaredComp := buildStdCall("$objectFlatMerge", *comp.Loc(), desugaredArrayComp)
|
||||
return desugaredComp, nil
|
||||
}
|
||||
|
||||
@ -245,7 +245,7 @@ func buildSimpleIndex(obj ast.Node, member ast.Identifier) ast.Node {
|
||||
}
|
||||
}
|
||||
|
||||
func buildStdCall(builtinName ast.Identifier, args ...ast.Node) ast.Node {
|
||||
func buildStdCall(builtinName ast.Identifier, loc ast.LocationRange, args ...ast.Node) ast.Node {
|
||||
std := &ast.Var{Id: "std"}
|
||||
builtin := buildSimpleIndex(std, builtinName)
|
||||
positional := make([]ast.CommaSeparatedExpr, len(args))
|
||||
@ -253,6 +253,9 @@ func buildStdCall(builtinName ast.Identifier, args ...ast.Node) ast.Node {
|
||||
positional[i].Expr = args[i]
|
||||
}
|
||||
return &ast.Apply{
|
||||
NodeBase: ast.NodeBase{
|
||||
LocRange: loc,
|
||||
},
|
||||
Target: builtin,
|
||||
Arguments: ast.Arguments{Positional: positional},
|
||||
}
|
||||
@ -350,9 +353,9 @@ func desugar(astPtr *ast.Node, objLevel int) (err error) {
|
||||
if funcname, replaced := desugaredBop[node.Op]; replaced {
|
||||
if node.Op == ast.BopIn {
|
||||
// reversed order of arguments
|
||||
*astPtr = buildStdCall(funcname, node.Right, node.Left)
|
||||
*astPtr = buildStdCall(funcname, *node.Loc(), node.Right, node.Left)
|
||||
} else {
|
||||
*astPtr = buildStdCall(funcname, node.Left, node.Right)
|
||||
*astPtr = buildStdCall(funcname, *node.Loc(), node.Left, node.Right)
|
||||
}
|
||||
return desugar(astPtr, objLevel)
|
||||
}
|
||||
@ -455,7 +458,7 @@ func desugar(astPtr *ast.Node, objLevel int) (err error) {
|
||||
if node.Step == nil {
|
||||
node.Step = &ast.LiteralNull{}
|
||||
}
|
||||
*astPtr = buildStdCall("slice", node.Target, node.BeginIndex, node.EndIndex, node.Step)
|
||||
*astPtr = buildStdCall("slice", *node.Loc(), node.Target, node.BeginIndex, node.EndIndex, node.Step)
|
||||
err = desugar(astPtr, objLevel)
|
||||
if err != nil {
|
||||
return
|
||||
|
295
interpreter.go
295
interpreter.go
@ -49,15 +49,15 @@ func makeEnvironment(upValues bindingFrame, sb selfBinding) environment {
|
||||
}
|
||||
}
|
||||
|
||||
func (i *interpreter) getCurrentStackTrace(additional traceElement) []traceFrame {
|
||||
func (i *interpreter) getCurrentStackTrace() []traceFrame {
|
||||
var result []traceFrame
|
||||
for _, f := range i.stack.stack {
|
||||
if f.isCall {
|
||||
result = append(result, traceElementToTraceFrame(f.trace))
|
||||
}
|
||||
}
|
||||
if additional.loc != nil {
|
||||
result = append(result, traceElementToTraceFrame(additional))
|
||||
if i.stack.currentTrace.loc != nil {
|
||||
result = append(result, traceElementToTraceFrame(i.stack.currentTrace))
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -95,9 +95,10 @@ func dumpCallFrame(c *callFrame) string {
|
||||
}
|
||||
|
||||
type callStack struct {
|
||||
calls int
|
||||
limit int
|
||||
stack []*callFrame
|
||||
calls int
|
||||
limit int
|
||||
stack []*callFrame
|
||||
currentTrace traceElement
|
||||
}
|
||||
|
||||
func dumpCallStack(c *callStack) string {
|
||||
@ -123,6 +124,7 @@ func (s *callStack) popIfExists(whichFrame int) {
|
||||
if s.top().isCall {
|
||||
s.calls--
|
||||
}
|
||||
s.setCurrentTrace(s.stack[len(s.stack)-1].trace)
|
||||
s.stack = s.stack[:len(s.stack)-1]
|
||||
}
|
||||
}
|
||||
@ -142,6 +144,17 @@ func (s *callStack) tailCallTrimStack() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *callStack) setCurrentTrace(trace traceElement) {
|
||||
if s.currentTrace != (traceElement{}) {
|
||||
panic("Tried to change the traceElement while the old one was still there.")
|
||||
}
|
||||
s.currentTrace = trace
|
||||
}
|
||||
|
||||
func (s *callStack) clearCurrentTrace() {
|
||||
s.currentTrace = traceElement{}
|
||||
}
|
||||
|
||||
type tailCallStatus int
|
||||
|
||||
const (
|
||||
@ -149,20 +162,26 @@ const (
|
||||
tailCall
|
||||
)
|
||||
|
||||
func (s *callStack) newCall(trace traceElement, env environment, trimmable bool) {
|
||||
func (s *callStack) newCall(env environment, trimmable bool) {
|
||||
if s.currentTrace == (traceElement{}) {
|
||||
panic("Saving empty traceElement on stack")
|
||||
}
|
||||
s.stack = append(s.stack, &callFrame{
|
||||
isCall: true,
|
||||
trace: trace,
|
||||
trace: s.currentTrace,
|
||||
env: env,
|
||||
trimmable: trimmable,
|
||||
})
|
||||
s.clearCurrentTrace()
|
||||
s.calls++
|
||||
}
|
||||
|
||||
func (s *callStack) newLocal(vars bindingFrame) {
|
||||
s.stack = append(s.stack, &callFrame{
|
||||
env: makeEnvironment(vars, selfBinding{}),
|
||||
env: makeEnvironment(vars, selfBinding{}),
|
||||
trace: s.currentTrace,
|
||||
})
|
||||
s.clearCurrentTrace()
|
||||
}
|
||||
|
||||
// getSelfBinding resolves the self construct
|
||||
@ -256,12 +275,12 @@ func addBindings(a, b bindingFrame) bindingFrame {
|
||||
return result
|
||||
}
|
||||
|
||||
func (i *interpreter) newCall(trace traceElement, env environment, trimmable bool) error {
|
||||
func (i *interpreter) newCall(env environment, trimmable bool) error {
|
||||
s := &i.stack
|
||||
if s.calls >= s.limit {
|
||||
return makeRuntimeError("max stack frames exceeded.", i.getCurrentStackTrace(trace))
|
||||
return makeRuntimeError("max stack frames exceeded.", i.getCurrentStackTrace())
|
||||
}
|
||||
s.newCall(trace, env, trimmable)
|
||||
s.newCall(env, trimmable)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -270,6 +289,10 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
loc: a.Loc(),
|
||||
context: a.Context(),
|
||||
}
|
||||
oldTrace := i.stack.currentTrace
|
||||
i.stack.clearCurrentTrace()
|
||||
i.stack.setCurrentTrace(trace)
|
||||
defer func() { i.stack.clearCurrentTrace(); i.stack.setCurrentTrace(oldTrace) }()
|
||||
|
||||
switch node := a.(type) {
|
||||
case *ast.Array:
|
||||
@ -289,7 +312,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x, err := i.getBoolean(xv, trace)
|
||||
x, err := i.getBoolean(xv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -300,14 +323,14 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.getBoolean(yv, trace)
|
||||
return i.getBoolean(yv)
|
||||
} else if node.Op == ast.BopOr {
|
||||
// Special case for shortcut semantics.
|
||||
xv, err := i.evaluate(node.Left, nonTailCall)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x, err := i.getBoolean(xv, trace)
|
||||
x, err := i.getBoolean(xv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -318,7 +341,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.getBoolean(yv, trace)
|
||||
return i.getBoolean(yv)
|
||||
|
||||
} else {
|
||||
left, err := i.evaluate(node.Left, nonTailCall)
|
||||
@ -331,7 +354,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
}
|
||||
// TODO(dcunnin): The double dereference here is probably not necessary.
|
||||
builtin := bopBuiltins[node.Op]
|
||||
return builtin.function(i, trace, left, right)
|
||||
return builtin.function(i, left, right)
|
||||
}
|
||||
|
||||
case *ast.Unary:
|
||||
@ -342,7 +365,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
|
||||
builtin := uopBuiltins[node.Op]
|
||||
|
||||
result, err := builtin.function(i, trace, value)
|
||||
result, err := builtin.function(i, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -353,7 +376,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
condBool, err := i.getBoolean(cond, trace)
|
||||
condBool, err := i.getBoolean(cond)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -378,11 +401,11 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
// Omitted field.
|
||||
continue
|
||||
default:
|
||||
return nil, i.Error(fmt.Sprintf("Field name must be string, got %v", fieldNameValue.getType().name), trace)
|
||||
return nil, i.Error(fmt.Sprintf("Field name must be string, got %v", fieldNameValue.getType().name))
|
||||
}
|
||||
|
||||
if _, ok := fields[fieldName]; ok {
|
||||
return nil, i.Error(duplicateFieldNameErrMsg(fieldName), trace)
|
||||
return nil, i.Error(duplicateFieldNameErrMsg(fieldName))
|
||||
}
|
||||
var f unboundField = &codeUnboundField{field.Body}
|
||||
if field.PlusSuper {
|
||||
@ -408,16 +431,16 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
return nil, err
|
||||
}
|
||||
if msgVal.getType() != stringType {
|
||||
msgVal, err = builtinToString(i, trace, msgVal)
|
||||
msgVal, err = builtinToString(i, msgVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
msg, err := i.getString(msgVal, trace)
|
||||
msg, err := i.getString(msgVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, i.Error(msg.getGoString(), trace)
|
||||
return nil, i.Error(msg.getGoString())
|
||||
|
||||
case *ast.Index:
|
||||
targetValue, err := i.evaluate(node.Target, nonTailCall)
|
||||
@ -430,37 +453,37 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
}
|
||||
switch target := targetValue.(type) {
|
||||
case *valueObject:
|
||||
indexString, err := i.getString(index, trace)
|
||||
indexString, err := i.getString(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return target.index(i, trace, indexString.getGoString())
|
||||
return target.index(i, indexString.getGoString())
|
||||
case *valueArray:
|
||||
indexInt, err := i.getNumber(index, trace)
|
||||
indexInt, err := i.getNumber(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO(https://github.com/google/jsonnet/issues/377): non-integer indexes should be an error
|
||||
return target.index(i, trace, int(indexInt.value))
|
||||
return target.index(i, int(indexInt.value))
|
||||
|
||||
case valueString:
|
||||
indexInt, err := i.getNumber(index, trace)
|
||||
indexInt, err := i.getNumber(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO(https://github.com/google/jsonnet/issues/377): non-integer indexes should be an error
|
||||
return target.index(i, trace, int(indexInt.value))
|
||||
return target.index(i, int(indexInt.value))
|
||||
}
|
||||
|
||||
return nil, i.Error(fmt.Sprintf("Value non indexable: %v", reflect.TypeOf(targetValue)), trace)
|
||||
return nil, i.Error(fmt.Sprintf("Value non indexable: %v", reflect.TypeOf(targetValue)))
|
||||
|
||||
case *ast.Import:
|
||||
codePath := node.Loc().FileName
|
||||
return i.importCache.importCode(codePath, node.File.Value, i, trace)
|
||||
return i.importCache.importCode(codePath, node.File.Value, i)
|
||||
|
||||
case *ast.ImportStr:
|
||||
codePath := node.Loc().FileName
|
||||
return i.importCache.importString(codePath, node.File.Value, i, trace)
|
||||
return i.importCache.importString(codePath, node.File.Value, i)
|
||||
|
||||
case *ast.LiteralBoolean:
|
||||
return makeValueBoolean(node.Value), nil
|
||||
@ -474,7 +497,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("overflow", trace)
|
||||
return nil, i.Error("overflow")
|
||||
}
|
||||
return makeValueNumber(num), nil
|
||||
|
||||
@ -506,25 +529,25 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
|
||||
case *ast.Var:
|
||||
foo := i.stack.lookUpVarOrPanic(node.Id)
|
||||
return foo.getValue(i, trace)
|
||||
return foo.getValue(i)
|
||||
|
||||
case *ast.SuperIndex:
|
||||
index, err := i.evaluate(node.Index, nonTailCall)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indexStr, err := i.getString(index, trace)
|
||||
indexStr, err := i.getString(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return objectIndex(i, trace, i.stack.getSelfBinding().super(), indexStr.getGoString())
|
||||
return objectIndex(i, i.stack.getSelfBinding().super(), indexStr.getGoString())
|
||||
|
||||
case *ast.InSuper:
|
||||
index, err := i.evaluate(node.Index, nonTailCall)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indexStr, err := i.getString(index, trace)
|
||||
indexStr, err := i.getString(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -542,7 +565,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
function, err := i.getFunction(target, trace)
|
||||
function, err := i.getFunction(target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -561,7 +584,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
for i, arg := range node.Arguments.Named {
|
||||
arguments.named[i] = namedCallArgument{name: arg.Name, pv: &cachedThunk{env: &argEnv, body: arg.Arg}}
|
||||
}
|
||||
return i.evaluateTailCall(function, arguments, tc, trace)
|
||||
return i.evaluateTailCall(function, arguments, tc)
|
||||
|
||||
case *astMakeArrayElement:
|
||||
arguments := callArguments{
|
||||
@ -571,7 +594,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
||||
},
|
||||
},
|
||||
}
|
||||
return i.evaluateTailCall(node.function, arguments, tc, trace)
|
||||
return i.evaluateTailCall(node.function, arguments, tc)
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("Executing this AST type not implemented: %v", reflect.TypeOf(a)))
|
||||
@ -624,14 +647,20 @@ func unparseNumber(v float64) string {
|
||||
}
|
||||
|
||||
// manifestJSON converts to standard JSON representation as in "encoding/json" package
|
||||
func (i *interpreter) manifestJSON(trace traceElement, v value) (interface{}, error) {
|
||||
func (i *interpreter) manifestJSON(v value) (interface{}, error) {
|
||||
// TODO(sbarzowski) Add nice stack traces indicating the part of the code which
|
||||
// evaluates to non-manifestable value (that might require passing context about
|
||||
// the root value)
|
||||
if i.stack.currentTrace == (traceElement{}) {
|
||||
panic("manifesting JSON with empty traceElement")
|
||||
}
|
||||
switch v := v.(type) {
|
||||
|
||||
case *valueBoolean:
|
||||
return v.value, nil
|
||||
|
||||
case *valueFunction:
|
||||
return nil, makeRuntimeError("couldn't manifest function in JSON output.", i.getCurrentStackTrace(trace))
|
||||
return nil, makeRuntimeError("couldn't manifest function as JSON", i.getCurrentStackTrace())
|
||||
|
||||
case *valueNumber:
|
||||
return v.value, nil
|
||||
@ -645,11 +674,11 @@ func (i *interpreter) manifestJSON(trace traceElement, v value) (interface{}, er
|
||||
case *valueArray:
|
||||
result := make([]interface{}, 0, len(v.elements))
|
||||
for _, th := range v.elements {
|
||||
elVal, err := i.evaluatePV(th, trace)
|
||||
elVal, err := i.evaluatePV(th)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
elem, err := i.manifestJSON(trace, elVal)
|
||||
elem, err := i.manifestJSON(elVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -661,7 +690,7 @@ func (i *interpreter) manifestJSON(trace traceElement, v value) (interface{}, er
|
||||
fieldNames := objectFields(v, withoutHidden)
|
||||
sort.Strings(fieldNames)
|
||||
|
||||
err := checkAssertions(i, trace, v)
|
||||
err := checkAssertions(i, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -669,12 +698,12 @@ func (i *interpreter) manifestJSON(trace traceElement, v value) (interface{}, er
|
||||
result := make(map[string]interface{})
|
||||
|
||||
for _, fieldName := range fieldNames {
|
||||
fieldVal, err := v.index(i, trace, fieldName)
|
||||
fieldVal, err := v.index(i, fieldName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
field, err := i.manifestJSON(trace, fieldVal)
|
||||
field, err := i.manifestJSON(fieldVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -686,7 +715,7 @@ func (i *interpreter) manifestJSON(trace traceElement, v value) (interface{}, er
|
||||
default:
|
||||
return nil, makeRuntimeError(
|
||||
fmt.Sprintf("manifesting this value not implemented yet: %s", reflect.TypeOf(v)),
|
||||
i.getCurrentStackTrace(trace),
|
||||
i.getCurrentStackTrace(),
|
||||
)
|
||||
|
||||
}
|
||||
@ -790,8 +819,8 @@ func serializeJSON(v interface{}, multiline bool, indent string, buf *bytes.Buff
|
||||
}
|
||||
|
||||
func (i *interpreter) manifestAndSerializeJSON(
|
||||
buf *bytes.Buffer, trace traceElement, v value, multiline bool, indent string) error {
|
||||
manifested, err := i.manifestJSON(trace, v)
|
||||
buf *bytes.Buffer, v value, multiline bool, indent string) error {
|
||||
manifested, err := i.manifestJSON(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -800,19 +829,19 @@ func (i *interpreter) manifestAndSerializeJSON(
|
||||
}
|
||||
|
||||
// manifestString expects the value to be a string and returns it.
|
||||
func (i *interpreter) manifestString(buf *bytes.Buffer, trace traceElement, v value) error {
|
||||
func (i *interpreter) manifestString(buf *bytes.Buffer, v value) error {
|
||||
switch v := v.(type) {
|
||||
case valueString:
|
||||
buf.WriteString(v.getGoString())
|
||||
return nil
|
||||
default:
|
||||
return makeRuntimeError(fmt.Sprintf("expected string result, got: %s", v.getType().name), i.getCurrentStackTrace(trace))
|
||||
return makeRuntimeError(fmt.Sprintf("expected string result, got: %s", v.getType().name), i.getCurrentStackTrace())
|
||||
}
|
||||
}
|
||||
|
||||
func (i *interpreter) manifestAndSerializeMulti(trace traceElement, v value, stringOutputMode bool) (r map[string]string, err error) {
|
||||
func (i *interpreter) manifestAndSerializeMulti(v value, stringOutputMode bool) (r map[string]string, err error) {
|
||||
r = make(map[string]string)
|
||||
json, err := i.manifestJSON(trace, v)
|
||||
json, err := i.manifestJSON(v)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
@ -826,7 +855,7 @@ func (i *interpreter) manifestAndSerializeMulti(trace traceElement, v value, str
|
||||
default:
|
||||
msg := fmt.Sprintf("multi mode: top-level object's key %s has a value of type %T, "+
|
||||
"should be a string", filename, val)
|
||||
return r, makeRuntimeError(msg, i.getCurrentStackTrace(trace))
|
||||
return r, makeRuntimeError(msg, i.getCurrentStackTrace())
|
||||
}
|
||||
} else {
|
||||
var buf bytes.Buffer
|
||||
@ -839,14 +868,14 @@ func (i *interpreter) manifestAndSerializeMulti(trace traceElement, v value, str
|
||||
msg := fmt.Sprintf("multi mode: top-level object was a %s, "+
|
||||
"should be an object whose keys are filenames and values hold "+
|
||||
"the JSON for that file.", v.getType().name)
|
||||
return r, makeRuntimeError(msg, i.getCurrentStackTrace(trace))
|
||||
return r, makeRuntimeError(msg, i.getCurrentStackTrace())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (i *interpreter) manifestAndSerializeYAMLStream(trace traceElement, v value) (r []string, err error) {
|
||||
func (i *interpreter) manifestAndSerializeYAMLStream(v value) (r []string, err error) {
|
||||
r = make([]string, 0)
|
||||
json, err := i.manifestJSON(trace, v)
|
||||
json, err := i.manifestJSON(v)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
@ -862,12 +891,12 @@ func (i *interpreter) manifestAndSerializeYAMLStream(trace traceElement, v value
|
||||
msg := fmt.Sprintf("stream mode: top-level object was a %s, "+
|
||||
"should be an array whose elements hold "+
|
||||
"the JSON for each document in the stream.", v.getType().name)
|
||||
return r, makeRuntimeError(msg, i.getCurrentStackTrace(trace))
|
||||
return r, makeRuntimeError(msg, i.getCurrentStackTrace())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func jsonToValue(i *interpreter, trace traceElement, v interface{}) (value, error) {
|
||||
func jsonToValue(i *interpreter, v interface{}) (value, error) {
|
||||
switch v := v.(type) {
|
||||
case nil:
|
||||
return &nullValue, nil
|
||||
@ -875,7 +904,7 @@ func jsonToValue(i *interpreter, trace traceElement, v interface{}) (value, erro
|
||||
case []interface{}:
|
||||
elems := make([]*cachedThunk, len(v))
|
||||
for counter, elem := range v {
|
||||
val, err := jsonToValue(i, trace, elem)
|
||||
val, err := jsonToValue(i, elem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -886,12 +915,12 @@ func jsonToValue(i *interpreter, trace traceElement, v interface{}) (value, erro
|
||||
case bool:
|
||||
return makeValueBoolean(v), nil
|
||||
case float64:
|
||||
return makeDoubleCheck(i, trace, v)
|
||||
return makeDoubleCheck(i, v)
|
||||
|
||||
case map[string]interface{}:
|
||||
fieldMap := map[string]value{}
|
||||
for name, f := range v {
|
||||
val, err := jsonToValue(i, trace, f)
|
||||
val, err := jsonToValue(i, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -903,12 +932,12 @@ func jsonToValue(i *interpreter, trace traceElement, v interface{}) (value, erro
|
||||
return makeValueString(v), nil
|
||||
|
||||
default:
|
||||
return nil, i.Error(fmt.Sprintf("Not a json type: %#+v", v), trace)
|
||||
return nil, i.Error(fmt.Sprintf("Not a json type: %#+v", v))
|
||||
}
|
||||
}
|
||||
|
||||
func (i *interpreter) EvalInCleanEnv(fromWhere traceElement, env *environment, ast ast.Node, trimmable bool) (value, error) {
|
||||
err := i.newCall(fromWhere, *env, trimmable)
|
||||
func (i *interpreter) EvalInCleanEnv(env *environment, ast ast.Node, trimmable bool) (value, error) {
|
||||
err := i.newCall(*env, trimmable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -921,56 +950,54 @@ func (i *interpreter) EvalInCleanEnv(fromWhere traceElement, env *environment, a
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (i *interpreter) evaluatePV(ph potentialValue, trace traceElement) (value, error) {
|
||||
return ph.getValue(i, trace)
|
||||
func (i *interpreter) evaluatePV(ph potentialValue) (value, error) {
|
||||
return ph.getValue(i)
|
||||
}
|
||||
|
||||
func (i *interpreter) evaluateTailCall(function *valueFunction, args callArguments, tc tailCallStatus, trace traceElement) (value, error) {
|
||||
func (i *interpreter) evaluateTailCall(function *valueFunction, args callArguments, tc tailCallStatus) (value, error) {
|
||||
if tc == tailCall {
|
||||
i.stack.tailCallTrimStack()
|
||||
}
|
||||
return function.call(i, trace, args)
|
||||
return function.call(i, args)
|
||||
}
|
||||
|
||||
func (i *interpreter) Error(s string, trace traceElement) error {
|
||||
err := makeRuntimeError(s, i.getCurrentStackTrace(trace))
|
||||
func (i *interpreter) Error(s string) error {
|
||||
err := makeRuntimeError(s, i.getCurrentStackTrace())
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *interpreter) typeErrorSpecific(bad value, good value, trace traceElement) error {
|
||||
func (i *interpreter) typeErrorSpecific(bad value, good value) error {
|
||||
return i.Error(
|
||||
fmt.Sprintf("Unexpected type %v, expected %v", bad.getType().name, good.getType().name),
|
||||
trace,
|
||||
)
|
||||
}
|
||||
|
||||
func (i *interpreter) typeErrorGeneral(bad value, trace traceElement) error {
|
||||
func (i *interpreter) typeErrorGeneral(bad value) error {
|
||||
return i.Error(
|
||||
fmt.Sprintf("Unexpected type %v", bad.getType().name),
|
||||
trace,
|
||||
)
|
||||
}
|
||||
|
||||
func (i *interpreter) getNumber(val value, trace traceElement) (*valueNumber, error) {
|
||||
func (i *interpreter) getNumber(val value) (*valueNumber, error) {
|
||||
switch v := val.(type) {
|
||||
case *valueNumber:
|
||||
return v, nil
|
||||
default:
|
||||
return nil, i.typeErrorSpecific(val, &valueNumber{}, trace)
|
||||
return nil, i.typeErrorSpecific(val, &valueNumber{})
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:unused
|
||||
func (i *interpreter) evaluateNumber(pv potentialValue, trace traceElement) (*valueNumber, error) {
|
||||
v, err := i.evaluatePV(pv, trace)
|
||||
func (i *interpreter) evaluateNumber(pv potentialValue) (*valueNumber, error) {
|
||||
v, err := i.evaluatePV(pv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.getNumber(v, trace)
|
||||
return i.getNumber(v)
|
||||
}
|
||||
|
||||
func (i *interpreter) getInt(val value, trace traceElement) (int, error) {
|
||||
num, err := i.getNumber(val, trace)
|
||||
func (i *interpreter) getInt(val value) (int, error) {
|
||||
num, err := i.getNumber(val)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -978,128 +1005,128 @@ func (i *interpreter) getInt(val value, trace traceElement) (int, error) {
|
||||
// on any machine. And it's used only for indexing anyway.
|
||||
intNum := int(int32(num.value))
|
||||
if float64(intNum) != num.value {
|
||||
return 0, i.Error(fmt.Sprintf("Expected an integer, but got %v", num.value), trace)
|
||||
return 0, i.Error(fmt.Sprintf("Expected an integer, but got %v", num.value))
|
||||
}
|
||||
return intNum, nil
|
||||
}
|
||||
|
||||
func (i *interpreter) evaluateInt(pv potentialValue, trace traceElement) (int, error) {
|
||||
v, err := i.evaluatePV(pv, trace)
|
||||
func (i *interpreter) evaluateInt(pv potentialValue) (int, error) {
|
||||
v, err := i.evaluatePV(pv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i.getInt(v, trace)
|
||||
return i.getInt(v)
|
||||
}
|
||||
|
||||
//nolint:unused
|
||||
func (i *interpreter) getInt64(val value, trace traceElement) (int64, error) {
|
||||
num, err := i.getNumber(val, trace)
|
||||
func (i *interpreter) getInt64(val value) (int64, error) {
|
||||
num, err := i.getNumber(val)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
intNum := int64(num.value)
|
||||
if float64(intNum) != num.value {
|
||||
return 0, i.Error(fmt.Sprintf("Expected an integer, but got %v", num.value), trace)
|
||||
return 0, i.Error(fmt.Sprintf("Expected an integer, but got %v", num.value))
|
||||
}
|
||||
return intNum, nil
|
||||
}
|
||||
|
||||
//nolint:unused
|
||||
func (i *interpreter) evaluateInt64(pv potentialValue, trace traceElement) (int64, error) {
|
||||
v, err := i.evaluatePV(pv, trace)
|
||||
func (i *interpreter) evaluateInt64(pv potentialValue) (int64, error) {
|
||||
v, err := i.evaluatePV(pv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i.getInt64(v, trace)
|
||||
return i.getInt64(v)
|
||||
}
|
||||
|
||||
func (i *interpreter) getString(val value, trace traceElement) (valueString, error) {
|
||||
func (i *interpreter) getString(val value) (valueString, error) {
|
||||
switch v := val.(type) {
|
||||
case valueString:
|
||||
return v, nil
|
||||
default:
|
||||
return nil, i.typeErrorSpecific(val, emptyString(), trace)
|
||||
return nil, i.typeErrorSpecific(val, emptyString())
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:unused
|
||||
func (i *interpreter) evaluateString(pv potentialValue, trace traceElement) (valueString, error) {
|
||||
v, err := i.evaluatePV(pv, trace)
|
||||
func (i *interpreter) evaluateString(pv potentialValue) (valueString, error) {
|
||||
v, err := i.evaluatePV(pv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.getString(v, trace)
|
||||
return i.getString(v)
|
||||
}
|
||||
|
||||
func (i *interpreter) getBoolean(val value, trace traceElement) (*valueBoolean, error) {
|
||||
func (i *interpreter) getBoolean(val value) (*valueBoolean, error) {
|
||||
switch v := val.(type) {
|
||||
case *valueBoolean:
|
||||
return v, nil
|
||||
default:
|
||||
return nil, i.typeErrorSpecific(val, &valueBoolean{}, trace)
|
||||
return nil, i.typeErrorSpecific(val, &valueBoolean{})
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:unused
|
||||
func (i *interpreter) evaluateBoolean(pv potentialValue, trace traceElement) (*valueBoolean, error) {
|
||||
v, err := i.evaluatePV(pv, trace)
|
||||
func (i *interpreter) evaluateBoolean(pv potentialValue) (*valueBoolean, error) {
|
||||
v, err := i.evaluatePV(pv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.getBoolean(v, trace)
|
||||
return i.getBoolean(v)
|
||||
}
|
||||
|
||||
func (i *interpreter) getArray(val value, trace traceElement) (*valueArray, error) {
|
||||
func (i *interpreter) getArray(val value) (*valueArray, error) {
|
||||
switch v := val.(type) {
|
||||
case *valueArray:
|
||||
return v, nil
|
||||
default:
|
||||
return nil, i.typeErrorSpecific(val, &valueArray{}, trace)
|
||||
return nil, i.typeErrorSpecific(val, &valueArray{})
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:unused
|
||||
func (i *interpreter) evaluateArray(pv potentialValue, trace traceElement) (*valueArray, error) {
|
||||
v, err := i.evaluatePV(pv, trace)
|
||||
func (i *interpreter) evaluateArray(pv potentialValue) (*valueArray, error) {
|
||||
v, err := i.evaluatePV(pv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.getArray(v, trace)
|
||||
return i.getArray(v)
|
||||
}
|
||||
|
||||
func (i *interpreter) getFunction(val value, trace traceElement) (*valueFunction, error) {
|
||||
func (i *interpreter) getFunction(val value) (*valueFunction, error) {
|
||||
switch v := val.(type) {
|
||||
case *valueFunction:
|
||||
return v, nil
|
||||
default:
|
||||
return nil, i.typeErrorSpecific(val, &valueFunction{}, trace)
|
||||
return nil, i.typeErrorSpecific(val, &valueFunction{})
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:unused
|
||||
func (i *interpreter) evaluateFunction(pv potentialValue, trace traceElement) (*valueFunction, error) {
|
||||
v, err := i.evaluatePV(pv, trace)
|
||||
func (i *interpreter) evaluateFunction(pv potentialValue) (*valueFunction, error) {
|
||||
v, err := i.evaluatePV(pv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.getFunction(v, trace)
|
||||
return i.getFunction(v)
|
||||
}
|
||||
|
||||
func (i *interpreter) getObject(val value, trace traceElement) (*valueObject, error) {
|
||||
func (i *interpreter) getObject(val value) (*valueObject, error) {
|
||||
switch v := val.(type) {
|
||||
case *valueObject:
|
||||
return v, nil
|
||||
default:
|
||||
return nil, i.typeErrorSpecific(val, &valueObject{}, trace)
|
||||
return nil, i.typeErrorSpecific(val, &valueObject{})
|
||||
}
|
||||
}
|
||||
|
||||
func (i *interpreter) evaluateObject(pv potentialValue, trace traceElement) (*valueObject, error) {
|
||||
v, err := i.evaluatePV(pv, trace)
|
||||
func (i *interpreter) evaluateObject(pv potentialValue) (*valueObject, error) {
|
||||
v, err := i.evaluatePV(pv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.getObject(v, trace)
|
||||
return i.getObject(v)
|
||||
}
|
||||
|
||||
func buildStdObject(i *interpreter) (*valueObject, error) {
|
||||
@ -1128,7 +1155,9 @@ func evaluateStd(i *interpreter) (value, error) {
|
||||
evalLoc := ast.MakeLocationRangeMessage("During evaluation of std")
|
||||
evalTrace := traceElement{loc: &evalLoc}
|
||||
node := astgen.StdAst
|
||||
return i.EvalInCleanEnv(evalTrace, &beforeStdEnv, node, false)
|
||||
i.stack.setCurrentTrace(evalTrace)
|
||||
defer i.stack.clearCurrentTrace()
|
||||
return i.EvalInCleanEnv(&beforeStdEnv, node, false)
|
||||
}
|
||||
|
||||
func prepareExtVars(i *interpreter, ext vmExtMap, kind string) map[string]*cachedThunk {
|
||||
@ -1188,7 +1217,9 @@ func evaluateAux(i *interpreter, node ast.Node, tla vmExtMap) (value, traceEleme
|
||||
loc: &evalLoc,
|
||||
}
|
||||
env := makeInitialEnv(node.Loc().FileName, i.baseStd)
|
||||
result, err := i.EvalInCleanEnv(evalTrace, &env, node, false)
|
||||
i.stack.setCurrentTrace(evalTrace)
|
||||
result, err := i.EvalInCleanEnv(&env, node, false)
|
||||
i.stack.clearCurrentTrace()
|
||||
if err != nil {
|
||||
return nil, traceElement{}, err
|
||||
}
|
||||
@ -1199,11 +1230,13 @@ func evaluateAux(i *interpreter, node ast.Node, tla vmExtMap) (value, traceEleme
|
||||
for argName, pv := range toplevelArgMap {
|
||||
args.named = append(args.named, namedCallArgument{name: ast.Identifier(argName), pv: pv})
|
||||
}
|
||||
funcLoc := ast.MakeLocationRangeMessage("Top-level function")
|
||||
funcLoc := ast.MakeLocationRangeMessage("Top-level function call")
|
||||
funcTrace := traceElement{
|
||||
loc: &funcLoc,
|
||||
}
|
||||
result, err = f.call(i, funcTrace, args)
|
||||
i.stack.setCurrentTrace(funcTrace)
|
||||
result, err = f.call(i, args)
|
||||
i.stack.clearCurrentTrace()
|
||||
if err != nil {
|
||||
return nil, traceElement{}, err
|
||||
}
|
||||
@ -1230,11 +1263,13 @@ func evaluate(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[string]
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
i.stack.setCurrentTrace(manifestationTrace)
|
||||
if stringOutputMode {
|
||||
err = i.manifestString(&buf, manifestationTrace, result)
|
||||
err = i.manifestString(&buf, result)
|
||||
} else {
|
||||
err = i.manifestAndSerializeJSON(&buf, manifestationTrace, result, true, "")
|
||||
err = i.manifestAndSerializeJSON(&buf, result, true, "")
|
||||
}
|
||||
i.stack.clearCurrentTrace()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -1256,7 +1291,10 @@ func evaluateMulti(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[st
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return i.manifestAndSerializeMulti(manifestationTrace, result, stringOutputMode)
|
||||
i.stack.setCurrentTrace(manifestationTrace)
|
||||
manifested, err := i.manifestAndSerializeMulti(result, stringOutputMode)
|
||||
i.stack.clearCurrentTrace()
|
||||
return manifested, err
|
||||
}
|
||||
|
||||
// TODO(sbarzowski) this function takes far too many arguments - build interpreter in vm instead
|
||||
@ -1273,5 +1311,8 @@ func evaluateStream(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[s
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return i.manifestAndSerializeYAMLStream(manifestationTrace, result)
|
||||
i.stack.setCurrentTrace(manifestationTrace)
|
||||
manifested, err := i.manifestAndSerializeYAMLStream(result)
|
||||
i.stack.clearCurrentTrace()
|
||||
return manifested, err
|
||||
}
|
||||
|
10
testdata/array_comp_try_iterate_over_obj.golden
vendored
Normal file
10
testdata/array_comp_try_iterate_over_obj.golden
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
RUNTIME ERROR: std.flatMap second param must be array / string, got object
|
||||
-------------------------------------------------
|
||||
testdata/array_comp_try_iterate_over_obj:1:1-16
|
||||
|
||||
[a for a in {}]
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
||||
|
1
testdata/array_comp_try_iterate_over_obj.jsonnet
vendored
Normal file
1
testdata/array_comp_try_iterate_over_obj.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
||||
[a for a in {}]
|
0
testdata/array_comp_try_iterate_over_obj.linter.golden
vendored
Normal file
0
testdata/array_comp_try_iterate_over_obj.linter.golden
vendored
Normal file
4
testdata/arrcomp_if6.golden
vendored
4
testdata/arrcomp_if6.golden
vendored
@ -5,7 +5,9 @@ RUNTIME ERROR: x
|
||||
[x for x in [1] if error "x"]
|
||||
|
||||
-------------------------------------------------
|
||||
builtin function <flatMap>
|
||||
testdata/arrcomp_if6:1:1-30
|
||||
|
||||
[x for x in [1] if error "x"]
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
4
testdata/arrcomp_if7.golden
vendored
4
testdata/arrcomp_if7.golden
vendored
@ -3,7 +3,9 @@ RUNTIME ERROR: Unexpected type number, expected boolean
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
builtin function <flatMap>
|
||||
testdata/arrcomp_if7:1:1-29
|
||||
|
||||
[x for x in [1, 2, 3] if 42]
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: failed to decode: illegal base64 data at input byte 0
|
||||
-------------------------------------------------
|
||||
testdata/builtinBase64DecodeBytes_high_codepoint:1:1-30 builtin function <base64DecodeBytes>
|
||||
testdata/builtinBase64DecodeBytes_high_codepoint:1:1-30 $
|
||||
|
||||
std.base64DecodeBytes("ĀQ=")
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: input string appears not to be a base64 encoded string. Wrong length found (5)
|
||||
-------------------------------------------------
|
||||
testdata/builtinBase64DecodeBytes_invalid_base64_data:1:1-31 builtin function <base64DecodeBytes>
|
||||
testdata/builtinBase64DecodeBytes_invalid_base64_data:1:1-31 $
|
||||
|
||||
std.base64DecodeBytes("wrong")
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: base64DecodeBytes requires a string, got number
|
||||
-------------------------------------------------
|
||||
testdata/builtinBase64DecodeBytes_wrong_type:1:1-25 builtin function <base64DecodeBytes>
|
||||
testdata/builtinBase64DecodeBytes_wrong_type:1:1-25 $
|
||||
|
||||
std.base64DecodeBytes(1)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: failed to decode: illegal base64 data at input byte 0
|
||||
-------------------------------------------------
|
||||
testdata/builtinBase64Decode_high_codepoint:1:1-25 builtin function <base64Decode>
|
||||
testdata/builtinBase64Decode_high_codepoint:1:1-25 $
|
||||
|
||||
std.base64Decode("ĀQ=")
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: input string appears not to be a base64 encoded string. Wrong length found (5)
|
||||
-------------------------------------------------
|
||||
testdata/builtinBase64Decode_invalid_base64_data:1:1-26 builtin function <base64Decode>
|
||||
testdata/builtinBase64Decode_invalid_base64_data:1:1-26 $
|
||||
|
||||
std.base64Decode("wrong")
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: base64DecodeBytes requires a string, got number
|
||||
-------------------------------------------------
|
||||
testdata/builtinBase64Decode_wrong_type:1:1-20 builtin function <base64Decode>
|
||||
testdata/builtinBase64Decode_wrong_type:1:1-20 $
|
||||
|
||||
std.base64Decode(1)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: base64 encountered a non-integer value in the array, got string
|
||||
-------------------------------------------------
|
||||
testdata/builtinBase64_invalid_byte_array:1:1-23 builtin function <base64>
|
||||
testdata/builtinBase64_invalid_byte_array:1:1-23 $
|
||||
|
||||
std.base64([1, "foo"])
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: base64 encountered invalid codepoint value in the array (must be 0 <= X <= 255), got -1
|
||||
-------------------------------------------------
|
||||
testdata/builtinBase64_invalid_byte_array1:1:1-20 builtin function <base64>
|
||||
testdata/builtinBase64_invalid_byte_array1:1:1-20 $
|
||||
|
||||
std.base64([1, -1])
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: base64 encountered invalid codepoint value in the array (must be 0 <= X <= 255), got 256
|
||||
-------------------------------------------------
|
||||
testdata/builtinBase64_invalid_byte_array2:1:1-21 builtin function <base64>
|
||||
testdata/builtinBase64_invalid_byte_array2:1:1-21 $
|
||||
|
||||
std.base64([1, 256])
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: base64 can only base64 encode strings / arrays of single bytes, got number
|
||||
-------------------------------------------------
|
||||
testdata/builtinBase64_non_string_non_array:1:1-14 builtin function <base64>
|
||||
testdata/builtinBase64_non_string_non_array:1:1-14 $
|
||||
|
||||
std.base64(1)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: base64 encountered invalid codepoint value in the array (must be 0 <= X <= 255), got 256
|
||||
-------------------------------------------------
|
||||
testdata/builtinBase64_string_high_codepoint:1:1-17 builtin function <base64>
|
||||
testdata/builtinBase64_string_high_codepoint:1:1-17 $
|
||||
|
||||
std.base64("Ā")
|
||||
|
||||
|
2
testdata/builtinChar3.golden
vendored
2
testdata/builtinChar3.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Codepoints must be >= 0, got -1
|
||||
-------------------------------------------------
|
||||
testdata/builtinChar3:1:1-13 builtin function <char>
|
||||
testdata/builtinChar3:1:1-13 $
|
||||
|
||||
std.char(-1)
|
||||
|
||||
|
2
testdata/builtinChar5.golden
vendored
2
testdata/builtinChar5.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Invalid unicode codepoint, got 1.114112e+06
|
||||
-------------------------------------------------
|
||||
testdata/builtinChar5:2:1-18 builtin function <char>
|
||||
testdata/builtinChar5:2:1-18 $
|
||||
|
||||
std.char(1114112)
|
||||
|
||||
|
2
testdata/builtinChar7.golden
vendored
2
testdata/builtinChar7.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected number
|
||||
-------------------------------------------------
|
||||
testdata/builtinChar7:1:1-16 builtin function <char>
|
||||
testdata/builtinChar7:1:1-16 $
|
||||
|
||||
std.char("xxx")
|
||||
|
||||
|
2
testdata/builtinObjectFieldsEx_bad.golden
vendored
2
testdata/builtinObjectFieldsEx_bad.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type number, expected object
|
||||
-------------------------------------------------
|
||||
testdata/builtinObjectFieldsEx_bad:1:1-29 builtin function <objectFieldsEx>
|
||||
testdata/builtinObjectFieldsEx_bad:1:1-29 $
|
||||
|
||||
std.objectFieldsEx(42, true)
|
||||
|
||||
|
2
testdata/builtinObjectFieldsEx_bad2.golden
vendored
2
testdata/builtinObjectFieldsEx_bad2.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected boolean
|
||||
-------------------------------------------------
|
||||
testdata/builtinObjectFieldsEx_bad2:1:1-30 builtin function <objectFieldsEx>
|
||||
testdata/builtinObjectFieldsEx_bad2:1:1-30 $
|
||||
|
||||
std.objectFieldsEx({}, "xxx")
|
||||
|
||||
|
2
testdata/builtinObjectHasExBadBoolean.golden
vendored
2
testdata/builtinObjectHasExBadBoolean.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected boolean
|
||||
-------------------------------------------------
|
||||
testdata/builtinObjectHasExBadBoolean:1:1-34 builtin function <objectHasEx>
|
||||
testdata/builtinObjectHasExBadBoolean:1:1-34 $
|
||||
|
||||
std.objectHasEx({}, "xxx", "xxx")
|
||||
|
||||
|
2
testdata/builtinObjectHasExBadField.golden
vendored
2
testdata/builtinObjectHasExBadField.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type number, expected string
|
||||
-------------------------------------------------
|
||||
testdata/builtinObjectHasExBadField:1:1-31 builtin function <objectHasEx>
|
||||
testdata/builtinObjectHasExBadField:1:1-31 $
|
||||
|
||||
std.objectHasEx({}, 42, false)
|
||||
|
||||
|
2
testdata/builtinObjectHasExBadObject.golden
vendored
2
testdata/builtinObjectHasExBadObject.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type number, expected object
|
||||
-------------------------------------------------
|
||||
testdata/builtinObjectHasExBadObject:1:1-32 builtin function <objectHasEx>
|
||||
testdata/builtinObjectHasExBadObject:1:1-32 $
|
||||
|
||||
std.objectHasEx(42, "x", false)
|
||||
|
||||
|
2
testdata/builtinReverse_not_array.golden
vendored
2
testdata/builtinReverse_not_array.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected array
|
||||
-------------------------------------------------
|
||||
testdata/builtinReverse_not_array:1:1-20 builtin function <reverse>
|
||||
testdata/builtinReverse_not_array:1:1-20 $
|
||||
|
||||
std.reverse("asdf")
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: substr first parameter should be a string, got number
|
||||
-------------------------------------------------
|
||||
testdata/builtinSubStr_first_param_not_string:1:1-20 builtin function <substr>
|
||||
testdata/builtinSubStr_first_param_not_string:1:1-20 $
|
||||
|
||||
std.substr(1, 0, 1)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: substr second parameter should be an integer, got 1.200000
|
||||
-------------------------------------------------
|
||||
testdata/builtinSubStr_second_parameter_not_integer:1:1-28 builtin function <substr>
|
||||
testdata/builtinSubStr_second_parameter_not_integer:1:1-28 $
|
||||
|
||||
std.substr("hello", 1.2, 5)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: substr second parameter should be a number, got string
|
||||
-------------------------------------------------
|
||||
testdata/builtinSubStr_second_parameter_not_number:1:1-30 builtin function <substr>
|
||||
testdata/builtinSubStr_second_parameter_not_number:1:1-30 $
|
||||
|
||||
std.substr("hello", "foo", 5)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: substr third parameter should be greater than zero, got -1
|
||||
-------------------------------------------------
|
||||
testdata/builtinSubStr_third_parameter_less_then_zero:1:1-27 builtin function <substr>
|
||||
testdata/builtinSubStr_third_parameter_less_then_zero:1:1-27 $
|
||||
|
||||
std.substr("hello", 0, -1)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: substr third parameter should be an integer, got 1.200000
|
||||
-------------------------------------------------
|
||||
testdata/builtinSubStr_third_parameter_not_integer:1:1-28 builtin function <substr>
|
||||
testdata/builtinSubStr_third_parameter_not_integer:1:1-28 $
|
||||
|
||||
std.substr("hello", 0, 1.2)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: substr third parameter should be a number, got string
|
||||
-------------------------------------------------
|
||||
testdata/builtinSubStr_third_parameter_not_number:1:1-30 builtin function <substr>
|
||||
testdata/builtinSubStr_third_parameter_not_number:1:1-30 $
|
||||
|
||||
std.substr("hello", 0, "foo")
|
||||
|
||||
|
2
testdata/builtin_exp3.golden
vendored
2
testdata/builtin_exp3.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Overflow
|
||||
-------------------------------------------------
|
||||
testdata/builtin_exp3:1:1-14 builtin function <exp>
|
||||
testdata/builtin_exp3:1:1-14 $
|
||||
|
||||
std.exp(1000)
|
||||
|
||||
|
2
testdata/builtin_exp5.golden
vendored
2
testdata/builtin_exp5.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Overflow
|
||||
-------------------------------------------------
|
||||
testdata/builtin_exp5:1:1-31 builtin function <exp>
|
||||
testdata/builtin_exp5:1:1-31 $
|
||||
|
||||
std.exp(100000000000000000000)
|
||||
|
||||
|
2
testdata/builtin_log5.golden
vendored
2
testdata/builtin_log5.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Overflow
|
||||
-------------------------------------------------
|
||||
testdata/builtin_log5:1:1-11 builtin function <log>
|
||||
testdata/builtin_log5:1:1-11 $
|
||||
|
||||
std.log(0)
|
||||
|
||||
|
2
testdata/builtin_log7.golden
vendored
2
testdata/builtin_log7.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Not a number
|
||||
-------------------------------------------------
|
||||
testdata/builtin_log7:1:1-12 builtin function <log>
|
||||
testdata/builtin_log7:1:1-12 $
|
||||
|
||||
std.log(-1)
|
||||
|
||||
|
2
testdata/builtin_log8.golden
vendored
2
testdata/builtin_log8.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Not a number
|
||||
-------------------------------------------------
|
||||
testdata/builtin_log8:1:1-24 builtin function <log>
|
||||
testdata/builtin_log8:1:1-24 $
|
||||
|
||||
std.log(-1000000000000)
|
||||
|
||||
|
2
testdata/builtin_sqrt2.golden
vendored
2
testdata/builtin_sqrt2.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected number
|
||||
-------------------------------------------------
|
||||
testdata/builtin_sqrt2:1:1-19 builtin function <sqrt>
|
||||
testdata/builtin_sqrt2:1:1-19 $
|
||||
|
||||
std.sqrt("cookie")
|
||||
|
||||
|
4
testdata/cpp-tests-override/ext3.golden.stderr
vendored
Normal file
4
testdata/cpp-tests-override/ext3.golden.stderr
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
RUNTIME ERROR: Undefined external variable: x
|
||||
<cmdline>:1:1-16 $
|
||||
During evaluation
|
||||
|
3
testdata/cpp-tests-override/tla3.golden.stderr
vendored
Normal file
3
testdata/cpp-tests-override/tla3.golden.stderr
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
RUNTIME ERROR: function has no parameter y
|
||||
Top-level function call
|
||||
|
3
testdata/cpp-tests-override/tla7.golden.stderr
vendored
Normal file
3
testdata/cpp-tests-override/tla7.golden.stderr
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
RUNTIME ERROR: function has no parameter x
|
||||
Top-level function call
|
||||
|
2
testdata/error_function_fail.golden
vendored
2
testdata/error_function_fail.golden
vendored
@ -1,4 +1,4 @@
|
||||
RUNTIME ERROR: couldn't manifest function in JSON output.
|
||||
RUNTIME ERROR: couldn't manifest function as JSON
|
||||
-------------------------------------------------
|
||||
testdata/error_function_fail:1:1-23 $
|
||||
|
||||
|
2
testdata/extvar_error.golden
vendored
2
testdata/extvar_error.golden
vendored
@ -5,7 +5,7 @@ RUNTIME ERROR: xxx
|
||||
error 'xxx'
|
||||
|
||||
-------------------------------------------------
|
||||
testdata/extvar_error:1:1-23 builtin function <extVar>
|
||||
testdata/extvar_error:1:1-23 $
|
||||
|
||||
std.extVar("errorVar")
|
||||
|
||||
|
2
testdata/extvar_not_a_string.golden
vendored
2
testdata/extvar_not_a_string.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type number, expected string
|
||||
-------------------------------------------------
|
||||
testdata/extvar_not_a_string:1:1-15 builtin function <extVar>
|
||||
testdata/extvar_not_a_string:1:1-15 $
|
||||
|
||||
std.extVar(42)
|
||||
|
||||
|
2
testdata/extvar_unknown.golden
vendored
2
testdata/extvar_unknown.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Undefined external variable: UNKNOWN
|
||||
-------------------------------------------------
|
||||
testdata/extvar_unknown:1:1-22 builtin function <extVar>
|
||||
testdata/extvar_unknown:1:1-22 $
|
||||
|
||||
std.extVar("UNKNOWN")
|
||||
|
||||
|
2
testdata/function_manifested.golden
vendored
2
testdata/function_manifested.golden
vendored
@ -1,4 +1,4 @@
|
||||
RUNTIME ERROR: couldn't manifest function in JSON output.
|
||||
RUNTIME ERROR: couldn't manifest function as JSON
|
||||
-------------------------------------------------
|
||||
During manifestation
|
||||
|
||||
|
2
testdata/function_plus_string.golden
vendored
2
testdata/function_plus_string.golden
vendored
@ -1,4 +1,4 @@
|
||||
RUNTIME ERROR: couldn't manifest function in JSON output.
|
||||
RUNTIME ERROR: couldn't manifest function as JSON
|
||||
-------------------------------------------------
|
||||
testdata/function_plus_string:1:1-24 $
|
||||
|
||||
|
2
testdata/function_too_many_params.golden
vendored
2
testdata/function_too_many_params.golden
vendored
@ -1,5 +1,5 @@
|
||||
RUNTIME ERROR: Missing argument: x
|
||||
-------------------------------------------------
|
||||
Top-level function
|
||||
Top-level function call
|
||||
|
||||
|
||||
|
2
testdata/native5.golden
vendored
2
testdata/native5.golden
vendored
@ -1,4 +1,4 @@
|
||||
RUNTIME ERROR: couldn't manifest function in JSON output.
|
||||
RUNTIME ERROR: couldn't manifest function as JSON
|
||||
-------------------------------------------------
|
||||
testdata/native5:1:1-42 $
|
||||
|
||||
|
4
testdata/object_comp_duplicate.golden
vendored
4
testdata/object_comp_duplicate.golden
vendored
@ -1,6 +1,8 @@
|
||||
RUNTIME ERROR: Duplicate field name: "x"
|
||||
-------------------------------------------------
|
||||
builtin function <$objectFlatMerge>
|
||||
testdata/object_comp_duplicate:1:1-31
|
||||
|
||||
{ [x]: x for x in ["x", "x"] }
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
4
testdata/object_comp_err_index.golden
vendored
4
testdata/object_comp_err_index.golden
vendored
@ -5,7 +5,9 @@ RUNTIME ERROR: xxx
|
||||
{ [error "xxx"]: 42 for x in [1] }
|
||||
|
||||
-------------------------------------------------
|
||||
builtin function <$objectFlatMerge>
|
||||
testdata/object_comp_err_index:1:1-35
|
||||
|
||||
{ [error "xxx"]: 42 for x in [1] }
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
4
testdata/object_comp_int_index.golden
vendored
4
testdata/object_comp_int_index.golden
vendored
@ -5,7 +5,9 @@ RUNTIME ERROR: Field name must be string, got number
|
||||
{ [x]: x for x in [1, 2, 3] }
|
||||
|
||||
-------------------------------------------------
|
||||
builtin function <$objectFlatMerge>
|
||||
testdata/object_comp_int_index:1:1-30
|
||||
|
||||
{ [x]: x for x in [1, 2, 3] }
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
4
testdata/percent_bad.golden
vendored
4
testdata/percent_bad.golden
vendored
@ -5,7 +5,9 @@ RUNTIME ERROR: Operator % cannot be used on types number and string.
|
||||
error 'Operator % cannot be used on types ' + std.type(a) + ' and ' + std.type(b) + '.',
|
||||
|
||||
-------------------------------------------------
|
||||
|
||||
testdata/percent_bad:1:1-9
|
||||
|
||||
42 % "x"
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
4
testdata/percent_bad2.golden
vendored
4
testdata/percent_bad2.golden
vendored
@ -20,7 +20,9 @@ RUNTIME ERROR: Too many values to format: 1, expected 0
|
||||
std.format(a, b)
|
||||
|
||||
-------------------------------------------------
|
||||
|
||||
testdata/percent_bad2:1:1-9
|
||||
|
||||
"x" % 42
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
4
testdata/percent_bad3.golden
vendored
4
testdata/percent_bad3.golden
vendored
@ -5,7 +5,9 @@ RUNTIME ERROR: Operator % cannot be used on types function and number.
|
||||
error 'Operator % cannot be used on types ' + std.type(a) + ' and ' + std.type(b) + '.',
|
||||
|
||||
-------------------------------------------------
|
||||
|
||||
testdata/percent_bad3:1:1-21
|
||||
|
||||
(function(x) x) % 42
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
4
testdata/percent_format_str4.golden
vendored
4
testdata/percent_format_str4.golden
vendored
@ -20,7 +20,9 @@ RUNTIME ERROR: Too many values to format: 2, expected 1
|
||||
std.format(a, b)
|
||||
|
||||
-------------------------------------------------
|
||||
|
||||
testdata/percent_format_str4:1:1-20
|
||||
|
||||
"x %s" % ["y", "z"]
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
4
testdata/percent_format_str5.golden
vendored
4
testdata/percent_format_str5.golden
vendored
@ -37,7 +37,9 @@ RUNTIME ERROR: Not enough values to format: 1, expected more than 1
|
||||
std.format(a, b)
|
||||
|
||||
-------------------------------------------------
|
||||
|
||||
testdata/percent_format_str5:1:1-18
|
||||
|
||||
"x %s %s" % ["y"]
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
4
testdata/percent_format_str6.golden
vendored
4
testdata/percent_format_str6.golden
vendored
@ -37,7 +37,9 @@ RUNTIME ERROR: Not enough values to format: 1, expected more than 1
|
||||
std.format(a, b)
|
||||
|
||||
-------------------------------------------------
|
||||
|
||||
testdata/percent_format_str6:1:1-16
|
||||
|
||||
"x %s %s" % "y"
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
4
testdata/percent_format_str7.golden
vendored
4
testdata/percent_format_str7.golden
vendored
@ -38,7 +38,9 @@ RUNTIME ERROR: Format required number at 0, got string
|
||||
std.format(a, b)
|
||||
|
||||
-------------------------------------------------
|
||||
|
||||
testdata/percent_format_str7:1:1-15
|
||||
|
||||
"x %d" % ["y"]
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
6
testdata/percent_mod_int5.golden
vendored
6
testdata/percent_mod_int5.golden
vendored
@ -1,11 +1,13 @@
|
||||
RUNTIME ERROR: Division by zero.
|
||||
-------------------------------------------------
|
||||
<std>:235:7-23 builtin function <modulo>
|
||||
<std>:235:7-23 function <anonymous>
|
||||
|
||||
std.modulo(a, b)
|
||||
|
||||
-------------------------------------------------
|
||||
|
||||
testdata/percent_mod_int5:1:1-7
|
||||
|
||||
42 % 0
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
2
testdata/pow4.golden
vendored
2
testdata/pow4.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Not a number
|
||||
-------------------------------------------------
|
||||
testdata/pow4:1:1-17 builtin function <pow>
|
||||
testdata/pow4:1:1-17 $
|
||||
|
||||
std.pow(-1, 0.2)
|
||||
|
||||
|
2
testdata/pow7.golden
vendored
2
testdata/pow7.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Overflow
|
||||
-------------------------------------------------
|
||||
testdata/pow7:2:1-23 builtin function <pow>
|
||||
testdata/pow7:2:1-23 $
|
||||
|
||||
std.pow(1.1, 7447.082)
|
||||
|
||||
|
2
testdata/pow8.golden
vendored
2
testdata/pow8.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected number
|
||||
-------------------------------------------------
|
||||
testdata/pow8:1:1-19 builtin function <pow>
|
||||
testdata/pow8:1:1-19 $
|
||||
|
||||
std.pow("xxx", 42)
|
||||
|
||||
|
2
testdata/pow9.golden
vendored
2
testdata/pow9.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected number
|
||||
-------------------------------------------------
|
||||
testdata/pow9:1:1-19 builtin function <pow>
|
||||
testdata/pow9:1:1-19 $
|
||||
|
||||
std.pow(42, "xxx")
|
||||
|
||||
|
2
testdata/std.codepoint3.golden
vendored
2
testdata/std.codepoint3.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: codepoint takes a string of length 1, got length 2
|
||||
-------------------------------------------------
|
||||
testdata/std.codepoint3:1:1-20 builtin function <codepoint>
|
||||
testdata/std.codepoint3:1:1-20 $
|
||||
|
||||
std.codepoint("aa")
|
||||
|
||||
|
2
testdata/std.codepoint6.golden
vendored
2
testdata/std.codepoint6.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: codepoint takes a string of length 1, got length 0
|
||||
-------------------------------------------------
|
||||
testdata/std.codepoint6:1:1-18 builtin function <codepoint>
|
||||
testdata/std.codepoint6:1:1-18 $
|
||||
|
||||
std.codepoint("")
|
||||
|
||||
|
2
testdata/std.codepoint7.golden
vendored
2
testdata/std.codepoint7.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: codepoint takes a string of length 1, got length 2
|
||||
-------------------------------------------------
|
||||
testdata/std.codepoint7:2:1-21 builtin function <codepoint>
|
||||
testdata/std.codepoint7:2:1-21 $
|
||||
|
||||
std.codepoint("ą")
|
||||
|
||||
|
2
testdata/std.codepoint8.golden
vendored
2
testdata/std.codepoint8.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type number, expected string
|
||||
-------------------------------------------------
|
||||
testdata/std.codepoint8:1:1-18 builtin function <codepoint>
|
||||
testdata/std.codepoint8:1:1-18 $
|
||||
|
||||
std.codepoint(42)
|
||||
|
||||
|
2
testdata/std.filter4.golden
vendored
2
testdata/std.filter4.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type number, expected function
|
||||
-------------------------------------------------
|
||||
testdata/std.filter4:1:1-19 builtin function <filter>
|
||||
testdata/std.filter4:1:1-19 $
|
||||
|
||||
std.filter(42, [])
|
||||
|
||||
|
2
testdata/std.filter5.golden
vendored
2
testdata/std.filter5.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type number, expected array
|
||||
-------------------------------------------------
|
||||
testdata/std.filter5:1:1-31 builtin function <filter>
|
||||
testdata/std.filter5:1:1-31 $
|
||||
|
||||
std.filter(function(n) 42, 42)
|
||||
|
||||
|
2
testdata/std.filter6.golden
vendored
2
testdata/std.filter6.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected array
|
||||
-------------------------------------------------
|
||||
testdata/std.filter6:1:1-21 builtin function <filter>
|
||||
testdata/std.filter6:1:1-21 $
|
||||
|
||||
std.filter(42, "42")
|
||||
|
||||
|
2
testdata/std.filter8.golden
vendored
2
testdata/std.filter8.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type function, expected array
|
||||
-------------------------------------------------
|
||||
testdata/std.filter8:1:1-36 builtin function <filter>
|
||||
testdata/std.filter8:1:1-36 $
|
||||
|
||||
std.filter([42], function(i) "xxx")
|
||||
|
||||
|
2
testdata/std.filter_swapped_args.golden
vendored
2
testdata/std.filter_swapped_args.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type function, expected array
|
||||
-------------------------------------------------
|
||||
testdata/std.filter_swapped_args:1:1-38 builtin function <filter>
|
||||
testdata/std.filter_swapped_args:1:1-38 $
|
||||
|
||||
std.filter([1,2,3], function(n) true)
|
||||
|
||||
|
2
testdata/std.flatmap5.golden
vendored
2
testdata/std.flatmap5.golden
vendored
@ -5,7 +5,7 @@ RUNTIME ERROR: a
|
||||
local failWith(x) = error x;
|
||||
|
||||
-------------------------------------------------
|
||||
testdata/std.flatmap5:2:10-48 builtin function <flatMap>
|
||||
testdata/std.flatmap5:2:10-48 thunk from <$>
|
||||
|
||||
std.type(std.flatMap(failWith, ["a", "b", "c"]))
|
||||
|
||||
|
2
testdata/std.join7.golden
vendored
2
testdata/std.join7.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type array, expected string
|
||||
-------------------------------------------------
|
||||
testdata/std.join7:1:1-27 builtin function <join>
|
||||
testdata/std.join7:1:1-27 $
|
||||
|
||||
std.join("aa", [[1], [2]])
|
||||
|
||||
|
2
testdata/std.join8.golden
vendored
2
testdata/std.join8.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected array
|
||||
-------------------------------------------------
|
||||
testdata/std.join8:1:1-33 builtin function <join>
|
||||
testdata/std.join8:1:1-33 $
|
||||
|
||||
std.join([3, 4], [[1, 2], "56"])
|
||||
|
||||
|
2
testdata/std.makeArray_bad.golden
vendored
2
testdata/std.makeArray_bad.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected number
|
||||
-------------------------------------------------
|
||||
testdata/std.makeArray_bad:1:1-36 builtin function <makeArray>
|
||||
testdata/std.makeArray_bad:1:1-36 $
|
||||
|
||||
std.makeArray("xxx", function(i) i)
|
||||
|
||||
|
2
testdata/std.makeArray_bad2.golden
vendored
2
testdata/std.makeArray_bad2.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected function
|
||||
-------------------------------------------------
|
||||
testdata/std.makeArray_bad2:1:1-25 builtin function <makeArray>
|
||||
testdata/std.makeArray_bad2:1:1-25 $
|
||||
|
||||
std.makeArray(42, "xxx")
|
||||
|
||||
|
2
testdata/std.makeArray_noninteger.golden
vendored
2
testdata/std.makeArray_noninteger.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Expected an integer, but got 2.5
|
||||
-------------------------------------------------
|
||||
testdata/std.makeArray_noninteger:1:1-34 builtin function <makeArray>
|
||||
testdata/std.makeArray_noninteger:1:1-34 $
|
||||
|
||||
std.makeArray(2.5, function(i) i)
|
||||
|
||||
|
2
testdata/std.makeArray_noninteger_big.golden
vendored
2
testdata/std.makeArray_noninteger_big.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Expected an integer, but got 1e+100
|
||||
-------------------------------------------------
|
||||
testdata/std.makeArray_noninteger_big:1:1-36 builtin function <makeArray>
|
||||
testdata/std.makeArray_noninteger_big:1:1-36 $
|
||||
|
||||
std.makeArray(1e100, function(i) i)
|
||||
|
||||
|
2
testdata/std.md5_6.golden
vendored
2
testdata/std.md5_6.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type number, expected string
|
||||
-------------------------------------------------
|
||||
testdata/std.md5_6:1:1-12 builtin function <md5>
|
||||
testdata/std.md5_6:1:1-12 $
|
||||
|
||||
std.md5(42)
|
||||
|
||||
|
2
testdata/std.modulo2.golden
vendored
2
testdata/std.modulo2.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected number
|
||||
-------------------------------------------------
|
||||
testdata/std.modulo2:1:1-22 builtin function <modulo>
|
||||
testdata/std.modulo2:1:1-22 $
|
||||
|
||||
std.modulo("xxx", 42)
|
||||
|
||||
|
2
testdata/std.modulo3.golden
vendored
2
testdata/std.modulo3.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected number
|
||||
-------------------------------------------------
|
||||
testdata/std.modulo3:1:1-22 builtin function <modulo>
|
||||
testdata/std.modulo3:1:1-22 $
|
||||
|
||||
std.modulo("xxx", 42)
|
||||
|
||||
|
2
testdata/std.primitiveEquals13.golden
vendored
2
testdata/std.primitiveEquals13.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: primitiveEquals operates on primitive types, got array
|
||||
-------------------------------------------------
|
||||
testdata/std.primitiveEquals13:1:1-28 builtin function <primitiveEquals>
|
||||
testdata/std.primitiveEquals13:1:1-28 $
|
||||
|
||||
std.primitiveEquals([], [])
|
||||
|
||||
|
2
testdata/std.primitiveEquals6.golden
vendored
2
testdata/std.primitiveEquals6.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: primitiveEquals operates on primitive types, got object
|
||||
-------------------------------------------------
|
||||
testdata/std.primitiveEquals6:1:1-28 builtin function <primitiveEquals>
|
||||
testdata/std.primitiveEquals6:1:1-28 $
|
||||
|
||||
std.primitiveEquals({}, {})
|
||||
|
||||
|
2
testdata/std.primitiveEquals7.golden
vendored
2
testdata/std.primitiveEquals7.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Cannot test equality of functions
|
||||
-------------------------------------------------
|
||||
testdata/std.primitiveEquals7:1:1-50 builtin function <primitiveEquals>
|
||||
testdata/std.primitiveEquals7:1:1-50 $
|
||||
|
||||
std.primitiveEquals(function() 42, function() 42)
|
||||
|
||||
|
2
testdata/std.sort3.golden
vendored
2
testdata/std.sort3.golden
vendored
@ -5,7 +5,7 @@ RUNTIME ERROR: foo
|
||||
std.sort([1,2, error "foo"])
|
||||
|
||||
-------------------------------------------------
|
||||
testdata/std.sort3:1:1-29 builtin function <sort>
|
||||
testdata/std.sort3:1:1-29 $
|
||||
|
||||
std.sort([1,2, error "foo"])
|
||||
|
||||
|
2
testdata/std.sort4.golden
vendored
2
testdata/std.sort4.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: Unexpected type number, expected array
|
||||
-------------------------------------------------
|
||||
testdata/std.sort4:1:1-29 builtin function <sort>
|
||||
testdata/std.sort4:1:1-29 $
|
||||
|
||||
std.sort([1, [error "foo"]])
|
||||
|
||||
|
2
testdata/strReplace3.golden
vendored
2
testdata/strReplace3.golden
vendored
@ -1,6 +1,6 @@
|
||||
RUNTIME ERROR: 'from' string must not be zero length.
|
||||
-------------------------------------------------
|
||||
testdata/strReplace3:1:1-35 builtin function <strReplace>
|
||||
testdata/strReplace3:1:1-35 $
|
||||
|
||||
std.strReplace("test", "", "blah")
|
||||
|
||||
|
2
testdata/string_plus_function.golden
vendored
2
testdata/string_plus_function.golden
vendored
@ -1,4 +1,4 @@
|
||||
RUNTIME ERROR: couldn't manifest function in JSON output.
|
||||
RUNTIME ERROR: couldn't manifest function as JSON
|
||||
-------------------------------------------------
|
||||
testdata/string_plus_function:1:1-24 $
|
||||
|
||||
|
4
tests.sh
4
tests.sh
@ -3,6 +3,7 @@
|
||||
set -e
|
||||
|
||||
PYTHON_COMMAND=${PYTHON_COMMAND:=python}
|
||||
JSONNET_CPP_DIR=${JSONNET_CPP_DIR:=$PWD/cpp-jsonnet}
|
||||
|
||||
set -x
|
||||
|
||||
@ -19,6 +20,7 @@ else
|
||||
fi
|
||||
|
||||
export IMPLEMENTATION=golang
|
||||
export OVERRIDE_DIR="$PWD/testdata/cpp-tests-override/"
|
||||
|
||||
go build ./cmd/jsonnet
|
||||
go build ./cmd/jsonnetfmt
|
||||
@ -28,5 +30,5 @@ export DISABLE_ERROR_TESTS=true
|
||||
export JSONNETFMT_BIN="$PWD/jsonnetfmt"
|
||||
export JSONNET_BIN="$PWD/jsonnet"
|
||||
|
||||
cd cpp-jsonnet
|
||||
cd "$JSONNET_CPP_DIR"
|
||||
exec ./tests.sh
|
||||
|
42
thunks.go
42
thunks.go
@ -32,7 +32,7 @@ type readyValue struct {
|
||||
content value
|
||||
}
|
||||
|
||||
func (rv *readyValue) evaluate(i *interpreter, trace traceElement, sb selfBinding, origBinding bindingFrame, fieldName string) (value, error) {
|
||||
func (rv *readyValue) evaluate(i *interpreter, sb selfBinding, origBinding bindingFrame, fieldName string) (value, error) {
|
||||
return rv.content, nil
|
||||
}
|
||||
|
||||
@ -58,14 +58,14 @@ func readyThunk(content value) *cachedThunk {
|
||||
return &cachedThunk{content: content}
|
||||
}
|
||||
|
||||
func (t *cachedThunk) getValue(i *interpreter, trace traceElement) (value, error) {
|
||||
func (t *cachedThunk) getValue(i *interpreter) (value, error) {
|
||||
if t.content != nil {
|
||||
return t.content, nil
|
||||
}
|
||||
if t.err != nil {
|
||||
return nil, t.err
|
||||
}
|
||||
v, err := i.EvalInCleanEnv(trace, t.env, t.body, false)
|
||||
v, err := i.EvalInCleanEnv(t.env, t.body, false)
|
||||
if err != nil {
|
||||
// TODO(sbarzowski) perhaps cache errors as well
|
||||
// may be necessary if we allow handling them in any way
|
||||
@ -87,9 +87,9 @@ type codeUnboundField struct {
|
||||
body ast.Node
|
||||
}
|
||||
|
||||
func (f *codeUnboundField) evaluate(i *interpreter, trace traceElement, sb selfBinding, origBindings bindingFrame, fieldName string) (value, error) {
|
||||
func (f *codeUnboundField) evaluate(i *interpreter, sb selfBinding, origBindings bindingFrame, fieldName string) (value, error) {
|
||||
env := makeEnvironment(origBindings, sb)
|
||||
return i.EvalInCleanEnv(trace, &env, f.body, false)
|
||||
return i.EvalInCleanEnv(&env, f.body, false)
|
||||
}
|
||||
|
||||
// Provide additional bindings for a field. It shadows bindings from the object.
|
||||
@ -99,7 +99,7 @@ type bindingsUnboundField struct {
|
||||
bindings bindingFrame
|
||||
}
|
||||
|
||||
func (f *bindingsUnboundField) evaluate(i *interpreter, trace traceElement, sb selfBinding, origBindings bindingFrame, fieldName string) (value, error) {
|
||||
func (f *bindingsUnboundField) evaluate(i *interpreter, sb selfBinding, origBindings bindingFrame, fieldName string) (value, error) {
|
||||
upValues := make(bindingFrame)
|
||||
for variable, pvalue := range origBindings {
|
||||
upValues[variable] = pvalue
|
||||
@ -107,7 +107,7 @@ func (f *bindingsUnboundField) evaluate(i *interpreter, trace traceElement, sb s
|
||||
for variable, pvalue := range f.bindings {
|
||||
upValues[variable] = pvalue
|
||||
}
|
||||
return f.inner.evaluate(i, trace, sb, upValues, fieldName)
|
||||
return f.inner.evaluate(i, sb, upValues, fieldName)
|
||||
}
|
||||
|
||||
// plusSuperUnboundField represents a `field+: ...` that hasn't been bound to an object.
|
||||
@ -115,19 +115,19 @@ type plusSuperUnboundField struct {
|
||||
inner unboundField
|
||||
}
|
||||
|
||||
func (f *plusSuperUnboundField) evaluate(i *interpreter, trace traceElement, sb selfBinding, origBinding bindingFrame, fieldName string) (value, error) {
|
||||
right, err := f.inner.evaluate(i, trace, sb, origBinding, fieldName)
|
||||
func (f *plusSuperUnboundField) evaluate(i *interpreter, sb selfBinding, origBinding bindingFrame, fieldName string) (value, error) {
|
||||
right, err := f.inner.evaluate(i, sb, origBinding, fieldName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !objectHasField(sb.super(), fieldName, withHidden) {
|
||||
return right, nil
|
||||
}
|
||||
left, err := objectIndex(i, trace, sb.super(), fieldName)
|
||||
left, err := objectIndex(i, sb.super(), fieldName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return builtinPlus(i, trace, left, right)
|
||||
return builtinPlus(i, left, right)
|
||||
}
|
||||
|
||||
// evalCallables
|
||||
@ -141,9 +141,9 @@ type closure struct {
|
||||
params []namedParameter
|
||||
}
|
||||
|
||||
func forceThunks(i *interpreter, trace traceElement, args *bindingFrame) error {
|
||||
func forceThunks(i *interpreter, args *bindingFrame) error {
|
||||
for _, arg := range *args {
|
||||
_, err := arg.getValue(i, trace)
|
||||
_, err := arg.getValue(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -151,7 +151,7 @@ func forceThunks(i *interpreter, trace traceElement, args *bindingFrame) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (closure *closure) evalCall(arguments callArguments, i *interpreter, trace traceElement) (value, error) {
|
||||
func (closure *closure) evalCall(arguments callArguments, i *interpreter) (value, error) {
|
||||
argThunks := make(bindingFrame)
|
||||
parameters := closure.parameters()
|
||||
for i, arg := range arguments.positional {
|
||||
@ -175,7 +175,7 @@ func (closure *closure) evalCall(arguments callArguments, i *interpreter, trace
|
||||
}
|
||||
|
||||
if arguments.tailstrict {
|
||||
err := forceThunks(i, trace, &argThunks)
|
||||
err := forceThunks(i, &argThunks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -185,7 +185,7 @@ func (closure *closure) evalCall(arguments callArguments, i *interpreter, trace
|
||||
addBindings(closure.env.upValues, argThunks),
|
||||
closure.env.selfBinding,
|
||||
)
|
||||
return i.EvalInCleanEnv(trace, &calledEnvironment, closure.function.Body, arguments.tailstrict)
|
||||
return i.EvalInCleanEnv(&calledEnvironment, closure.function.Body, arguments.tailstrict)
|
||||
}
|
||||
|
||||
func (closure *closure) parameters() []namedParameter {
|
||||
@ -220,15 +220,15 @@ 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) {
|
||||
func (native *NativeFunction) evalCall(arguments callArguments, i *interpreter) (value, error) {
|
||||
flatArgs := flattenArgs(arguments, native.parameters(), []value{})
|
||||
nativeArgs := make([]interface{}, 0, len(flatArgs))
|
||||
for _, arg := range flatArgs {
|
||||
v, err := i.evaluatePV(arg, trace)
|
||||
v, err := i.evaluatePV(arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
json, err := i.manifestJSON(trace, v)
|
||||
json, err := i.manifestJSON(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -236,9 +236,9 @@ func (native *NativeFunction) evalCall(arguments callArguments, i *interpreter,
|
||||
}
|
||||
resultJSON, err := native.Func(nativeArgs)
|
||||
if err != nil {
|
||||
return nil, i.Error(err.Error(), trace)
|
||||
return nil, i.Error(err.Error())
|
||||
}
|
||||
return jsonToValue(i, trace, resultJSON)
|
||||
return jsonToValue(i, resultJSON)
|
||||
}
|
||||
|
||||
// Parameters returns a NativeFunction's parameters.
|
||||
|
66
value.go
66
value.go
@ -58,7 +58,7 @@ var arrayType = &valueType{"array"}
|
||||
// TODO(sbarzowski) perhaps call it just "Thunk"?
|
||||
type potentialValue interface {
|
||||
// fromWhere keeps the information from where the evaluation was requested.
|
||||
getValue(i *interpreter, fromWhere traceElement) (value, error)
|
||||
getValue(i *interpreter) (value, error)
|
||||
|
||||
aPotentialValue()
|
||||
}
|
||||
@ -78,7 +78,7 @@ type valueString interface {
|
||||
length() int
|
||||
getRunes() []rune
|
||||
getGoString() string
|
||||
index(i *interpreter, trace traceElement, index int) (value, error)
|
||||
index(i *interpreter, index int) (value, error)
|
||||
}
|
||||
|
||||
// valueFlatString represents a string value, internally using a []rune for quick
|
||||
@ -89,11 +89,11 @@ type valueFlatString struct {
|
||||
value []rune
|
||||
}
|
||||
|
||||
func (s *valueFlatString) index(i *interpreter, trace traceElement, index int) (value, error) {
|
||||
func (s *valueFlatString) index(i *interpreter, index int) (value, error) {
|
||||
if 0 <= index && index < s.length() {
|
||||
return makeValueString(string(s.value[index])), nil
|
||||
}
|
||||
return nil, i.Error(fmt.Sprintf("Index %d out of bounds, not within [0, %v)", index, s.length()), trace)
|
||||
return nil, i.Error(fmt.Sprintf("Index %d out of bounds, not within [0, %v)", index, s.length()))
|
||||
}
|
||||
|
||||
func (s *valueFlatString) getRunes() []rune {
|
||||
@ -142,12 +142,12 @@ func (s *valueStringTree) flattenToLeft() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *valueStringTree) index(i *interpreter, trace traceElement, index int) (value, error) {
|
||||
func (s *valueStringTree) index(i *interpreter, index int) (value, error) {
|
||||
if 0 <= index && index < s.len {
|
||||
s.flattenToLeft()
|
||||
return s.left.index(i, trace, index)
|
||||
return s.left.index(i, index)
|
||||
}
|
||||
return nil, i.Error(fmt.Sprintf("Index %d out of bounds, not within [0, %v)", index, s.length()), trace)
|
||||
return nil, i.Error(fmt.Sprintf("Index %d out of bounds, not within [0, %v)", index, s.length()))
|
||||
}
|
||||
|
||||
func (s *valueStringTree) getRunes() []rune {
|
||||
@ -290,11 +290,11 @@ type valueArray struct {
|
||||
elements []*cachedThunk
|
||||
}
|
||||
|
||||
func (arr *valueArray) index(i *interpreter, trace traceElement, index int) (value, error) {
|
||||
func (arr *valueArray) index(i *interpreter, index int) (value, error) {
|
||||
if 0 <= index && index < arr.length() {
|
||||
return i.evaluatePV(arr.elements[index], trace)
|
||||
return i.evaluatePV(arr.elements[index])
|
||||
}
|
||||
return nil, i.Error(fmt.Sprintf("Index %d out of bounds, not within [0, %v)", index, arr.length()), trace)
|
||||
return nil, i.Error(fmt.Sprintf("Index %d out of bounds, not within [0, %v)", index, arr.length()))
|
||||
}
|
||||
|
||||
func (arr *valueArray) length() int {
|
||||
@ -337,29 +337,29 @@ type valueFunction struct {
|
||||
|
||||
// TODO(sbarzowski) better name?
|
||||
type evalCallable interface {
|
||||
evalCall(args callArguments, i *interpreter, trace traceElement) (value, error)
|
||||
evalCall(args callArguments, i *interpreter) (value, error)
|
||||
parameters() []namedParameter
|
||||
}
|
||||
|
||||
func (f *valueFunction) call(i *interpreter, trace traceElement, args callArguments) (value, error) {
|
||||
err := checkArguments(i, trace, args, f.parameters())
|
||||
func (f *valueFunction) call(i *interpreter, args callArguments) (value, error) {
|
||||
err := checkArguments(i, args, f.parameters())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f.ec.evalCall(args, i, trace)
|
||||
return f.ec.evalCall(args, i)
|
||||
}
|
||||
|
||||
func (f *valueFunction) parameters() []namedParameter {
|
||||
return f.ec.parameters()
|
||||
}
|
||||
|
||||
func checkArguments(i *interpreter, trace traceElement, args callArguments, params []namedParameter) error {
|
||||
func checkArguments(i *interpreter, args callArguments, params []namedParameter) error {
|
||||
|
||||
numPassed := len(args.positional)
|
||||
maxExpected := len(params)
|
||||
|
||||
if numPassed > maxExpected {
|
||||
return i.Error(fmt.Sprintf("function expected %v positional argument(s), but got %v", maxExpected, numPassed), trace)
|
||||
return i.Error(fmt.Sprintf("function expected %v positional argument(s), but got %v", maxExpected, numPassed))
|
||||
}
|
||||
|
||||
// Parameter names the function will accept.
|
||||
@ -375,17 +375,17 @@ func checkArguments(i *interpreter, trace traceElement, args callArguments, para
|
||||
}
|
||||
for _, arg := range args.named {
|
||||
if _, present := received[arg.name]; present {
|
||||
return i.Error(fmt.Sprintf("Argument %v already provided", arg.name), trace)
|
||||
return i.Error(fmt.Sprintf("Argument %v already provided", arg.name))
|
||||
}
|
||||
if _, present := accepted[arg.name]; !present {
|
||||
return i.Error(fmt.Sprintf("function has no parameter %v", arg.name), trace)
|
||||
return i.Error(fmt.Sprintf("function has no parameter %v", arg.name))
|
||||
}
|
||||
received[arg.name] = true
|
||||
}
|
||||
|
||||
for _, param := range params {
|
||||
if _, present := received[param.name]; !present && param.defaultArg == nil {
|
||||
return i.Error(fmt.Sprintf("Missing argument: %v", param.name), trace)
|
||||
return i.Error(fmt.Sprintf("Missing argument: %v", param.name))
|
||||
}
|
||||
}
|
||||
|
||||
@ -492,8 +492,8 @@ func (*valueObject) getType() *valueType {
|
||||
return objectType
|
||||
}
|
||||
|
||||
func (obj *valueObject) index(i *interpreter, trace traceElement, field string) (value, error) {
|
||||
return objectIndex(i, trace, objectBinding(obj), field)
|
||||
func (obj *valueObject) index(i *interpreter, field string) (value, error) {
|
||||
return objectIndex(i, objectBinding(obj), field)
|
||||
}
|
||||
|
||||
func (obj *valueObject) assertionsChecked() bool {
|
||||
@ -545,14 +545,14 @@ type simpleObject struct {
|
||||
locals []objectLocal
|
||||
}
|
||||
|
||||
func checkAssertionsHelper(i *interpreter, trace traceElement, obj *valueObject, curr uncachedObject, superDepth int) error {
|
||||
func checkAssertionsHelper(i *interpreter, obj *valueObject, curr uncachedObject, superDepth int) error {
|
||||
switch curr := curr.(type) {
|
||||
case *extendedObject:
|
||||
err := checkAssertionsHelper(i, trace, obj, curr.right, superDepth)
|
||||
err := checkAssertionsHelper(i, obj, curr.right, superDepth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = checkAssertionsHelper(i, trace, obj, curr.left, superDepth+curr.right.inheritanceSize())
|
||||
err = checkAssertionsHelper(i, obj, curr.left, superDepth+curr.right.inheritanceSize())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -561,7 +561,7 @@ func checkAssertionsHelper(i *interpreter, trace traceElement, obj *valueObject,
|
||||
for _, assert := range curr.asserts {
|
||||
sb := selfBinding{self: obj, superDepth: superDepth}
|
||||
fieldUpValues := prepareFieldUpvalues(sb, curr.upValues, curr.locals)
|
||||
_, err := assert.evaluate(i, trace, sb, fieldUpValues, "")
|
||||
_, err := assert.evaluate(i, sb, fieldUpValues, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -574,13 +574,13 @@ func checkAssertionsHelper(i *interpreter, trace traceElement, obj *valueObject,
|
||||
}
|
||||
}
|
||||
|
||||
func checkAssertions(i *interpreter, trace traceElement, obj *valueObject) error {
|
||||
func checkAssertions(i *interpreter, obj *valueObject) error {
|
||||
if !obj.assertionsChecked() {
|
||||
// Assertions may refer to the object that will normally
|
||||
// trigger checking of assertions, resulting in an endless recursion.
|
||||
// To avoid that, while we check them, we treat them as already passed.
|
||||
obj.setAssertionsCheckResult(errNoErrorInObjectInvariants)
|
||||
obj.setAssertionsCheckResult(checkAssertionsHelper(i, trace, obj, obj.uncached, 0))
|
||||
obj.setAssertionsCheckResult(checkAssertionsHelper(i, obj, obj.uncached, 0))
|
||||
}
|
||||
return obj.getAssertionsCheckResult()
|
||||
}
|
||||
@ -610,7 +610,7 @@ type simpleObjectField struct {
|
||||
|
||||
// unboundField is a field that doesn't know yet in which object it is.
|
||||
type unboundField interface {
|
||||
evaluate(i *interpreter, trace traceElement, sb selfBinding, origBinding bindingFrame, fieldName string) (value, error)
|
||||
evaluate(i *interpreter, sb selfBinding, origBinding bindingFrame, fieldName string) (value, error)
|
||||
}
|
||||
|
||||
// extendedObject represents an object created through inheritance (left + right).
|
||||
@ -699,18 +699,18 @@ func prepareFieldUpvalues(sb selfBinding, upValues bindingFrame, locals []object
|
||||
return newUpValues
|
||||
}
|
||||
|
||||
func objectIndex(i *interpreter, trace traceElement, sb selfBinding, fieldName string) (value, error) {
|
||||
err := checkAssertions(i, trace, sb.self)
|
||||
func objectIndex(i *interpreter, sb selfBinding, fieldName string) (value, error) {
|
||||
err := checkAssertions(i, sb.self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if sb.superDepth >= sb.self.uncached.inheritanceSize() {
|
||||
return nil, i.Error("Attempt to use super when there is no super class.", trace)
|
||||
return nil, i.Error("Attempt to use super when there is no super class.")
|
||||
}
|
||||
|
||||
found, field, upValues, locals, foundAt := findField(sb.self.uncached, sb.superDepth, fieldName)
|
||||
if !found {
|
||||
return nil, i.Error(fmt.Sprintf("Field does not exist: %s", fieldName), trace)
|
||||
return nil, i.Error(fmt.Sprintf("Field does not exist: %s", fieldName))
|
||||
}
|
||||
|
||||
if val, ok := sb.self.cache[objectCacheKey{field: fieldName, depth: foundAt}]; ok {
|
||||
@ -720,7 +720,7 @@ func objectIndex(i *interpreter, trace traceElement, sb selfBinding, fieldName s
|
||||
fieldSelfBinding := selfBinding{self: sb.self, superDepth: foundAt}
|
||||
fieldUpValues := prepareFieldUpvalues(fieldSelfBinding, upValues, locals)
|
||||
|
||||
val, err := field.field.evaluate(i, trace, fieldSelfBinding, fieldUpValues, fieldName)
|
||||
val, err := field.field.evaluate(i, fieldSelfBinding, fieldUpValues, fieldName)
|
||||
|
||||
if err == nil {
|
||||
sb.self.cache[objectCacheKey{field: fieldName, depth: foundAt}] = val
|
||||
|
Loading…
Reference in New Issue
Block a user