mirror of
https://github.com/google/go-jsonnet.git
synced 2025-08-07 23:07:14 +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.
|
// 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)
|
data, _, err := cache.importData(importedFrom, importedPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, i.Error(err.Error(), trace)
|
return nil, i.Error(err.Error())
|
||||||
}
|
}
|
||||||
return makeValueString(data.String()), nil
|
return makeValueString(data.String()), nil
|
||||||
}
|
}
|
||||||
@ -158,10 +158,10 @@ func codeToPV(i *interpreter, filename string, code string) *cachedThunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ImportCode imports code from a path.
|
// 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)
|
node, foundAt, err := cache.importAST(importedFrom, importedPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, i.Error(err.Error(), trace)
|
return nil, i.Error(err.Error())
|
||||||
}
|
}
|
||||||
var pv potentialValue
|
var pv potentialValue
|
||||||
if cachedPV, isCached := cache.codeCache[foundAt]; !isCached {
|
if cachedPV, isCached := cache.codeCache[foundAt]; !isCached {
|
||||||
@ -176,7 +176,7 @@ func (cache *importCache) importCode(importedFrom, importedPath string, i *inter
|
|||||||
} else {
|
} else {
|
||||||
pv = cachedPV
|
pv = cachedPV
|
||||||
}
|
}
|
||||||
return i.evaluatePV(pv, trace)
|
return i.evaluatePV(pv)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Concrete importers
|
// 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)
|
// 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
|
var body ast.Node
|
||||||
if len(forSpec.Conditions) > 0 {
|
if len(forSpec.Conditions) > 0 {
|
||||||
cond := forSpec.Conditions[0].Expr
|
cond := forSpec.Conditions[0].Expr
|
||||||
@ -179,11 +179,11 @@ func desugarForSpec(inside ast.Node, forSpec *ast.ForSpec, objLevel int) (ast.No
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
current := buildStdCall("flatMap", function, forSpec.Expr)
|
current := buildStdCall("flatMap", loc, function, forSpec.Expr)
|
||||||
if forSpec.Outer == nil {
|
if forSpec.Outer == nil {
|
||||||
return current, nil
|
return current, nil
|
||||||
}
|
}
|
||||||
return desugarForSpec(current, forSpec.Outer, objLevel)
|
return desugarForSpec(current, loc, forSpec.Outer, objLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrapInArray(inside ast.Node) ast.Node {
|
func wrapInArray(inside ast.Node) ast.Node {
|
||||||
@ -195,7 +195,7 @@ func desugarArrayComp(comp *ast.ArrayComp, objLevel int) (ast.Node, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
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")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
desugaredComp := buildStdCall("$objectFlatMerge", desugaredArrayComp)
|
desugaredComp := buildStdCall("$objectFlatMerge", *comp.Loc(), desugaredArrayComp)
|
||||||
return desugaredComp, nil
|
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"}
|
std := &ast.Var{Id: "std"}
|
||||||
builtin := buildSimpleIndex(std, builtinName)
|
builtin := buildSimpleIndex(std, builtinName)
|
||||||
positional := make([]ast.CommaSeparatedExpr, len(args))
|
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]
|
positional[i].Expr = args[i]
|
||||||
}
|
}
|
||||||
return &ast.Apply{
|
return &ast.Apply{
|
||||||
|
NodeBase: ast.NodeBase{
|
||||||
|
LocRange: loc,
|
||||||
|
},
|
||||||
Target: builtin,
|
Target: builtin,
|
||||||
Arguments: ast.Arguments{Positional: positional},
|
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 funcname, replaced := desugaredBop[node.Op]; replaced {
|
||||||
if node.Op == ast.BopIn {
|
if node.Op == ast.BopIn {
|
||||||
// reversed order of arguments
|
// reversed order of arguments
|
||||||
*astPtr = buildStdCall(funcname, node.Right, node.Left)
|
*astPtr = buildStdCall(funcname, *node.Loc(), node.Right, node.Left)
|
||||||
} else {
|
} else {
|
||||||
*astPtr = buildStdCall(funcname, node.Left, node.Right)
|
*astPtr = buildStdCall(funcname, *node.Loc(), node.Left, node.Right)
|
||||||
}
|
}
|
||||||
return desugar(astPtr, objLevel)
|
return desugar(astPtr, objLevel)
|
||||||
}
|
}
|
||||||
@ -455,7 +458,7 @@ func desugar(astPtr *ast.Node, objLevel int) (err error) {
|
|||||||
if node.Step == nil {
|
if node.Step == nil {
|
||||||
node.Step = &ast.LiteralNull{}
|
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)
|
err = desugar(astPtr, objLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
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
|
var result []traceFrame
|
||||||
for _, f := range i.stack.stack {
|
for _, f := range i.stack.stack {
|
||||||
if f.isCall {
|
if f.isCall {
|
||||||
result = append(result, traceElementToTraceFrame(f.trace))
|
result = append(result, traceElementToTraceFrame(f.trace))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if additional.loc != nil {
|
if i.stack.currentTrace.loc != nil {
|
||||||
result = append(result, traceElementToTraceFrame(additional))
|
result = append(result, traceElementToTraceFrame(i.stack.currentTrace))
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -95,9 +95,10 @@ func dumpCallFrame(c *callFrame) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type callStack struct {
|
type callStack struct {
|
||||||
calls int
|
calls int
|
||||||
limit int
|
limit int
|
||||||
stack []*callFrame
|
stack []*callFrame
|
||||||
|
currentTrace traceElement
|
||||||
}
|
}
|
||||||
|
|
||||||
func dumpCallStack(c *callStack) string {
|
func dumpCallStack(c *callStack) string {
|
||||||
@ -123,6 +124,7 @@ func (s *callStack) popIfExists(whichFrame int) {
|
|||||||
if s.top().isCall {
|
if s.top().isCall {
|
||||||
s.calls--
|
s.calls--
|
||||||
}
|
}
|
||||||
|
s.setCurrentTrace(s.stack[len(s.stack)-1].trace)
|
||||||
s.stack = s.stack[:len(s.stack)-1]
|
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
|
type tailCallStatus int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -149,20 +162,26 @@ const (
|
|||||||
tailCall
|
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{
|
s.stack = append(s.stack, &callFrame{
|
||||||
isCall: true,
|
isCall: true,
|
||||||
trace: trace,
|
trace: s.currentTrace,
|
||||||
env: env,
|
env: env,
|
||||||
trimmable: trimmable,
|
trimmable: trimmable,
|
||||||
})
|
})
|
||||||
|
s.clearCurrentTrace()
|
||||||
s.calls++
|
s.calls++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *callStack) newLocal(vars bindingFrame) {
|
func (s *callStack) newLocal(vars bindingFrame) {
|
||||||
s.stack = append(s.stack, &callFrame{
|
s.stack = append(s.stack, &callFrame{
|
||||||
env: makeEnvironment(vars, selfBinding{}),
|
env: makeEnvironment(vars, selfBinding{}),
|
||||||
|
trace: s.currentTrace,
|
||||||
})
|
})
|
||||||
|
s.clearCurrentTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSelfBinding resolves the self construct
|
// getSelfBinding resolves the self construct
|
||||||
@ -256,12 +275,12 @@ func addBindings(a, b bindingFrame) bindingFrame {
|
|||||||
return result
|
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
|
s := &i.stack
|
||||||
if s.calls >= s.limit {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,6 +289,10 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
|||||||
loc: a.Loc(),
|
loc: a.Loc(),
|
||||||
context: a.Context(),
|
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) {
|
switch node := a.(type) {
|
||||||
case *ast.Array:
|
case *ast.Array:
|
||||||
@ -289,7 +312,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
x, err := i.getBoolean(xv, trace)
|
x, err := i.getBoolean(xv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -300,14 +323,14 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return i.getBoolean(yv, trace)
|
return i.getBoolean(yv)
|
||||||
} else if node.Op == ast.BopOr {
|
} else if node.Op == ast.BopOr {
|
||||||
// Special case for shortcut semantics.
|
// Special case for shortcut semantics.
|
||||||
xv, err := i.evaluate(node.Left, nonTailCall)
|
xv, err := i.evaluate(node.Left, nonTailCall)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
x, err := i.getBoolean(xv, trace)
|
x, err := i.getBoolean(xv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -318,7 +341,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return i.getBoolean(yv, trace)
|
return i.getBoolean(yv)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
left, err := i.evaluate(node.Left, nonTailCall)
|
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.
|
// TODO(dcunnin): The double dereference here is probably not necessary.
|
||||||
builtin := bopBuiltins[node.Op]
|
builtin := bopBuiltins[node.Op]
|
||||||
return builtin.function(i, trace, left, right)
|
return builtin.function(i, left, right)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ast.Unary:
|
case *ast.Unary:
|
||||||
@ -342,7 +365,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
|||||||
|
|
||||||
builtin := uopBuiltins[node.Op]
|
builtin := uopBuiltins[node.Op]
|
||||||
|
|
||||||
result, err := builtin.function(i, trace, value)
|
result, err := builtin.function(i, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -353,7 +376,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
condBool, err := i.getBoolean(cond, trace)
|
condBool, err := i.getBoolean(cond)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -378,11 +401,11 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
|||||||
// Omitted field.
|
// Omitted field.
|
||||||
continue
|
continue
|
||||||
default:
|
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 {
|
if _, ok := fields[fieldName]; ok {
|
||||||
return nil, i.Error(duplicateFieldNameErrMsg(fieldName), trace)
|
return nil, i.Error(duplicateFieldNameErrMsg(fieldName))
|
||||||
}
|
}
|
||||||
var f unboundField = &codeUnboundField{field.Body}
|
var f unboundField = &codeUnboundField{field.Body}
|
||||||
if field.PlusSuper {
|
if field.PlusSuper {
|
||||||
@ -408,16 +431,16 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if msgVal.getType() != stringType {
|
if msgVal.getType() != stringType {
|
||||||
msgVal, err = builtinToString(i, trace, msgVal)
|
msgVal, err = builtinToString(i, msgVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg, err := i.getString(msgVal, trace)
|
msg, err := i.getString(msgVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, i.Error(msg.getGoString(), trace)
|
return nil, i.Error(msg.getGoString())
|
||||||
|
|
||||||
case *ast.Index:
|
case *ast.Index:
|
||||||
targetValue, err := i.evaluate(node.Target, nonTailCall)
|
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) {
|
switch target := targetValue.(type) {
|
||||||
case *valueObject:
|
case *valueObject:
|
||||||
indexString, err := i.getString(index, trace)
|
indexString, err := i.getString(index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return target.index(i, trace, indexString.getGoString())
|
return target.index(i, indexString.getGoString())
|
||||||
case *valueArray:
|
case *valueArray:
|
||||||
indexInt, err := i.getNumber(index, trace)
|
indexInt, err := i.getNumber(index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// TODO(https://github.com/google/jsonnet/issues/377): non-integer indexes should be an error
|
// 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:
|
case valueString:
|
||||||
indexInt, err := i.getNumber(index, trace)
|
indexInt, err := i.getNumber(index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// TODO(https://github.com/google/jsonnet/issues/377): non-integer indexes should be an error
|
// 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:
|
case *ast.Import:
|
||||||
codePath := node.Loc().FileName
|
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:
|
case *ast.ImportStr:
|
||||||
codePath := node.Loc().FileName
|
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:
|
case *ast.LiteralBoolean:
|
||||||
return makeValueBoolean(node.Value), nil
|
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.
|
// too large to fit in a double.
|
||||||
num, err := strconv.ParseFloat(node.OriginalString, 64)
|
num, err := strconv.ParseFloat(node.OriginalString, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, i.Error("overflow", trace)
|
return nil, i.Error("overflow")
|
||||||
}
|
}
|
||||||
return makeValueNumber(num), nil
|
return makeValueNumber(num), nil
|
||||||
|
|
||||||
@ -506,25 +529,25 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
|||||||
|
|
||||||
case *ast.Var:
|
case *ast.Var:
|
||||||
foo := i.stack.lookUpVarOrPanic(node.Id)
|
foo := i.stack.lookUpVarOrPanic(node.Id)
|
||||||
return foo.getValue(i, trace)
|
return foo.getValue(i)
|
||||||
|
|
||||||
case *ast.SuperIndex:
|
case *ast.SuperIndex:
|
||||||
index, err := i.evaluate(node.Index, nonTailCall)
|
index, err := i.evaluate(node.Index, nonTailCall)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
indexStr, err := i.getString(index, trace)
|
indexStr, err := i.getString(index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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:
|
case *ast.InSuper:
|
||||||
index, err := i.evaluate(node.Index, nonTailCall)
|
index, err := i.evaluate(node.Index, nonTailCall)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
indexStr, err := i.getString(index, trace)
|
indexStr, err := i.getString(index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -542,7 +565,7 @@ func (i *interpreter) evaluate(a ast.Node, tc tailCallStatus) (value, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
function, err := i.getFunction(target, trace)
|
function, err := i.getFunction(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
for i, arg := range node.Arguments.Named {
|
||||||
arguments.named[i] = namedCallArgument{name: arg.Name, pv: &cachedThunk{env: &argEnv, body: arg.Arg}}
|
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:
|
case *astMakeArrayElement:
|
||||||
arguments := callArguments{
|
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:
|
default:
|
||||||
panic(fmt.Sprintf("Executing this AST type not implemented: %v", reflect.TypeOf(a)))
|
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
|
// 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) {
|
switch v := v.(type) {
|
||||||
|
|
||||||
case *valueBoolean:
|
case *valueBoolean:
|
||||||
return v.value, nil
|
return v.value, nil
|
||||||
|
|
||||||
case *valueFunction:
|
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:
|
case *valueNumber:
|
||||||
return v.value, nil
|
return v.value, nil
|
||||||
@ -645,11 +674,11 @@ func (i *interpreter) manifestJSON(trace traceElement, v value) (interface{}, er
|
|||||||
case *valueArray:
|
case *valueArray:
|
||||||
result := make([]interface{}, 0, len(v.elements))
|
result := make([]interface{}, 0, len(v.elements))
|
||||||
for _, th := range v.elements {
|
for _, th := range v.elements {
|
||||||
elVal, err := i.evaluatePV(th, trace)
|
elVal, err := i.evaluatePV(th)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
elem, err := i.manifestJSON(trace, elVal)
|
elem, err := i.manifestJSON(elVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -661,7 +690,7 @@ func (i *interpreter) manifestJSON(trace traceElement, v value) (interface{}, er
|
|||||||
fieldNames := objectFields(v, withoutHidden)
|
fieldNames := objectFields(v, withoutHidden)
|
||||||
sort.Strings(fieldNames)
|
sort.Strings(fieldNames)
|
||||||
|
|
||||||
err := checkAssertions(i, trace, v)
|
err := checkAssertions(i, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -669,12 +698,12 @@ func (i *interpreter) manifestJSON(trace traceElement, v value) (interface{}, er
|
|||||||
result := make(map[string]interface{})
|
result := make(map[string]interface{})
|
||||||
|
|
||||||
for _, fieldName := range fieldNames {
|
for _, fieldName := range fieldNames {
|
||||||
fieldVal, err := v.index(i, trace, fieldName)
|
fieldVal, err := v.index(i, fieldName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
field, err := i.manifestJSON(trace, fieldVal)
|
field, err := i.manifestJSON(fieldVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -686,7 +715,7 @@ func (i *interpreter) manifestJSON(trace traceElement, v value) (interface{}, er
|
|||||||
default:
|
default:
|
||||||
return nil, makeRuntimeError(
|
return nil, makeRuntimeError(
|
||||||
fmt.Sprintf("manifesting this value not implemented yet: %s", reflect.TypeOf(v)),
|
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(
|
func (i *interpreter) manifestAndSerializeJSON(
|
||||||
buf *bytes.Buffer, trace traceElement, v value, multiline bool, indent string) error {
|
buf *bytes.Buffer, v value, multiline bool, indent string) error {
|
||||||
manifested, err := i.manifestJSON(trace, v)
|
manifested, err := i.manifestJSON(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -800,19 +829,19 @@ func (i *interpreter) manifestAndSerializeJSON(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// manifestString expects the value to be a string and returns it.
|
// 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) {
|
switch v := v.(type) {
|
||||||
case valueString:
|
case valueString:
|
||||||
buf.WriteString(v.getGoString())
|
buf.WriteString(v.getGoString())
|
||||||
return nil
|
return nil
|
||||||
default:
|
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)
|
r = make(map[string]string)
|
||||||
json, err := i.manifestJSON(trace, v)
|
json, err := i.manifestJSON(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
@ -826,7 +855,7 @@ func (i *interpreter) manifestAndSerializeMulti(trace traceElement, v value, str
|
|||||||
default:
|
default:
|
||||||
msg := fmt.Sprintf("multi mode: top-level object's key %s has a value of type %T, "+
|
msg := fmt.Sprintf("multi mode: top-level object's key %s has a value of type %T, "+
|
||||||
"should be a string", filename, val)
|
"should be a string", filename, val)
|
||||||
return r, makeRuntimeError(msg, i.getCurrentStackTrace(trace))
|
return r, makeRuntimeError(msg, i.getCurrentStackTrace())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var buf bytes.Buffer
|
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, "+
|
msg := fmt.Sprintf("multi mode: top-level object was a %s, "+
|
||||||
"should be an object whose keys are filenames and values hold "+
|
"should be an object whose keys are filenames and values hold "+
|
||||||
"the JSON for that file.", v.getType().name)
|
"the JSON for that file.", v.getType().name)
|
||||||
return r, makeRuntimeError(msg, i.getCurrentStackTrace(trace))
|
return r, makeRuntimeError(msg, i.getCurrentStackTrace())
|
||||||
}
|
}
|
||||||
return
|
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)
|
r = make([]string, 0)
|
||||||
json, err := i.manifestJSON(trace, v)
|
json, err := i.manifestJSON(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, err
|
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, "+
|
msg := fmt.Sprintf("stream mode: top-level object was a %s, "+
|
||||||
"should be an array whose elements hold "+
|
"should be an array whose elements hold "+
|
||||||
"the JSON for each document in the stream.", v.getType().name)
|
"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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func jsonToValue(i *interpreter, trace traceElement, v interface{}) (value, error) {
|
func jsonToValue(i *interpreter, v interface{}) (value, error) {
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
return &nullValue, nil
|
return &nullValue, nil
|
||||||
@ -875,7 +904,7 @@ func jsonToValue(i *interpreter, trace traceElement, v interface{}) (value, erro
|
|||||||
case []interface{}:
|
case []interface{}:
|
||||||
elems := make([]*cachedThunk, len(v))
|
elems := make([]*cachedThunk, len(v))
|
||||||
for counter, elem := range v {
|
for counter, elem := range v {
|
||||||
val, err := jsonToValue(i, trace, elem)
|
val, err := jsonToValue(i, elem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -886,12 +915,12 @@ func jsonToValue(i *interpreter, trace traceElement, v interface{}) (value, erro
|
|||||||
case bool:
|
case bool:
|
||||||
return makeValueBoolean(v), nil
|
return makeValueBoolean(v), nil
|
||||||
case float64:
|
case float64:
|
||||||
return makeDoubleCheck(i, trace, v)
|
return makeDoubleCheck(i, v)
|
||||||
|
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
fieldMap := map[string]value{}
|
fieldMap := map[string]value{}
|
||||||
for name, f := range v {
|
for name, f := range v {
|
||||||
val, err := jsonToValue(i, trace, f)
|
val, err := jsonToValue(i, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -903,12 +932,12 @@ func jsonToValue(i *interpreter, trace traceElement, v interface{}) (value, erro
|
|||||||
return makeValueString(v), nil
|
return makeValueString(v), nil
|
||||||
|
|
||||||
default:
|
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) {
|
func (i *interpreter) EvalInCleanEnv(env *environment, ast ast.Node, trimmable bool) (value, error) {
|
||||||
err := i.newCall(fromWhere, *env, trimmable)
|
err := i.newCall(*env, trimmable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -921,56 +950,54 @@ func (i *interpreter) EvalInCleanEnv(fromWhere traceElement, env *environment, a
|
|||||||
return val, err
|
return val, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interpreter) evaluatePV(ph potentialValue, trace traceElement) (value, error) {
|
func (i *interpreter) evaluatePV(ph potentialValue) (value, error) {
|
||||||
return ph.getValue(i, trace)
|
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 {
|
if tc == tailCall {
|
||||||
i.stack.tailCallTrimStack()
|
i.stack.tailCallTrimStack()
|
||||||
}
|
}
|
||||||
return function.call(i, trace, args)
|
return function.call(i, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interpreter) Error(s string, trace traceElement) error {
|
func (i *interpreter) Error(s string) error {
|
||||||
err := makeRuntimeError(s, i.getCurrentStackTrace(trace))
|
err := makeRuntimeError(s, i.getCurrentStackTrace())
|
||||||
return err
|
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(
|
return i.Error(
|
||||||
fmt.Sprintf("Unexpected type %v, expected %v", bad.getType().name, good.getType().name),
|
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(
|
return i.Error(
|
||||||
fmt.Sprintf("Unexpected type %v", bad.getType().name),
|
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) {
|
switch v := val.(type) {
|
||||||
case *valueNumber:
|
case *valueNumber:
|
||||||
return v, nil
|
return v, nil
|
||||||
default:
|
default:
|
||||||
return nil, i.typeErrorSpecific(val, &valueNumber{}, trace)
|
return nil, i.typeErrorSpecific(val, &valueNumber{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:unused
|
//nolint:unused
|
||||||
func (i *interpreter) evaluateNumber(pv potentialValue, trace traceElement) (*valueNumber, error) {
|
func (i *interpreter) evaluateNumber(pv potentialValue) (*valueNumber, error) {
|
||||||
v, err := i.evaluatePV(pv, trace)
|
v, err := i.evaluatePV(pv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return i.getNumber(v, trace)
|
return i.getNumber(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interpreter) getInt(val value, trace traceElement) (int, error) {
|
func (i *interpreter) getInt(val value) (int, error) {
|
||||||
num, err := i.getNumber(val, trace)
|
num, err := i.getNumber(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
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.
|
// on any machine. And it's used only for indexing anyway.
|
||||||
intNum := int(int32(num.value))
|
intNum := int(int32(num.value))
|
||||||
if float64(intNum) != 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
|
return intNum, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interpreter) evaluateInt(pv potentialValue, trace traceElement) (int, error) {
|
func (i *interpreter) evaluateInt(pv potentialValue) (int, error) {
|
||||||
v, err := i.evaluatePV(pv, trace)
|
v, err := i.evaluatePV(pv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return i.getInt(v, trace)
|
return i.getInt(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:unused
|
//nolint:unused
|
||||||
func (i *interpreter) getInt64(val value, trace traceElement) (int64, error) {
|
func (i *interpreter) getInt64(val value) (int64, error) {
|
||||||
num, err := i.getNumber(val, trace)
|
num, err := i.getNumber(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
intNum := int64(num.value)
|
intNum := int64(num.value)
|
||||||
if float64(intNum) != 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
|
return intNum, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:unused
|
//nolint:unused
|
||||||
func (i *interpreter) evaluateInt64(pv potentialValue, trace traceElement) (int64, error) {
|
func (i *interpreter) evaluateInt64(pv potentialValue) (int64, error) {
|
||||||
v, err := i.evaluatePV(pv, trace)
|
v, err := i.evaluatePV(pv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
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) {
|
switch v := val.(type) {
|
||||||
case valueString:
|
case valueString:
|
||||||
return v, nil
|
return v, nil
|
||||||
default:
|
default:
|
||||||
return nil, i.typeErrorSpecific(val, emptyString(), trace)
|
return nil, i.typeErrorSpecific(val, emptyString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:unused
|
//nolint:unused
|
||||||
func (i *interpreter) evaluateString(pv potentialValue, trace traceElement) (valueString, error) {
|
func (i *interpreter) evaluateString(pv potentialValue) (valueString, error) {
|
||||||
v, err := i.evaluatePV(pv, trace)
|
v, err := i.evaluatePV(pv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
switch v := val.(type) {
|
||||||
case *valueBoolean:
|
case *valueBoolean:
|
||||||
return v, nil
|
return v, nil
|
||||||
default:
|
default:
|
||||||
return nil, i.typeErrorSpecific(val, &valueBoolean{}, trace)
|
return nil, i.typeErrorSpecific(val, &valueBoolean{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:unused
|
//nolint:unused
|
||||||
func (i *interpreter) evaluateBoolean(pv potentialValue, trace traceElement) (*valueBoolean, error) {
|
func (i *interpreter) evaluateBoolean(pv potentialValue) (*valueBoolean, error) {
|
||||||
v, err := i.evaluatePV(pv, trace)
|
v, err := i.evaluatePV(pv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
switch v := val.(type) {
|
||||||
case *valueArray:
|
case *valueArray:
|
||||||
return v, nil
|
return v, nil
|
||||||
default:
|
default:
|
||||||
return nil, i.typeErrorSpecific(val, &valueArray{}, trace)
|
return nil, i.typeErrorSpecific(val, &valueArray{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:unused
|
//nolint:unused
|
||||||
func (i *interpreter) evaluateArray(pv potentialValue, trace traceElement) (*valueArray, error) {
|
func (i *interpreter) evaluateArray(pv potentialValue) (*valueArray, error) {
|
||||||
v, err := i.evaluatePV(pv, trace)
|
v, err := i.evaluatePV(pv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
switch v := val.(type) {
|
||||||
case *valueFunction:
|
case *valueFunction:
|
||||||
return v, nil
|
return v, nil
|
||||||
default:
|
default:
|
||||||
return nil, i.typeErrorSpecific(val, &valueFunction{}, trace)
|
return nil, i.typeErrorSpecific(val, &valueFunction{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:unused
|
//nolint:unused
|
||||||
func (i *interpreter) evaluateFunction(pv potentialValue, trace traceElement) (*valueFunction, error) {
|
func (i *interpreter) evaluateFunction(pv potentialValue) (*valueFunction, error) {
|
||||||
v, err := i.evaluatePV(pv, trace)
|
v, err := i.evaluatePV(pv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
switch v := val.(type) {
|
||||||
case *valueObject:
|
case *valueObject:
|
||||||
return v, nil
|
return v, nil
|
||||||
default:
|
default:
|
||||||
return nil, i.typeErrorSpecific(val, &valueObject{}, trace)
|
return nil, i.typeErrorSpecific(val, &valueObject{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interpreter) evaluateObject(pv potentialValue, trace traceElement) (*valueObject, error) {
|
func (i *interpreter) evaluateObject(pv potentialValue) (*valueObject, error) {
|
||||||
v, err := i.evaluatePV(pv, trace)
|
v, err := i.evaluatePV(pv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return i.getObject(v, trace)
|
return i.getObject(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildStdObject(i *interpreter) (*valueObject, error) {
|
func buildStdObject(i *interpreter) (*valueObject, error) {
|
||||||
@ -1128,7 +1155,9 @@ func evaluateStd(i *interpreter) (value, error) {
|
|||||||
evalLoc := ast.MakeLocationRangeMessage("During evaluation of std")
|
evalLoc := ast.MakeLocationRangeMessage("During evaluation of std")
|
||||||
evalTrace := traceElement{loc: &evalLoc}
|
evalTrace := traceElement{loc: &evalLoc}
|
||||||
node := astgen.StdAst
|
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 {
|
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,
|
loc: &evalLoc,
|
||||||
}
|
}
|
||||||
env := makeInitialEnv(node.Loc().FileName, i.baseStd)
|
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 {
|
if err != nil {
|
||||||
return nil, traceElement{}, err
|
return nil, traceElement{}, err
|
||||||
}
|
}
|
||||||
@ -1199,11 +1230,13 @@ func evaluateAux(i *interpreter, node ast.Node, tla vmExtMap) (value, traceEleme
|
|||||||
for argName, pv := range toplevelArgMap {
|
for argName, pv := range toplevelArgMap {
|
||||||
args.named = append(args.named, namedCallArgument{name: ast.Identifier(argName), pv: pv})
|
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{
|
funcTrace := traceElement{
|
||||||
loc: &funcLoc,
|
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 {
|
if err != nil {
|
||||||
return nil, traceElement{}, err
|
return nil, traceElement{}, err
|
||||||
}
|
}
|
||||||
@ -1230,11 +1263,13 @@ func evaluate(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[string]
|
|||||||
}
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
i.stack.setCurrentTrace(manifestationTrace)
|
||||||
if stringOutputMode {
|
if stringOutputMode {
|
||||||
err = i.manifestString(&buf, manifestationTrace, result)
|
err = i.manifestString(&buf, result)
|
||||||
} else {
|
} else {
|
||||||
err = i.manifestAndSerializeJSON(&buf, manifestationTrace, result, true, "")
|
err = i.manifestAndSerializeJSON(&buf, result, true, "")
|
||||||
}
|
}
|
||||||
|
i.stack.clearCurrentTrace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -1256,7 +1291,10 @@ func evaluateMulti(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[st
|
|||||||
return nil, err
|
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
|
// 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 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"]
|
[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
|
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
|
During evaluation
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: failed to decode: illegal base64 data at input byte 0
|
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=")
|
std.base64DecodeBytes("ĀQ=")
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: input string appears not to be a base64 encoded string. Wrong length found (5)
|
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")
|
std.base64DecodeBytes("wrong")
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: base64DecodeBytes requires a string, got number
|
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)
|
std.base64DecodeBytes(1)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: failed to decode: illegal base64 data at input byte 0
|
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=")
|
std.base64Decode("ĀQ=")
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: input string appears not to be a base64 encoded string. Wrong length found (5)
|
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")
|
std.base64Decode("wrong")
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: base64DecodeBytes requires a string, got number
|
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)
|
std.base64Decode(1)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: base64 encountered a non-integer value in the array, got string
|
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"])
|
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
|
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])
|
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
|
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])
|
std.base64([1, 256])
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: base64 can only base64 encode strings / arrays of single bytes, got number
|
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)
|
std.base64(1)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: base64 encountered invalid codepoint value in the array (must be 0 <= X <= 255), got 256
|
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("Ā")
|
std.base64("Ā")
|
||||||
|
|
||||||
|
2
testdata/builtinChar3.golden
vendored
2
testdata/builtinChar3.golden
vendored
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: Codepoints must be >= 0, got -1
|
RUNTIME ERROR: Codepoints must be >= 0, got -1
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/builtinChar3:1:1-13 builtin function <char>
|
testdata/builtinChar3:1:1-13 $
|
||||||
|
|
||||||
std.char(-1)
|
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
|
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)
|
std.char(1114112)
|
||||||
|
|
||||||
|
2
testdata/builtinChar7.golden
vendored
2
testdata/builtinChar7.golden
vendored
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: Unexpected type string, expected number
|
RUNTIME ERROR: Unexpected type string, expected number
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/builtinChar7:1:1-16 builtin function <char>
|
testdata/builtinChar7:1:1-16 $
|
||||||
|
|
||||||
std.char("xxx")
|
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
|
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)
|
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
|
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")
|
std.objectFieldsEx({}, "xxx")
|
||||||
|
|
||||||
|
2
testdata/builtinObjectHasExBadBoolean.golden
vendored
2
testdata/builtinObjectHasExBadBoolean.golden
vendored
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: Unexpected type string, expected boolean
|
RUNTIME ERROR: Unexpected type string, expected boolean
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/builtinObjectHasExBadBoolean:1:1-34 builtin function <objectHasEx>
|
testdata/builtinObjectHasExBadBoolean:1:1-34 $
|
||||||
|
|
||||||
std.objectHasEx({}, "xxx", "xxx")
|
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
|
RUNTIME ERROR: Unexpected type number, expected string
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/builtinObjectHasExBadField:1:1-31 builtin function <objectHasEx>
|
testdata/builtinObjectHasExBadField:1:1-31 $
|
||||||
|
|
||||||
std.objectHasEx({}, 42, false)
|
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
|
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)
|
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
|
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")
|
std.reverse("asdf")
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: substr first parameter should be a string, got number
|
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)
|
std.substr(1, 0, 1)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: substr second parameter should be an integer, got 1.200000
|
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)
|
std.substr("hello", 1.2, 5)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: substr second parameter should be a number, got string
|
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)
|
std.substr("hello", "foo", 5)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: substr third parameter should be greater than zero, got -1
|
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)
|
std.substr("hello", 0, -1)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: substr third parameter should be an integer, got 1.200000
|
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)
|
std.substr("hello", 0, 1.2)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: substr third parameter should be a number, got string
|
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")
|
std.substr("hello", 0, "foo")
|
||||||
|
|
||||||
|
2
testdata/builtin_exp3.golden
vendored
2
testdata/builtin_exp3.golden
vendored
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: Overflow
|
RUNTIME ERROR: Overflow
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/builtin_exp3:1:1-14 builtin function <exp>
|
testdata/builtin_exp3:1:1-14 $
|
||||||
|
|
||||||
std.exp(1000)
|
std.exp(1000)
|
||||||
|
|
||||||
|
2
testdata/builtin_exp5.golden
vendored
2
testdata/builtin_exp5.golden
vendored
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: Overflow
|
RUNTIME ERROR: Overflow
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/builtin_exp5:1:1-31 builtin function <exp>
|
testdata/builtin_exp5:1:1-31 $
|
||||||
|
|
||||||
std.exp(100000000000000000000)
|
std.exp(100000000000000000000)
|
||||||
|
|
||||||
|
2
testdata/builtin_log5.golden
vendored
2
testdata/builtin_log5.golden
vendored
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: Overflow
|
RUNTIME ERROR: Overflow
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/builtin_log5:1:1-11 builtin function <log>
|
testdata/builtin_log5:1:1-11 $
|
||||||
|
|
||||||
std.log(0)
|
std.log(0)
|
||||||
|
|
||||||
|
2
testdata/builtin_log7.golden
vendored
2
testdata/builtin_log7.golden
vendored
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: Not a number
|
RUNTIME ERROR: Not a number
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/builtin_log7:1:1-12 builtin function <log>
|
testdata/builtin_log7:1:1-12 $
|
||||||
|
|
||||||
std.log(-1)
|
std.log(-1)
|
||||||
|
|
||||||
|
2
testdata/builtin_log8.golden
vendored
2
testdata/builtin_log8.golden
vendored
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: Not a number
|
RUNTIME ERROR: Not a number
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/builtin_log8:1:1-24 builtin function <log>
|
testdata/builtin_log8:1:1-24 $
|
||||||
|
|
||||||
std.log(-1000000000000)
|
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
|
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")
|
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 $
|
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'
|
error 'xxx'
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/extvar_error:1:1-23 builtin function <extVar>
|
testdata/extvar_error:1:1-23 $
|
||||||
|
|
||||||
std.extVar("errorVar")
|
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
|
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)
|
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
|
RUNTIME ERROR: Undefined external variable: UNKNOWN
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/extvar_unknown:1:1-22 builtin function <extVar>
|
testdata/extvar_unknown:1:1-22 $
|
||||||
|
|
||||||
std.extVar("UNKNOWN")
|
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
|
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 $
|
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
|
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 $
|
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"
|
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
|
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] }
|
{ [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
|
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] }
|
{ [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
|
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) + '.',
|
error 'Operator % cannot be used on types ' + std.type(a) + ' and ' + std.type(b) + '.',
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
testdata/percent_bad:1:1-9
|
||||||
|
|
||||||
|
42 % "x"
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
During evaluation
|
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)
|
std.format(a, b)
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
testdata/percent_bad2:1:1-9
|
||||||
|
|
||||||
|
"x" % 42
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
During evaluation
|
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) + '.',
|
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
|
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)
|
std.format(a, b)
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
testdata/percent_format_str4:1:1-20
|
||||||
|
|
||||||
|
"x %s" % ["y", "z"]
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
During evaluation
|
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)
|
std.format(a, b)
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
testdata/percent_format_str5:1:1-18
|
||||||
|
|
||||||
|
"x %s %s" % ["y"]
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
During evaluation
|
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)
|
std.format(a, b)
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
testdata/percent_format_str6:1:1-16
|
||||||
|
|
||||||
|
"x %s %s" % "y"
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
During evaluation
|
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)
|
std.format(a, b)
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
testdata/percent_format_str7:1:1-15
|
||||||
|
|
||||||
|
"x %d" % ["y"]
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
During evaluation
|
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.
|
RUNTIME ERROR: Division by zero.
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
<std>:235:7-23 builtin function <modulo>
|
<std>:235:7-23 function <anonymous>
|
||||||
|
|
||||||
std.modulo(a, b)
|
std.modulo(a, b)
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
testdata/percent_mod_int5:1:1-7
|
||||||
|
|
||||||
|
42 % 0
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
During evaluation
|
During evaluation
|
||||||
|
2
testdata/pow4.golden
vendored
2
testdata/pow4.golden
vendored
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: Not a number
|
RUNTIME ERROR: Not a number
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/pow4:1:1-17 builtin function <pow>
|
testdata/pow4:1:1-17 $
|
||||||
|
|
||||||
std.pow(-1, 0.2)
|
std.pow(-1, 0.2)
|
||||||
|
|
||||||
|
2
testdata/pow7.golden
vendored
2
testdata/pow7.golden
vendored
@ -1,6 +1,6 @@
|
|||||||
RUNTIME ERROR: Overflow
|
RUNTIME ERROR: Overflow
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/pow7:2:1-23 builtin function <pow>
|
testdata/pow7:2:1-23 $
|
||||||
|
|
||||||
std.pow(1.1, 7447.082)
|
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
|
RUNTIME ERROR: Unexpected type string, expected number
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/pow8:1:1-19 builtin function <pow>
|
testdata/pow8:1:1-19 $
|
||||||
|
|
||||||
std.pow("xxx", 42)
|
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
|
RUNTIME ERROR: Unexpected type string, expected number
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
testdata/pow9:1:1-19 builtin function <pow>
|
testdata/pow9:1:1-19 $
|
||||||
|
|
||||||
std.pow(42, "xxx")
|
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
|
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")
|
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
|
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("")
|
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
|
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("ą")
|
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
|
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)
|
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
|
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, [])
|
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
|
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)
|
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
|
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")
|
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
|
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")
|
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
|
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)
|
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;
|
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"]))
|
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
|
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]])
|
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
|
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"])
|
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
|
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)
|
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
|
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")
|
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
|
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)
|
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
|
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)
|
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
|
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)
|
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
|
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)
|
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
|
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)
|
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
|
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([], [])
|
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
|
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({}, {})
|
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
|
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)
|
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"])
|
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"])
|
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
|
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"]])
|
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.
|
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")
|
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 $
|
testdata/string_plus_function:1:1-24 $
|
||||||
|
|
||||||
|
4
tests.sh
4
tests.sh
@ -3,6 +3,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
PYTHON_COMMAND=${PYTHON_COMMAND:=python}
|
PYTHON_COMMAND=${PYTHON_COMMAND:=python}
|
||||||
|
JSONNET_CPP_DIR=${JSONNET_CPP_DIR:=$PWD/cpp-jsonnet}
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
@ -19,6 +20,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
export IMPLEMENTATION=golang
|
export IMPLEMENTATION=golang
|
||||||
|
export OVERRIDE_DIR="$PWD/testdata/cpp-tests-override/"
|
||||||
|
|
||||||
go build ./cmd/jsonnet
|
go build ./cmd/jsonnet
|
||||||
go build ./cmd/jsonnetfmt
|
go build ./cmd/jsonnetfmt
|
||||||
@ -28,5 +30,5 @@ export DISABLE_ERROR_TESTS=true
|
|||||||
export JSONNETFMT_BIN="$PWD/jsonnetfmt"
|
export JSONNETFMT_BIN="$PWD/jsonnetfmt"
|
||||||
export JSONNET_BIN="$PWD/jsonnet"
|
export JSONNET_BIN="$PWD/jsonnet"
|
||||||
|
|
||||||
cd cpp-jsonnet
|
cd "$JSONNET_CPP_DIR"
|
||||||
exec ./tests.sh
|
exec ./tests.sh
|
||||||
|
42
thunks.go
42
thunks.go
@ -32,7 +32,7 @@ type readyValue struct {
|
|||||||
content value
|
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
|
return rv.content, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,14 +58,14 @@ func readyThunk(content value) *cachedThunk {
|
|||||||
return &cachedThunk{content: content}
|
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 {
|
if t.content != nil {
|
||||||
return t.content, nil
|
return t.content, nil
|
||||||
}
|
}
|
||||||
if t.err != nil {
|
if t.err != nil {
|
||||||
return nil, t.err
|
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 {
|
if err != nil {
|
||||||
// TODO(sbarzowski) perhaps cache errors as well
|
// TODO(sbarzowski) perhaps cache errors as well
|
||||||
// may be necessary if we allow handling them in any way
|
// may be necessary if we allow handling them in any way
|
||||||
@ -87,9 +87,9 @@ type codeUnboundField struct {
|
|||||||
body ast.Node
|
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)
|
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.
|
// Provide additional bindings for a field. It shadows bindings from the object.
|
||||||
@ -99,7 +99,7 @@ type bindingsUnboundField struct {
|
|||||||
bindings bindingFrame
|
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)
|
upValues := make(bindingFrame)
|
||||||
for variable, pvalue := range origBindings {
|
for variable, pvalue := range origBindings {
|
||||||
upValues[variable] = pvalue
|
upValues[variable] = pvalue
|
||||||
@ -107,7 +107,7 @@ func (f *bindingsUnboundField) evaluate(i *interpreter, trace traceElement, sb s
|
|||||||
for variable, pvalue := range f.bindings {
|
for variable, pvalue := range f.bindings {
|
||||||
upValues[variable] = pvalue
|
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.
|
// plusSuperUnboundField represents a `field+: ...` that hasn't been bound to an object.
|
||||||
@ -115,19 +115,19 @@ type plusSuperUnboundField struct {
|
|||||||
inner unboundField
|
inner unboundField
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *plusSuperUnboundField) evaluate(i *interpreter, trace traceElement, sb selfBinding, origBinding bindingFrame, fieldName string) (value, error) {
|
func (f *plusSuperUnboundField) evaluate(i *interpreter, sb selfBinding, origBinding bindingFrame, fieldName string) (value, error) {
|
||||||
right, err := f.inner.evaluate(i, trace, sb, origBinding, fieldName)
|
right, err := f.inner.evaluate(i, sb, origBinding, fieldName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !objectHasField(sb.super(), fieldName, withHidden) {
|
if !objectHasField(sb.super(), fieldName, withHidden) {
|
||||||
return right, nil
|
return right, nil
|
||||||
}
|
}
|
||||||
left, err := objectIndex(i, trace, sb.super(), fieldName)
|
left, err := objectIndex(i, sb.super(), fieldName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return builtinPlus(i, trace, left, right)
|
return builtinPlus(i, left, right)
|
||||||
}
|
}
|
||||||
|
|
||||||
// evalCallables
|
// evalCallables
|
||||||
@ -141,9 +141,9 @@ type closure struct {
|
|||||||
params []namedParameter
|
params []namedParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
func forceThunks(i *interpreter, trace traceElement, args *bindingFrame) error {
|
func forceThunks(i *interpreter, args *bindingFrame) error {
|
||||||
for _, arg := range *args {
|
for _, arg := range *args {
|
||||||
_, err := arg.getValue(i, trace)
|
_, err := arg.getValue(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -151,7 +151,7 @@ func forceThunks(i *interpreter, trace traceElement, args *bindingFrame) error {
|
|||||||
return nil
|
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)
|
argThunks := make(bindingFrame)
|
||||||
parameters := closure.parameters()
|
parameters := closure.parameters()
|
||||||
for i, arg := range arguments.positional {
|
for i, arg := range arguments.positional {
|
||||||
@ -175,7 +175,7 @@ func (closure *closure) evalCall(arguments callArguments, i *interpreter, trace
|
|||||||
}
|
}
|
||||||
|
|
||||||
if arguments.tailstrict {
|
if arguments.tailstrict {
|
||||||
err := forceThunks(i, trace, &argThunks)
|
err := forceThunks(i, &argThunks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -185,7 +185,7 @@ func (closure *closure) evalCall(arguments callArguments, i *interpreter, trace
|
|||||||
addBindings(closure.env.upValues, argThunks),
|
addBindings(closure.env.upValues, argThunks),
|
||||||
closure.env.selfBinding,
|
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 {
|
func (closure *closure) parameters() []namedParameter {
|
||||||
@ -220,15 +220,15 @@ type NativeFunction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// evalCall evaluates a call to a NativeFunction and returns the result.
|
// 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{})
|
flatArgs := flattenArgs(arguments, native.parameters(), []value{})
|
||||||
nativeArgs := make([]interface{}, 0, len(flatArgs))
|
nativeArgs := make([]interface{}, 0, len(flatArgs))
|
||||||
for _, arg := range flatArgs {
|
for _, arg := range flatArgs {
|
||||||
v, err := i.evaluatePV(arg, trace)
|
v, err := i.evaluatePV(arg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
json, err := i.manifestJSON(trace, v)
|
json, err := i.manifestJSON(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -236,9 +236,9 @@ func (native *NativeFunction) evalCall(arguments callArguments, i *interpreter,
|
|||||||
}
|
}
|
||||||
resultJSON, err := native.Func(nativeArgs)
|
resultJSON, err := native.Func(nativeArgs)
|
||||||
if err != nil {
|
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.
|
// 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"?
|
// TODO(sbarzowski) perhaps call it just "Thunk"?
|
||||||
type potentialValue interface {
|
type potentialValue interface {
|
||||||
// fromWhere keeps the information from where the evaluation was requested.
|
// fromWhere keeps the information from where the evaluation was requested.
|
||||||
getValue(i *interpreter, fromWhere traceElement) (value, error)
|
getValue(i *interpreter) (value, error)
|
||||||
|
|
||||||
aPotentialValue()
|
aPotentialValue()
|
||||||
}
|
}
|
||||||
@ -78,7 +78,7 @@ type valueString interface {
|
|||||||
length() int
|
length() int
|
||||||
getRunes() []rune
|
getRunes() []rune
|
||||||
getGoString() string
|
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
|
// valueFlatString represents a string value, internally using a []rune for quick
|
||||||
@ -89,11 +89,11 @@ type valueFlatString struct {
|
|||||||
value []rune
|
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() {
|
if 0 <= index && index < s.length() {
|
||||||
return makeValueString(string(s.value[index])), nil
|
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 {
|
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 {
|
if 0 <= index && index < s.len {
|
||||||
s.flattenToLeft()
|
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 {
|
func (s *valueStringTree) getRunes() []rune {
|
||||||
@ -290,11 +290,11 @@ type valueArray struct {
|
|||||||
elements []*cachedThunk
|
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() {
|
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 {
|
func (arr *valueArray) length() int {
|
||||||
@ -337,29 +337,29 @@ type valueFunction struct {
|
|||||||
|
|
||||||
// TODO(sbarzowski) better name?
|
// TODO(sbarzowski) better name?
|
||||||
type evalCallable interface {
|
type evalCallable interface {
|
||||||
evalCall(args callArguments, i *interpreter, trace traceElement) (value, error)
|
evalCall(args callArguments, i *interpreter) (value, error)
|
||||||
parameters() []namedParameter
|
parameters() []namedParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *valueFunction) call(i *interpreter, trace traceElement, args callArguments) (value, error) {
|
func (f *valueFunction) call(i *interpreter, args callArguments) (value, error) {
|
||||||
err := checkArguments(i, trace, args, f.parameters())
|
err := checkArguments(i, args, f.parameters())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return f.ec.evalCall(args, i, trace)
|
return f.ec.evalCall(args, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *valueFunction) parameters() []namedParameter {
|
func (f *valueFunction) parameters() []namedParameter {
|
||||||
return f.ec.parameters()
|
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)
|
numPassed := len(args.positional)
|
||||||
maxExpected := len(params)
|
maxExpected := len(params)
|
||||||
|
|
||||||
if numPassed > maxExpected {
|
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.
|
// Parameter names the function will accept.
|
||||||
@ -375,17 +375,17 @@ func checkArguments(i *interpreter, trace traceElement, args callArguments, para
|
|||||||
}
|
}
|
||||||
for _, arg := range args.named {
|
for _, arg := range args.named {
|
||||||
if _, present := received[arg.name]; present {
|
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 {
|
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
|
received[arg.name] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, param := range params {
|
for _, param := range params {
|
||||||
if _, present := received[param.name]; !present && param.defaultArg == nil {
|
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
|
return objectType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *valueObject) index(i *interpreter, trace traceElement, field string) (value, error) {
|
func (obj *valueObject) index(i *interpreter, field string) (value, error) {
|
||||||
return objectIndex(i, trace, objectBinding(obj), field)
|
return objectIndex(i, objectBinding(obj), field)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *valueObject) assertionsChecked() bool {
|
func (obj *valueObject) assertionsChecked() bool {
|
||||||
@ -545,14 +545,14 @@ type simpleObject struct {
|
|||||||
locals []objectLocal
|
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) {
|
switch curr := curr.(type) {
|
||||||
case *extendedObject:
|
case *extendedObject:
|
||||||
err := checkAssertionsHelper(i, trace, obj, curr.right, superDepth)
|
err := checkAssertionsHelper(i, obj, curr.right, superDepth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -561,7 +561,7 @@ func checkAssertionsHelper(i *interpreter, trace traceElement, obj *valueObject,
|
|||||||
for _, assert := range curr.asserts {
|
for _, assert := range curr.asserts {
|
||||||
sb := selfBinding{self: obj, superDepth: superDepth}
|
sb := selfBinding{self: obj, superDepth: superDepth}
|
||||||
fieldUpValues := prepareFieldUpvalues(sb, curr.upValues, curr.locals)
|
fieldUpValues := prepareFieldUpvalues(sb, curr.upValues, curr.locals)
|
||||||
_, err := assert.evaluate(i, trace, sb, fieldUpValues, "")
|
_, err := assert.evaluate(i, sb, fieldUpValues, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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() {
|
if !obj.assertionsChecked() {
|
||||||
// Assertions may refer to the object that will normally
|
// Assertions may refer to the object that will normally
|
||||||
// trigger checking of assertions, resulting in an endless recursion.
|
// trigger checking of assertions, resulting in an endless recursion.
|
||||||
// To avoid that, while we check them, we treat them as already passed.
|
// To avoid that, while we check them, we treat them as already passed.
|
||||||
obj.setAssertionsCheckResult(errNoErrorInObjectInvariants)
|
obj.setAssertionsCheckResult(errNoErrorInObjectInvariants)
|
||||||
obj.setAssertionsCheckResult(checkAssertionsHelper(i, trace, obj, obj.uncached, 0))
|
obj.setAssertionsCheckResult(checkAssertionsHelper(i, obj, obj.uncached, 0))
|
||||||
}
|
}
|
||||||
return obj.getAssertionsCheckResult()
|
return obj.getAssertionsCheckResult()
|
||||||
}
|
}
|
||||||
@ -610,7 +610,7 @@ type simpleObjectField struct {
|
|||||||
|
|
||||||
// unboundField is a field that doesn't know yet in which object it is.
|
// unboundField is a field that doesn't know yet in which object it is.
|
||||||
type unboundField interface {
|
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).
|
// extendedObject represents an object created through inheritance (left + right).
|
||||||
@ -699,18 +699,18 @@ func prepareFieldUpvalues(sb selfBinding, upValues bindingFrame, locals []object
|
|||||||
return newUpValues
|
return newUpValues
|
||||||
}
|
}
|
||||||
|
|
||||||
func objectIndex(i *interpreter, trace traceElement, sb selfBinding, fieldName string) (value, error) {
|
func objectIndex(i *interpreter, sb selfBinding, fieldName string) (value, error) {
|
||||||
err := checkAssertions(i, trace, sb.self)
|
err := checkAssertions(i, sb.self)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if sb.superDepth >= sb.self.uncached.inheritanceSize() {
|
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)
|
found, field, upValues, locals, foundAt := findField(sb.self.uncached, sb.superDepth, fieldName)
|
||||||
if !found {
|
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 {
|
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}
|
fieldSelfBinding := selfBinding{self: sb.self, superDepth: foundAt}
|
||||||
fieldUpValues := prepareFieldUpvalues(fieldSelfBinding, upValues, locals)
|
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 {
|
if err == nil {
|
||||||
sb.self.cache[objectCacheKey{field: fieldName, depth: foundAt}] = val
|
sb.self.cache[objectCacheKey{field: fieldName, depth: foundAt}] = val
|
||||||
|
Loading…
Reference in New Issue
Block a user