| // 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) |
| } |
| } |