Upstream itchyny/gojq state of the touched files before a0fd150fb8
This commit is contained in:
1 parent
af32cf4c58
commit
33d02f2fdb
4 files changed
+82
-899
No files matched your search
-204
@@ -1,204 +0,0 @@
|
||||
package gojq
|
||||
|
||||
// Static analysis deciding whether the accumulated value of a reduce
|
||||
// expression may be updated in place; see compiler#compileReduce. The checks
|
||||
// are conservative: failing them only keeps the previous copying behavior.
|
||||
|
||||
// inPlaceUpdate reports whether the query is a single assignment applied to
|
||||
// the input value, and returns its operands.
|
||||
func (e *Query) inPlaceUpdate() (l, r *Query, op Operator, ok bool) {
|
||||
if e.Term != nil || len(e.FuncDefs) > 0 {
|
||||
return nil, nil, 0, false
|
||||
}
|
||||
switch e.Op {
|
||||
case OpModify:
|
||||
// _modify releases the allocator before calling the update function.
|
||||
return e.Left, e.Right, e.Op, true
|
||||
case OpAssign:
|
||||
// A constant path compiles to setpath, which uses no allocator.
|
||||
if e.Left.toIndices(nil) != nil {
|
||||
return nil, nil, 0, false
|
||||
}
|
||||
fallthrough
|
||||
case OpUpdateAdd, OpUpdateSub, OpUpdateMul,
|
||||
OpUpdateDiv, OpUpdateMod, OpUpdateAlt:
|
||||
// The right-hand side must neither observe the input value, which it
|
||||
// could otherwise alias, nor yield multiple values, which would run
|
||||
// the assignment against an already modified input.
|
||||
if !e.Right.readsInput() && e.Right.singleValued() {
|
||||
return e.Left, e.Right, e.Op, true
|
||||
}
|
||||
}
|
||||
return nil, nil, 0, false
|
||||
}
|
||||
|
||||
// readsInput reports whether evaluating the query may observe its input value.
|
||||
// It answers true unless it can prove otherwise.
|
||||
func (e *Query) readsInput() bool {
|
||||
if len(e.FuncDefs) > 0 {
|
||||
return true
|
||||
}
|
||||
if e.Term != nil {
|
||||
return e.Term.readsInput()
|
||||
}
|
||||
switch e.Op {
|
||||
case OpPipe:
|
||||
// Binding variables also exposes the input to the right-hand side.
|
||||
if len(e.Patterns) > 0 {
|
||||
return e.Left.readsInput() || e.Right.readsInput()
|
||||
}
|
||||
return e.Left.readsInput()
|
||||
case OpComma, OpAdd, OpSub, OpMul, OpDiv, OpMod, OpEq, OpNe,
|
||||
OpGt, OpLt, OpGe, OpLe, OpAnd, OpOr, OpAlt:
|
||||
return e.Left.readsInput() || e.Right.readsInput()
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// singleValued reports whether the query yields at most one value.
|
||||
// It answers false unless it can prove otherwise.
|
||||
func (e *Query) singleValued() bool {
|
||||
if len(e.FuncDefs) > 0 {
|
||||
return false
|
||||
}
|
||||
if e.Term != nil {
|
||||
return e.Term.singleValued()
|
||||
}
|
||||
switch e.Op {
|
||||
case OpPipe:
|
||||
return len(e.Patterns) == 0 &&
|
||||
e.Left.singleValued() && e.Right.singleValued()
|
||||
case OpAdd, OpSub, OpMul, OpDiv, OpMod, OpEq, OpNe,
|
||||
OpGt, OpLt, OpGe, OpLe, OpAnd, OpOr:
|
||||
return e.Left.singleValued() && e.Right.singleValued()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Term) readsInput() bool {
|
||||
for _, s := range e.SuffixList {
|
||||
if s.readsInput() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
switch e.Type {
|
||||
case TermTypeNull, TermTypeTrue, TermTypeFalse, TermTypeNumber:
|
||||
return false
|
||||
case TermTypeString:
|
||||
return e.Str.readsInput()
|
||||
case TermTypeObject:
|
||||
for _, kv := range e.Object.KeyVals {
|
||||
if kv.readsInput() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case TermTypeArray:
|
||||
return e.Array.Query != nil && e.Array.Query.readsInput()
|
||||
case TermTypeUnary:
|
||||
return e.Unary.Term.readsInput()
|
||||
case TermTypeFunc:
|
||||
// Any function may be redefined, so only $x is known not to read it.
|
||||
return e.Func.Name[0] != '$' || len(e.Func.Args) > 0
|
||||
case TermTypeQuery:
|
||||
return e.Query.readsInput()
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Term) singleValued() bool {
|
||||
for _, s := range e.SuffixList {
|
||||
if !s.singleValued() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
switch e.Type {
|
||||
case TermTypeNull, TermTypeTrue, TermTypeFalse, TermTypeNumber:
|
||||
return true
|
||||
case TermTypeString:
|
||||
return e.Str.singleValued()
|
||||
case TermTypeObject:
|
||||
for _, kv := range e.Object.KeyVals {
|
||||
if !kv.singleValued() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case TermTypeArray:
|
||||
return true
|
||||
case TermTypeUnary:
|
||||
return e.Unary.Term.singleValued()
|
||||
case TermTypeFunc:
|
||||
return e.Func.Name[0] == '$' && len(e.Func.Args) == 0
|
||||
case TermTypeQuery:
|
||||
return e.Query.singleValued()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Suffix) readsInput() bool {
|
||||
// Only an index is evaluated against the input value.
|
||||
return e.Index != nil && e.Index.readsInput()
|
||||
}
|
||||
|
||||
func (e *Suffix) singleValued() bool {
|
||||
return !e.Iter && (e.Index == nil || e.Index.singleValued())
|
||||
}
|
||||
|
||||
func (e *Index) readsInput() bool {
|
||||
if e.Str != nil {
|
||||
return e.Str.readsInput()
|
||||
}
|
||||
return e.Start != nil && e.Start.readsInput() ||
|
||||
e.End != nil && e.End.readsInput()
|
||||
}
|
||||
|
||||
func (e *Index) singleValued() bool {
|
||||
if e.Str != nil {
|
||||
return e.Str.singleValued()
|
||||
}
|
||||
return (e.Start == nil || e.Start.singleValued()) &&
|
||||
(e.End == nil || e.End.singleValued())
|
||||
}
|
||||
|
||||
func (e *String) readsInput() bool {
|
||||
for _, q := range e.Queries {
|
||||
if q.readsInput() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *String) singleValued() bool {
|
||||
for _, q := range e.Queries {
|
||||
if !q.singleValued() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *ObjectKeyVal) readsInput() bool {
|
||||
if e.Val == nil {
|
||||
// {foo} reads the input value, {$foo} does not.
|
||||
return e.Key == "" || e.Key[0] != '$'
|
||||
}
|
||||
if e.KeyString != nil && e.KeyString.readsInput() ||
|
||||
e.KeyQuery != nil && e.KeyQuery.readsInput() {
|
||||
return true
|
||||
}
|
||||
return e.Val.readsInput()
|
||||
}
|
||||
|
||||
func (e *ObjectKeyVal) singleValued() bool {
|
||||
if e.KeyString != nil && !e.KeyString.singleValued() ||
|
||||
e.KeyQuery != nil && !e.KeyQuery.singleValued() {
|
||||
return false
|
||||
}
|
||||
return e.Val == nil || e.Val.singleValued()
|
||||
}
|
||||
Reference in new issue
Block a user