blob: 82f73a8c01763d57db842c35061b3f031a1c6b88 [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 resolver
import (
"fmt"
"reflect"
"strings"
"android.googlesource.com/platform/tools/gpu/api/ast"
"android.googlesource.com/platform/tools/gpu/api/semantic"
"android.googlesource.com/platform/tools/gpu/framework/parse"
)
type resolver struct {
errors parse.ErrorList
api *semantic.API
scope *scope // The current scope
globals *scope // The global scope
nextID uint64
mappings *Mappings
labels map[string][]*semantic.Label
genericSubroutines map[string]genericSubroutine
aliasStack stack // Currently resolving aliases.
defStack stack // Currently resolving definitions.
}
type scope struct {
semantic.Symbols
types map[string]semantic.Type
outer *scope
inferType semantic.Type
block *semantic.Statements
function *semantic.Function
nextID uint64
}
type named interface {
Name() string
}
func name(n interface{}) string {
switch n := n.(type) {
case semantic.Type:
return typename(n)
case named:
return n.Name()
case *ast.Label:
return n.Name.Value
default:
return fmt.Sprintf("%v %T", n, n)
}
}
// stack is a stack of objects.
// It is used to detect circular references in type and define declarations.
type stack []interface{}
func (s stack) String() string {
path := make([]string, len(s))
for i, o := range s {
path[i] = name(o)
}
return strings.Join(path, " -> ")
}
func (s *stack) push(o interface{}) {
*s = append(*s, o)
}
func (s *stack) pop() {
*s = (*s)[:len(*s)-1]
}
func (s stack) contains(o interface{}) bool {
for _, t := range s {
if t == o {
return true
}
}
return false
}
func (rv *resolver) errorf(at interface{}, message string, args ...interface{}) {
if at != nil {
n, ok := at.(ast.Node)
if !ok {
v := reflect.ValueOf(at)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() == reflect.Struct {
if a := v.FieldByName("AST"); a.IsValid() {
n, ok = a.Interface().(ast.Node)
}
}
}
if ok && n != nil && !reflect.ValueOf(n).IsNil() {
rv.errors.Add(nil, rv.mappings.CST(n), message, args...)
return
}
}
rv.errors.Add(nil, nil, message, args...)
}
func (rv *resolver) icef(at interface{}, message string, args ...interface{}) {
rv.errorf(at, "INTERNAL ERROR: "+message, args...)
}
// with evaluates the action within a new nested scope.
// The scope is available as rv.scope, and the original scope is
// restored before this function returns.
// Type t is used for type inference within the new scope (for
// instance when resolving untyped numeric constants)
func (rv *resolver) with(t semantic.Type, action func()) {
original := rv.scope
rv.scope = &scope{
types: map[string]semantic.Type{},
outer: rv.scope,
block: rv.scope.block,
function: rv.scope.function,
inferType: t,
}
defer func() { rv.scope = original }()
action()
}
// addNamed binds a named node within the current and nested scopes.
func (rv *resolver) addNamed(value semantic.NamedNode) {
rv.scope.AddNamed(value)
}
// alias maps a name to a node without the node knowing the name.
func (rv *resolver) add(name string, value semantic.Node) {
rv.scope.Add(name, value)
}
// addMembers adds all the members of owner directly to the curent scope.
func (rv *resolver) addMembers(owner semantic.Owner) {
owner.VisitMembers(func(m semantic.Owned) {
rv.scope.AddNamed(m)
})
}
// addSymbols adds all the entries of symbols directly to the curent scope.
func (rv *resolver) addSymbols(symbols *semantic.Symbols) {
symbols.Visit(func(name string, node semantic.Node) {
rv.scope.Add(name, node)
})
}
func (rv *resolver) ensureResolved(n semantic.Node) {
if g, ok := n.(*semantic.Global); ok {
// Globals can refer to other globals in their default initializer.
// This means some globals may need to be resolved out of order.
// Ensure that this global is resolved before returning.
global(rv, g)
}
}
// find searches the scope stack for a bindings that matches the name.
func (rv *resolver) find(name string) []interface{} {
result := []interface{}{}
for search := rv.scope; search != nil; search = search.outer {
list := search.FindAll(name)
for _, n := range list {
rv.ensureResolved(n)
result = append(result, n)
}
}
if gs, ok := rv.genericSubroutines[name]; ok {
result = append(result, gs)
}
return result
}
// disambiguate takes a list of possible scope values and attempts to see if
// one of them is unambiguously the right choice in the current context.
// For instance, if the values are all enum entries but only one of them
// matches the current enum inference.
func (rv *resolver) disambiguate(matches []interface{}) []interface{} {
if len(matches) <= 1 {
return matches
}
var enum semantic.Owner
for test := rv.scope; test != nil; test = test.outer {
if test.inferType != nil {
if e, ok := test.inferType.(*semantic.Enum); ok {
enum = e
break
}
}
}
if enum == nil {
// No disambiguating enums present
return matches
}
var res *semantic.EnumEntry
for _, m := range matches {
if ev, ok := m.(*semantic.EnumEntry); ok {
if enum == ev.Owner() {
// We found a disambiguation match
res = ev
}
} else {
// Non enum match found
return matches
}
}
if res == nil {
return matches
}
// Matched exactly once
return []interface{}{res}
}
// get searches the scope stack for a bindings that matches the name.
// If it cannot find exactly 1 unambiguous match, it reports an error, and
// nil is returned.
func (rv *resolver) get(at ast.Node, name string) interface{} {
if name == "_" {
return &semantic.Ignore{AST: at}
}
matches := rv.disambiguate(rv.find(name))
switch len(matches) {
case 0:
rv.errorf(at, "Unknown identifier %s", name)
return nil
case 1:
return matches[0]
default:
rv.ambiguousIdentifier(at, matches)
return nil
}
}
func (rv *resolver) ambiguousIdentifier(at ast.Node, matches []interface{}) {
possibilities := ""
for i, m := range matches {
if i > 0 {
possibilities += ", "
}
switch t := m.(type) {
case *semantic.EnumEntry:
possibilities += fmt.Sprintf("%s.%s", t.Owner().Name(), t.Name())
case *semantic.Parameter:
possibilities += fmt.Sprintf("parameter %q", t.Name())
case semantic.Type:
possibilities += fmt.Sprintf("type %q [%T]", typename(t), t)
default:
possibilities += fmt.Sprintf("[%T]%v", t, t)
}
}
rv.errorf(at, "Ambiguous identifier %q [using %s].\n Could be: %s", name(at), typename(rv.scope.inferType), possibilities)
}
func (rv *resolver) addType(t semantic.Type) {
name := t.Name()
withLocation := func(ty semantic.Type) string {
astBacked, ok := ty.(semantic.ASTBacked)
if ok {
tok := rv.mappings.CST(astBacked.ASTNode()).Token()
line, col := tok.Cursor()
return fmt.Sprintf("%s at %s:%d:%d", ty.Name(), tok.Source.Filename, line, col)
} else {
return ty.Name()
}
}
if prev, present := rv.scope.types[name]; present {
rv.errorf(t, "Duplicate type %s (already seen: %s)", t.Name(), withLocation(prev))
}
rv.scope.types[name] = t
}
func (rv *resolver) addGenericParameter(name string, t semantic.Type) {
if _, present := rv.scope.types[name]; present {
rv.errorf(t, "Duplicate type %s", name)
}
rv.scope.types[name] = t
}
func (rv *resolver) findType(at ast.Node, name string) semantic.Type {
for search := rv.scope; search != nil; search = search.outer {
if t, found := search.types[name]; found {
return t
}
}
return nil
}
func (rv *resolver) addStatement(s semantic.Statement) {
if !isInvalid(s) {
*rv.scope.block = append(*rv.scope.block, s)
}
}
func (rv *resolver) uid() uint64 {
id := rv.nextID
rv.nextID++
return id
}
func (rv *resolver) declareTemporaryLocal(value semantic.Expression) *semantic.DeclareLocal {
name := fmt.Sprintf("_res_%v", rv.scope.uid())
decl := &semantic.DeclareLocal{}
decl.Local = &semantic.Local{
Declaration: decl,
Type: value.ExpressionType(),
Named: semantic.Named(name),
Value: value,
}
return decl
}
func (s *scope) uid() uint64 {
id := s.nextID
s.nextID++
return id
}