blob: 4af016304e1fb7bf2b8b9795ed412de703f8677a [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package snippets
import (
"fmt"
"android.googlesource.com/platform/tools/gpu/framework/binary"
)
// pathway is way of finding a static component in a nested structure.
type Pathway interface {
binary.Object
isPath() // tag method
// root returns the root of this pathway
root() Pathway
// getBase returns the base of this pathway or nil if it is the root.
getBase() Pathway
}
// pathwayCast needed for generated code.
func PathwayCast(o binary.Object) Pathway {
return o.(Pathway)
}
// namepath is a path representing a symbol name in a particular category
// (local, global, param). A namePath can be the root of a path.
type namePath struct {
binary.Generate
cat SymbolCategory // category of this symbol (local, global, param)
name string // name of this symbol
}
func (*namePath) isPath() {}
func (n *namePath) root() Pathway {
return n
}
func (n *namePath) getBase() Pathway {
return nil
}
var _ Pathway = &namePath{}
// fieldPath is a path representing a field in an entity.
type fieldPath struct {
binary.Generate
base Pathway // Pathway to the entity.
name string // name of the field.
}
func (*fieldPath) isPath() {}
func (p *fieldPath) root() Pathway {
return p.base.root()
}
func (p *fieldPath) getBase() Pathway {
return p.base
}
var _ Pathway = &fieldPath{}
// partPath is a path representing a component of a container.
type partPath struct {
binary.Generate
base Pathway // Pathway to the container.
kind PartKind // kind of the component.
}
func (*partPath) isPath() {}
func (p *partPath) root() Pathway {
return p.base.root()
}
func (p *partPath) getBase() Pathway {
return p.base
}
var _ Pathway = &partPath{}
// relativePath is a path representing a symbol relative to a particular
// schema entity. A relativePath can be the root of a path.
type relativePath struct {
binary.Generate
// The name of the type as it is in the API file. The type of the global
// state object is synthetic at determined by the tag "globals" in the
// generated code.
typeName string
}
func (*relativePath) isPath() {}
func (n *relativePath) root() Pathway {
return n
}
func (n *relativePath) getBase() Pathway {
return nil
}
var _ Pathway = &relativePath{}
func (n *namePath) String() string {
return fmt.Sprintf("%s:%s", n.cat, n.name)
}
func (f *fieldPath) String() string {
return fmt.Sprintf("%s.%s", f.base, f.name)
}
func (f *partPath) String() string {
return fmt.Sprintf("%s.%s()", f.base, f.kind)
}
func (n *relativePath) String() string {
return fmt.Sprintf("%s:", n.typeName)
}
// MakeRelative return a copy of p with the root replaced
// by a relative root for typeName.
func MakeRelative(p Pathway, typeName string) Pathway {
switch p := p.(type) {
case *partPath:
return &partPath{base: MakeRelative(p.getBase(), typeName), kind: p.kind}
case *fieldPath:
return Field(MakeRelative(p.getBase(), typeName), p.name)
case *namePath:
return Field(Relative(typeName), p.name)
case *relativePath:
return Relative(typeName)
default:
panic(fmt.Errorf("Unexpected Pathway type %T in MakeRelative(%v, %s)", p, p, typeName))
}
}
// Make a relative pathway for the API type named typeName
func Relative(typeName string) Pathway {
return &relativePath{typeName: typeName}
}
// Variable returns a Pathway for a symbol named name in category cat.
func Variable(cat SymbolCategory, name string) Pathway {
return &namePath{cat: cat, name: name}
}
// Elem returns a Pathway to the element of a collection.
func Elem(p Pathway) Pathway {
return &partPath{base: p, kind: PartKind_Elem}
}
// Key returns a Pathway to the element of a collection.
func Key(p Pathway) Pathway {
return &partPath{base: p, kind: PartKind_Key}
}
// Field returns a Pathway to a field of an entity.
func Field(p Pathway, name string) Pathway {
return &fieldPath{base: p, name: name}
}
// Range returns a Pathway to a range of a slice or pointer.
func Range(p Pathway) Pathway {
return &partPath{base: p, kind: PartKind_Range}
}
func Equal(left, right Pathway) bool {
switch l := left.(type) {
case *namePath:
r, ok := right.(*namePath)
return ok && *l == *r
case *fieldPath:
r, ok := right.(*fieldPath)
return ok && l.name == r.name && Equal(l.base, r.base)
case *partPath:
r, ok := right.(*partPath)
return ok && l.kind == r.kind && Equal(l.base, r.base)
case *relativePath:
r, ok := right.(*relativePath)
return ok && l.typeName == r.typeName
}
return false
}
func IsGlobal(p Pathway) bool {
switch root := p.root().(type) {
case *namePath:
return root.cat == SymbolCategory_Global
case *relativePath:
panic(fmt.Errorf("Relative path %v used with IsGlobal", p))
default:
panic(fmt.Errorf("Unexpected Pathway root type %T in IsGlobal(%v)", p, p))
}
}