blob: 773dd2292a53dfd590ac052d155374819f84cb28 [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 analysis
import (
"android.googlesource.com/platform/tools/gpu/api/ast"
"android.googlesource.com/platform/tools/gpu/api/resolver"
"android.googlesource.com/platform/tools/gpu/api/semantic"
)
// scope contains the full context information for analysis of a semantic node.
type scope struct {
parent *scope
shared *shared
callstack Callstack
locals map[*semantic.Local]Value
parameters map[*semantic.Parameter]Value
globals map[*semantic.Global]Value
instances map[*semantic.Create]Value
abort *semantic.Abort
returnVal Value
}
// shared is the common data shared between all scopes.
type shared struct {
mappings *resolver.Mappings
literals map[semantic.Expression]Value
unknowns map[semantic.Type]Value
defaults map[semantic.Type]Value
reached map[ast.Node]struct{}
}
// push returns a new child scope with a copy of the s's values.
// pop merges the child scope global and instance values back into s.
func (s *scope) push() (child *scope, pop func()) {
c := scope{
parent: s,
shared: s.shared,
callstack: s.callstack,
locals: make(map[*semantic.Local]Value, len(s.locals)),
parameters: make(map[*semantic.Parameter]Value, len(s.parameters)),
globals: make(map[*semantic.Global]Value, len(s.globals)),
instances: make(map[*semantic.Create]Value, len(s.instances)),
}
return &c, func() {
// Merge global and instance values back together from child branch
for g, v := range c.globals {
s.globals[g] = unionOf(s.getGlobal(g), v)
}
for i, v := range c.instances {
s.instances[i] = unionOf(s.getInstance(i), v)
}
}
}
func (s *scope) getLocal(n *semantic.Local) Value {
if v, ok := s.locals[n]; ok || s.parent == nil {
return v
}
return s.parent.getLocal(n)
}
func (s *scope) getParameter(n *semantic.Parameter) Value {
if v, ok := s.parameters[n]; ok || s.parent == nil {
return v
}
return s.parent.getParameter(n)
}
func (s *scope) getGlobal(n *semantic.Global) Value {
if v, ok := s.globals[n]; ok || s.parent == nil {
return v
}
return s.parent.getGlobal(n)
}
func (s *scope) getInstance(n *semantic.Create) Value {
if v, ok := s.instances[n]; ok || s.parent == nil {
return v
}
return s.parent.getInstance(n)
}
// setUnion sets all the values in s to be a union of those in a and b.
// setUnion is used to merge the results of two child scopes.
func (s *scope) setUnion(a, b *scope) {
locals := map[*semantic.Local]struct{}{}
for n := range a.locals {
locals[n] = struct{}{}
}
for n := range b.locals {
locals[n] = struct{}{}
}
for n := range locals {
s.locals[n] = unionOf(a.getLocal(n), b.getLocal(n))
}
parameters := map[*semantic.Parameter]struct{}{}
for n := range a.parameters {
parameters[n] = struct{}{}
}
for n := range b.parameters {
parameters[n] = struct{}{}
}
for n := range parameters {
s.parameters[n] = unionOf(a.getParameter(n), b.getParameter(n))
}
globals := map[*semantic.Global]struct{}{}
for n := range a.globals {
globals[n] = struct{}{}
}
for n := range b.globals {
globals[n] = struct{}{}
}
for n := range globals {
s.globals[n] = unionOf(a.getGlobal(n), b.getGlobal(n))
}
instances := map[*semantic.Create]struct{}{}
for n := range a.instances {
instances[n] = struct{}{}
}
for n := range b.instances {
instances[n] = struct{}{}
}
for n := range instances {
s.instances[n] = unionOf(a.getInstance(n), b.getInstance(n))
}
}
// setCurrentNode marks the node n as reached and changes the scope's callstack
// to point to n.
func (s *scope) setCurrentNode(n semantic.Node) {
for _, n := range s.shared.mappings.SemanticToAST[n] {
s.shared.reached[n] = struct{}{}
}
if pn := s.shared.mappings.ParseNode(n); pn != nil {
s.callstack.set(pn)
}
}