blob: f8959278e37b532eb46c397ae1f14e0fbcba786b [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 annotate
import (
"bytes"
"fmt"
"android.googlesource.com/platform/tools/gpu/api/semantic"
"android.googlesource.com/platform/tools/gpu/api/snippets"
)
func category(expr semantic.Expression) snippets.SymbolCategory {
switch expr.(type) {
case *semantic.Global:
return snippets.SymbolCategory_Global
case *semantic.Local:
return snippets.SymbolCategory_Local
case *semantic.Parameter:
return snippets.SymbolCategory_Parameter
}
panic(fmt.Errorf("No symbol category for %T:%v", expr, expr))
}
// SymbolTable is a basic mapping between names and values
type SymbolTable map[string]*Location
func (s SymbolTable) String() string {
buf := &bytes.Buffer{}
first := true
for k, v := range s {
if v.leader().isEmpty() {
continue
}
if !first {
buf.WriteString(", ")
} else {
first = false
}
buf.WriteString(k)
buf.WriteString(": ")
buf.WriteString(fmt.Sprintf("%s", v))
}
return buf.String()
}
// ScopedSymbolTable is a symbol table with scopes which allow shadowing.
type ScopedSymbolTable []SymbolTable
// enter starts a new scope
func (t *ScopedSymbolTable) enter() {
(*t) = append(*t, make(SymbolTable))
}
// leave ends the current scope. It will panic if there is no current scope.
func (t *ScopedSymbolTable) leave() {
l := len(*t)
if l == 0 {
panic(fmt.Errorf("Scope imbalance, leave() called more times than enter()"))
}
(*t) = (*t)[:l-1]
}
// lookup finds a mapping for name in the outermost scope and return the
// leader of the equivalence set it is in. If name is not in the name
// space it will panic.
func (t *ScopedSymbolTable) lookup(name string) *Location {
for i := len(*t) - 1; i >= 0; i-- {
s := (*t)[i]
if loc, ok := s[name]; ok {
return loc.leader()
}
}
panic(fmt.Errorf("Failed to locate %s", name))
}
// declares a new name in the symbol table. It will panic if the name is
// already in use. The location for the new declaration is returned.
func (t *ScopedSymbolTable) declare(name string) *Location {
location := &Location{}
t.add(name, location)
return location
}
// add inserts new name in the symbol table. It will panic if the name is
// already in use.
func (t *ScopedSymbolTable) add(name string, location *Location) {
l := len(*t)
if l == 0 {
panic(fmt.Errorf("Declare called without any scope: %s", name))
}
s := (*t)[l-1]
if _, found := s[name]; found {
panic(fmt.Errorf("Attempt to redeclare %s", name))
}
s[name] = location
}
// SymbolSpace is a ScopedSymbolTable for each SymbolCategory.
type SymbolSpace map[snippets.SymbolCategory]*ScopedSymbolTable
func MakeSymbolSpace() SymbolSpace {
space := make(SymbolSpace)
for _, cat := range []snippets.SymbolCategory{
snippets.SymbolCategory_Global, snippets.SymbolCategory_Local, snippets.SymbolCategory_Parameter} {
space[cat] = &ScopedSymbolTable{}
}
return space
}
// enter starts a new scope
func (s SymbolSpace) enter() {
for _, t := range s {
t.enter()
}
}
// leave ends the current scope. It will panic if there is no current scope.
func (s SymbolSpace) leave() {
for _, t := range s {
t.leave()
}
}
func (s SymbolSpace) String() string {
buf := &bytes.Buffer{}
first := true
for k, v := range s {
if !first {
buf.WriteString(", ")
} else {
first = false
}
buf.WriteString(fmt.Sprintf("%s{%s}", k, *v))
}
return buf.String()
}