mirror of
https://github.com/google/go-jsonnet.git
synced 2025-08-07 23:07:14 +02:00
parent
9047718ad0
commit
8638a21287
31
desugarer.go
31
desugarer.go
@ -110,26 +110,23 @@ func desugarFields(location ast.LocationRange, fields *ast.ObjectFields, objLeve
|
||||
|
||||
// Simplify asserts
|
||||
// TODO(dcunnin): this
|
||||
for _, field := range *fields {
|
||||
for i := range *fields {
|
||||
field := &(*fields)[i]
|
||||
if field.Kind != ast.ObjectAssert {
|
||||
continue
|
||||
}
|
||||
/*
|
||||
AST *msg = field.expr3
|
||||
field.expr3 = nil
|
||||
if (msg == nil) {
|
||||
auto msg_str = U"Object assertion failed."
|
||||
msg = alloc->make<ast.LiteralString>(field.expr2->location, msg_str,
|
||||
ast.LiteralString::DOUBLE, "")
|
||||
}
|
||||
|
||||
// if expr2 then true else error msg
|
||||
field.expr2 = alloc->make<ast.Conditional>(
|
||||
ast->location,
|
||||
field.expr2,
|
||||
alloc->make<ast.LiteralBoolean>(E, true),
|
||||
alloc->make<Error>(msg->location, msg))
|
||||
*/
|
||||
msg := field.Expr3
|
||||
if msg == nil {
|
||||
msg = buildLiteralString("Object assertion failed.")
|
||||
}
|
||||
field.Expr3 = nil
|
||||
onFailure := &ast.Error{Expr: msg}
|
||||
assertion := &ast.Conditional{
|
||||
Cond: field.Expr2,
|
||||
BranchTrue: &ast.LiteralBoolean{Value: true}, // ignored anyway
|
||||
BranchFalse: onFailure,
|
||||
}
|
||||
field.Expr2 = assertion
|
||||
}
|
||||
|
||||
// Remove methods
|
||||
|
@ -326,8 +326,12 @@ func (i *interpreter) evaluate(a ast.Node, context *TraceContext) (value, error)
|
||||
}
|
||||
fields[fieldName] = valueSimpleObjectField{field.Hide, &codeUnboundField{field.Body}}
|
||||
}
|
||||
var asserts []unboundField
|
||||
for _, assert := range ast.Asserts {
|
||||
asserts = append(asserts, &codeUnboundField{assert})
|
||||
}
|
||||
upValues := i.capture(ast.FreeVariables())
|
||||
return makeValueSimpleObject(upValues, fields, ast.Asserts), nil
|
||||
return makeValueSimpleObject(upValues, fields, asserts), nil
|
||||
|
||||
case *ast.Error:
|
||||
msgVal, err := e.evalInCurrentContext(ast.Expr)
|
||||
@ -570,6 +574,11 @@ func (i *interpreter) manifestJSON(trace *TraceElement, v value, multiline bool,
|
||||
fieldNames := objectFields(v, true)
|
||||
sort.Strings(fieldNames)
|
||||
|
||||
err := checkAssertions(e, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(fieldNames) == 0 {
|
||||
buf.WriteString("{ }")
|
||||
} else {
|
||||
|
1
testdata/object_invariant.golden
vendored
Normal file
1
testdata/object_invariant.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ }
|
1
testdata/object_invariant.input
vendored
Normal file
1
testdata/object_invariant.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ assert true }
|
1
testdata/object_invariant10.golden
vendored
Normal file
1
testdata/object_invariant10.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: Object assertion failed.
|
1
testdata/object_invariant10.input
vendored
Normal file
1
testdata/object_invariant10.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ assert true, assert false }
|
1
testdata/object_invariant11.golden
vendored
Normal file
1
testdata/object_invariant11.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: Object assertion failed.
|
1
testdata/object_invariant11.input
vendored
Normal file
1
testdata/object_invariant11.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ assert false }.x
|
1
testdata/object_invariant12.golden
vendored
Normal file
1
testdata/object_invariant12.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ }
|
1
testdata/object_invariant12.input
vendored
Normal file
1
testdata/object_invariant12.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ assert 5 == 5 }
|
1
testdata/object_invariant13.golden
vendored
Normal file
1
testdata/object_invariant13.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: x
|
1
testdata/object_invariant13.input
vendored
Normal file
1
testdata/object_invariant13.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ assert error "x" }
|
1
testdata/object_invariant14.golden
vendored
Normal file
1
testdata/object_invariant14.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: xxx
|
1
testdata/object_invariant14.input
vendored
Normal file
1
testdata/object_invariant14.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ assert false: "xxx" }
|
1
testdata/object_invariant2.golden
vendored
Normal file
1
testdata/object_invariant2.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: Object assertion failed.
|
1
testdata/object_invariant2.input
vendored
Normal file
1
testdata/object_invariant2.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ assert false }
|
1
testdata/object_invariant3.golden
vendored
Normal file
1
testdata/object_invariant3.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
[ ]
|
1
testdata/object_invariant3.input
vendored
Normal file
1
testdata/object_invariant3.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
std.objectFields({assert false})
|
1
testdata/object_invariant4.golden
vendored
Normal file
1
testdata/object_invariant4.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
false
|
1
testdata/object_invariant4.input
vendored
Normal file
1
testdata/object_invariant4.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
std.objectHas({assert false}, "x")
|
1
testdata/object_invariant5.golden
vendored
Normal file
1
testdata/object_invariant5.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
"object"
|
1
testdata/object_invariant5.input
vendored
Normal file
1
testdata/object_invariant5.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
std.type({assert false})
|
3
testdata/object_invariant6.golden
vendored
Normal file
3
testdata/object_invariant6.golden
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"x": 5
|
||||
}
|
1
testdata/object_invariant6.input
vendored
Normal file
1
testdata/object_invariant6.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{assert self.x == 5, x: 5}
|
1
testdata/object_invariant7.golden
vendored
Normal file
1
testdata/object_invariant7.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: Field does not exist: x
|
1
testdata/object_invariant7.input
vendored
Normal file
1
testdata/object_invariant7.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ x: 5, assert super.x == 5 }
|
1
testdata/object_invariant8.golden
vendored
Normal file
1
testdata/object_invariant8.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: Object assertion failed.
|
1
testdata/object_invariant8.input
vendored
Normal file
1
testdata/object_invariant8.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ x: 5, assert self.x == 4 }
|
1
testdata/object_invariant9.golden
vendored
Normal file
1
testdata/object_invariant9.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: Object assertion failed.
|
1
testdata/object_invariant9.input
vendored
Normal file
1
testdata/object_invariant9.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ assert true, assert false }
|
455
testdata/object_invariant_perf.golden
vendored
Normal file
455
testdata/object_invariant_perf.golden
vendored
Normal file
@ -0,0 +1,455 @@
|
||||
[
|
||||
{
|
||||
"v": -1
|
||||
},
|
||||
{
|
||||
"v": 0
|
||||
},
|
||||
{
|
||||
"v": 1
|
||||
},
|
||||
{
|
||||
"v": 2
|
||||
},
|
||||
{
|
||||
"v": 3
|
||||
},
|
||||
{
|
||||
"v": 4
|
||||
},
|
||||
{
|
||||
"v": 5
|
||||
},
|
||||
{
|
||||
"v": 6
|
||||
},
|
||||
{
|
||||
"v": 7
|
||||
},
|
||||
{
|
||||
"v": 8
|
||||
},
|
||||
{
|
||||
"v": 9
|
||||
},
|
||||
{
|
||||
"v": 10
|
||||
},
|
||||
{
|
||||
"v": 11
|
||||
},
|
||||
{
|
||||
"v": 12
|
||||
},
|
||||
{
|
||||
"v": 13
|
||||
},
|
||||
{
|
||||
"v": 14
|
||||
},
|
||||
{
|
||||
"v": 15
|
||||
},
|
||||
{
|
||||
"v": 16
|
||||
},
|
||||
{
|
||||
"v": 17
|
||||
},
|
||||
{
|
||||
"v": 18
|
||||
},
|
||||
{
|
||||
"v": 19
|
||||
},
|
||||
{
|
||||
"v": 20
|
||||
},
|
||||
{
|
||||
"v": 21
|
||||
},
|
||||
{
|
||||
"v": 22
|
||||
},
|
||||
{
|
||||
"v": 23
|
||||
},
|
||||
{
|
||||
"v": 24
|
||||
},
|
||||
{
|
||||
"v": 25
|
||||
},
|
||||
{
|
||||
"v": 26
|
||||
},
|
||||
{
|
||||
"v": 27
|
||||
},
|
||||
{
|
||||
"v": 28
|
||||
},
|
||||
{
|
||||
"v": 29
|
||||
},
|
||||
{
|
||||
"v": 30
|
||||
},
|
||||
{
|
||||
"v": 31
|
||||
},
|
||||
{
|
||||
"v": 32
|
||||
},
|
||||
{
|
||||
"v": 33
|
||||
},
|
||||
{
|
||||
"v": 34
|
||||
},
|
||||
{
|
||||
"v": 35
|
||||
},
|
||||
{
|
||||
"v": 36
|
||||
},
|
||||
{
|
||||
"v": 37
|
||||
},
|
||||
{
|
||||
"v": 38
|
||||
},
|
||||
{
|
||||
"v": 39
|
||||
},
|
||||
{
|
||||
"v": 40
|
||||
},
|
||||
{
|
||||
"v": 41
|
||||
},
|
||||
{
|
||||
"v": 42
|
||||
},
|
||||
{
|
||||
"v": 43
|
||||
},
|
||||
{
|
||||
"v": 44
|
||||
},
|
||||
{
|
||||
"v": 45
|
||||
},
|
||||
{
|
||||
"v": 46
|
||||
},
|
||||
{
|
||||
"v": 47
|
||||
},
|
||||
{
|
||||
"v": 48
|
||||
},
|
||||
{
|
||||
"v": 49
|
||||
},
|
||||
{
|
||||
"v": 50
|
||||
},
|
||||
{
|
||||
"v": 51
|
||||
},
|
||||
{
|
||||
"v": 52
|
||||
},
|
||||
{
|
||||
"v": 53
|
||||
},
|
||||
{
|
||||
"v": 54
|
||||
},
|
||||
{
|
||||
"v": 55
|
||||
},
|
||||
{
|
||||
"v": 56
|
||||
},
|
||||
{
|
||||
"v": 57
|
||||
},
|
||||
{
|
||||
"v": 58
|
||||
},
|
||||
{
|
||||
"v": 59
|
||||
},
|
||||
{
|
||||
"v": 60
|
||||
},
|
||||
{
|
||||
"v": 61
|
||||
},
|
||||
{
|
||||
"v": 62
|
||||
},
|
||||
{
|
||||
"v": 63
|
||||
},
|
||||
{
|
||||
"v": 64
|
||||
},
|
||||
{
|
||||
"v": 65
|
||||
},
|
||||
{
|
||||
"v": 66
|
||||
},
|
||||
{
|
||||
"v": 67
|
||||
},
|
||||
{
|
||||
"v": 68
|
||||
},
|
||||
{
|
||||
"v": 69
|
||||
},
|
||||
{
|
||||
"v": 70
|
||||
},
|
||||
{
|
||||
"v": 71
|
||||
},
|
||||
{
|
||||
"v": 72
|
||||
},
|
||||
{
|
||||
"v": 73
|
||||
},
|
||||
{
|
||||
"v": 74
|
||||
},
|
||||
{
|
||||
"v": 75
|
||||
},
|
||||
{
|
||||
"v": 76
|
||||
},
|
||||
{
|
||||
"v": 77
|
||||
},
|
||||
{
|
||||
"v": 78
|
||||
},
|
||||
{
|
||||
"v": 79
|
||||
},
|
||||
{
|
||||
"v": 80
|
||||
},
|
||||
{
|
||||
"v": 81
|
||||
},
|
||||
{
|
||||
"v": 82
|
||||
},
|
||||
{
|
||||
"v": 83
|
||||
},
|
||||
{
|
||||
"v": 84
|
||||
},
|
||||
{
|
||||
"v": 85
|
||||
},
|
||||
{
|
||||
"v": 86
|
||||
},
|
||||
{
|
||||
"v": 87
|
||||
},
|
||||
{
|
||||
"v": 88
|
||||
},
|
||||
{
|
||||
"v": 89
|
||||
},
|
||||
{
|
||||
"v": 90
|
||||
},
|
||||
{
|
||||
"v": 91
|
||||
},
|
||||
{
|
||||
"v": 92
|
||||
},
|
||||
{
|
||||
"v": 93
|
||||
},
|
||||
{
|
||||
"v": 94
|
||||
},
|
||||
{
|
||||
"v": 95
|
||||
},
|
||||
{
|
||||
"v": 96
|
||||
},
|
||||
{
|
||||
"v": 97
|
||||
},
|
||||
{
|
||||
"v": 98
|
||||
},
|
||||
{
|
||||
"v": 99
|
||||
},
|
||||
{
|
||||
"v": 100
|
||||
},
|
||||
{
|
||||
"v": 101
|
||||
},
|
||||
{
|
||||
"v": 102
|
||||
},
|
||||
{
|
||||
"v": 103
|
||||
},
|
||||
{
|
||||
"v": 104
|
||||
},
|
||||
{
|
||||
"v": 105
|
||||
},
|
||||
{
|
||||
"v": 106
|
||||
},
|
||||
{
|
||||
"v": 107
|
||||
},
|
||||
{
|
||||
"v": 108
|
||||
},
|
||||
{
|
||||
"v": 109
|
||||
},
|
||||
{
|
||||
"v": 110
|
||||
},
|
||||
{
|
||||
"v": 111
|
||||
},
|
||||
{
|
||||
"v": 112
|
||||
},
|
||||
{
|
||||
"v": 113
|
||||
},
|
||||
{
|
||||
"v": 114
|
||||
},
|
||||
{
|
||||
"v": 115
|
||||
},
|
||||
{
|
||||
"v": 116
|
||||
},
|
||||
{
|
||||
"v": 117
|
||||
},
|
||||
{
|
||||
"v": 118
|
||||
},
|
||||
{
|
||||
"v": 119
|
||||
},
|
||||
{
|
||||
"v": 120
|
||||
},
|
||||
{
|
||||
"v": 121
|
||||
},
|
||||
{
|
||||
"v": 122
|
||||
},
|
||||
{
|
||||
"v": 123
|
||||
},
|
||||
{
|
||||
"v": 124
|
||||
},
|
||||
{
|
||||
"v": 125
|
||||
},
|
||||
{
|
||||
"v": 126
|
||||
},
|
||||
{
|
||||
"v": 127
|
||||
},
|
||||
{
|
||||
"v": 128
|
||||
},
|
||||
{
|
||||
"v": 129
|
||||
},
|
||||
{
|
||||
"v": 130
|
||||
},
|
||||
{
|
||||
"v": 131
|
||||
},
|
||||
{
|
||||
"v": 132
|
||||
},
|
||||
{
|
||||
"v": 133
|
||||
},
|
||||
{
|
||||
"v": 134
|
||||
},
|
||||
{
|
||||
"v": 135
|
||||
},
|
||||
{
|
||||
"v": 136
|
||||
},
|
||||
{
|
||||
"v": 137
|
||||
},
|
||||
{
|
||||
"v": 138
|
||||
},
|
||||
{
|
||||
"v": 139
|
||||
},
|
||||
{
|
||||
"v": 140
|
||||
},
|
||||
{
|
||||
"v": 141
|
||||
},
|
||||
{
|
||||
"v": 142
|
||||
},
|
||||
{
|
||||
"v": 143
|
||||
},
|
||||
{
|
||||
"v": 144
|
||||
},
|
||||
{
|
||||
"v": 145
|
||||
},
|
||||
{
|
||||
"v": 146
|
||||
},
|
||||
{
|
||||
"v": 147
|
||||
},
|
||||
{
|
||||
"v": 148
|
||||
},
|
||||
{
|
||||
"v": 149
|
||||
}
|
||||
]
|
2
testdata/object_invariant_perf.input
vendored
Normal file
2
testdata/object_invariant_perf.input
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
local arr = [{v: -1}] + std.makeArray(150, function(x) { v: x, assert arr[x].v == self.v - 1 });
|
||||
arr
|
1
testdata/object_invariant_plus.golden
vendored
Normal file
1
testdata/object_invariant_plus.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: Object assertion failed.
|
1
testdata/object_invariant_plus.input
vendored
Normal file
1
testdata/object_invariant_plus.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{assert false} + {assert true}
|
1
testdata/object_invariant_plus2.golden
vendored
Normal file
1
testdata/object_invariant_plus2.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: Object assertion failed.
|
1
testdata/object_invariant_plus2.input
vendored
Normal file
1
testdata/object_invariant_plus2.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{assert true} + {assert false}
|
1
testdata/object_invariant_plus3.golden
vendored
Normal file
1
testdata/object_invariant_plus3.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ }
|
1
testdata/object_invariant_plus3.input
vendored
Normal file
1
testdata/object_invariant_plus3.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{assert true} + {assert true}
|
3
testdata/object_invariant_plus4.golden
vendored
Normal file
3
testdata/object_invariant_plus4.golden
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"x": 5
|
||||
}
|
1
testdata/object_invariant_plus4.input
vendored
Normal file
1
testdata/object_invariant_plus4.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{assert self.x == 5} { x: 5 }
|
3
testdata/object_invariant_plus5.golden
vendored
Normal file
3
testdata/object_invariant_plus5.golden
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"x": 3
|
||||
}
|
1
testdata/object_invariant_plus5.input
vendored
Normal file
1
testdata/object_invariant_plus5.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{x: 1, assert self.x == 3} {x: 2, assert super.x == 1} {x: 3, assert super.x == 2}
|
1
testdata/object_invariant_plus6.golden
vendored
Normal file
1
testdata/object_invariant_plus6.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: yyy
|
1
testdata/object_invariant_plus6.input
vendored
Normal file
1
testdata/object_invariant_plus6.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ assert false: "xxx" } { assert false: "yyy" }
|
3
testdata/object_invariant_plus7.golden
vendored
Normal file
3
testdata/object_invariant_plus7.golden
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"x": 4
|
||||
}
|
2
testdata/object_invariant_plus7.input
vendored
Normal file
2
testdata/object_invariant_plus7.input
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
({x: 1} {x: 2, assert 1 == super.x}) +
|
||||
({x: 3, assert 2 == super.x} {x: 4, assert 3 == super.x})
|
2003
testdata/std.makeArray_recursive.golden
vendored
Normal file
2003
testdata/std.makeArray_recursive.golden
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
testdata/std.makeArray_recursive.input
vendored
Normal file
1
testdata/std.makeArray_recursive.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
local arr = [0] + std.makeArray(2000, function(i) arr[i] + 1); arr
|
1
testdata/std.makeArray_recursive_evalutation_order_matters.golden
vendored
Normal file
1
testdata/std.makeArray_recursive_evalutation_order_matters.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
RUNTIME ERROR: Max stack frames exceeded.
|
1
testdata/std.makeArray_recursive_evalutation_order_matters.input
vendored
Normal file
1
testdata/std.makeArray_recursive_evalutation_order_matters.input
vendored
Normal file
@ -0,0 +1 @@
|
||||
local arr = [0] + std.makeArray(2000, function(i) arr[i] + 1); arr[500]
|
@ -75,7 +75,7 @@ type callThunk struct {
|
||||
}
|
||||
|
||||
func makeCallThunk(ec evalCallable, args callArguments) potentialValue {
|
||||
return &callThunk{function: ec, args: args}
|
||||
return makeCachedThunk(&callThunk{function: ec, args: args})
|
||||
}
|
||||
|
||||
func (th *callThunk) getValue(i *interpreter, trace *TraceElement) (value, error) {
|
||||
|
79
value.go
79
value.go
@ -16,6 +16,7 @@ limitations under the License.
|
||||
package jsonnet
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-jsonnet/ast"
|
||||
@ -269,6 +270,9 @@ type valueObject interface {
|
||||
value
|
||||
inheritanceSize() int
|
||||
index(e *evaluator, field string) (value, error)
|
||||
assertionsChecked() bool
|
||||
setAssertionsCheckResult(err error)
|
||||
getAssertionsCheckResult() error
|
||||
}
|
||||
|
||||
type selfBinding struct {
|
||||
@ -276,7 +280,7 @@ type selfBinding struct {
|
||||
// that this is not the same as context, because we could be inside a function,
|
||||
// inside an object and then context would be the function, but self would still point
|
||||
// to the object.
|
||||
self value
|
||||
self valueObject
|
||||
|
||||
// superDepth is the "super" level of self. Sometimes, we look upwards in the
|
||||
// inheritance tree, e.g. via an explicit use of super, or because a given field
|
||||
@ -297,14 +301,43 @@ func makeUnboundSelfBinding() selfBinding {
|
||||
}
|
||||
}
|
||||
|
||||
// Hack - we need to distinguish not-checked-yet and no error situations
|
||||
// so we have a special value for no error and nil means that we don't know yet.
|
||||
var errNoErrorInObjectInvariants = errors.New("No error - assertions passed")
|
||||
|
||||
type valueObjectBase struct {
|
||||
valueBase
|
||||
assertionError error
|
||||
}
|
||||
|
||||
func (*valueObjectBase) typename() string {
|
||||
return "object"
|
||||
}
|
||||
|
||||
func (obj *valueObjectBase) assertionsChecked() bool {
|
||||
// nil - not checked yet
|
||||
// errNoErrorInObjectInvariants - we checked and there is no error (or checking in progress)
|
||||
return obj.assertionError != nil
|
||||
}
|
||||
|
||||
func (obj *valueObjectBase) setAssertionsCheckResult(err error) {
|
||||
if err != nil {
|
||||
obj.assertionError = err
|
||||
} else {
|
||||
obj.assertionError = errNoErrorInObjectInvariants
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *valueObjectBase) getAssertionsCheckResult() error {
|
||||
if obj.assertionError == nil {
|
||||
panic("Assertions not checked yet")
|
||||
}
|
||||
if obj.assertionError == errNoErrorInObjectInvariants {
|
||||
return nil
|
||||
}
|
||||
return obj.assertionError
|
||||
}
|
||||
|
||||
// valueSimpleObject represents a flat object (no inheritance).
|
||||
// Note that it can be used as part of extended objects
|
||||
// in inheritance using operator +.
|
||||
@ -317,7 +350,43 @@ type valueSimpleObject struct {
|
||||
valueObjectBase
|
||||
upValues bindingFrame
|
||||
fields valueSimpleObjectFieldMap
|
||||
asserts []ast.Node
|
||||
asserts []unboundField
|
||||
}
|
||||
|
||||
func checkAssertionsHelper(e *evaluator, obj valueObject, curr valueObject, superDepth int) error {
|
||||
switch curr := curr.(type) {
|
||||
case *valueExtendedObject:
|
||||
err := checkAssertionsHelper(e, obj, curr.right, superDepth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = checkAssertionsHelper(e, obj, curr.left, superDepth+curr.right.inheritanceSize())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
case *valueSimpleObject:
|
||||
for _, assert := range curr.asserts {
|
||||
_, err := e.evaluate(assert.bindToObject(selfBinding{self: obj, superDepth: superDepth}, curr.upValues))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown object type %#v", obj))
|
||||
}
|
||||
}
|
||||
|
||||
func checkAssertions(e *evaluator, obj valueObject) error {
|
||||
if !obj.assertionsChecked() {
|
||||
// Assertions may refer to the object that will normally
|
||||
// trigger checking of assertions, resulting in an endless recursion.
|
||||
// To avoid that, while we check them, we treat them as already passed.
|
||||
obj.setAssertionsCheckResult(errNoErrorInObjectInvariants)
|
||||
obj.setAssertionsCheckResult(checkAssertionsHelper(e, obj, obj, 0))
|
||||
}
|
||||
return obj.getAssertionsCheckResult()
|
||||
}
|
||||
|
||||
func (o *valueSimpleObject) index(e *evaluator, field string) (value, error) {
|
||||
@ -328,7 +397,7 @@ func (*valueSimpleObject) inheritanceSize() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func makeValueSimpleObject(b bindingFrame, fields valueSimpleObjectFieldMap, asserts ast.Nodes) *valueSimpleObject {
|
||||
func makeValueSimpleObject(b bindingFrame, fields valueSimpleObjectFieldMap, asserts []unboundField) *valueSimpleObject {
|
||||
return &valueSimpleObject{
|
||||
upValues: b,
|
||||
fields: fields,
|
||||
@ -425,6 +494,10 @@ func superIndex(e *evaluator, currentSB selfBinding, field string) (value, error
|
||||
}
|
||||
|
||||
func objectIndex(e *evaluator, sb selfBinding, fieldName string) (value, error) {
|
||||
err := checkAssertions(e, sb.self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
field, upValues, foundAt := findField(sb.self, sb.superDepth, fieldName)
|
||||
if field == nil {
|
||||
return nil, e.Error(fmt.Sprintf("Field does not exist: %s", fieldName))
|
||||
|
Loading…
Reference in New Issue
Block a user