| // Copyright (C) 2014 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 ( |
| "bytes" |
| |
| "android.googlesource.com/platform/tools/gpu/api/ast" |
| "android.googlesource.com/platform/tools/gpu/api/semantic" |
| ) |
| |
| type macroStub struct { |
| scope *scope |
| function *semantic.Function |
| } |
| |
| func (m *macroStub) ExpressionType() semantic.Type { return m.function.Signature } |
| |
| func functionSignature(ctx *context, out *semantic.Function) { |
| in := out.AST |
| args := make([]semantic.Type, 0, len(in.Parameters)-1) |
| out.Outputs = make([]*semantic.Parameter, 0, len(in.Parameters)) |
| out.FullParameters = make([]*semantic.Parameter, 0, len(in.Parameters)) |
| for i, inp := range in.Parameters { |
| outp := parameter(ctx, out, inp) |
| if inp.This { |
| if i == 0 { |
| out.This = outp |
| } else { |
| ctx.errorf(inp, "this only allowed on arg 0") |
| } |
| } |
| if i < len(in.Parameters)-1 { |
| if isVoid(outp.Type) { |
| ctx.errorf(in, "void typed parameter %s on function %s", outp.Name, out.Name) |
| } |
| if !inp.This { |
| args = append(args, outp.Type) |
| } |
| if inp.Output { |
| out.Outputs = append(out.Outputs, outp) |
| } |
| out.FullParameters = append(out.FullParameters, outp) |
| } else { |
| out.Return = outp |
| if !isVoid(outp.ExpressionType()) { |
| out.Return.Name = "result" |
| out.Outputs = append(out.Outputs, outp) |
| out.FullParameters = append(out.FullParameters, outp) |
| } |
| } |
| } |
| out.Signature = getSignature(ctx, in, out.Return.Type, args) |
| ctx.mappings[in] = out |
| } |
| |
| func parameter(ctx *context, owner *semantic.Function, in *ast.Parameter) *semantic.Parameter { |
| out := &semantic.Parameter{ |
| AST: in, |
| Input: in.Input, |
| Output: in.Output, |
| Function: owner, |
| } |
| if in.Name != nil { |
| out.Name = in.Name.Value |
| } |
| out.Docs = findDocumentation(in.CST) |
| out.Annotations = annotations(ctx, in.Annotations) |
| out.Type = type_(ctx, in.Type) |
| ctx.mappings[in] = out |
| return out |
| } |
| |
| func functionBody(ctx *context, owner semantic.Type, out *semantic.Function) { |
| in := out.AST |
| out.Owner = owner |
| if in.Block != nil { |
| ctx.with(semantic.VoidType, func() { |
| for _, p := range out.FullParameters { |
| ctx.add(p.Name, p) |
| } |
| if out.This != nil { |
| ctx.add(string(ast.KeywordThis), out.This) |
| } |
| out.Annotations = annotations(ctx, in.Annotations) |
| out.Block = block(ctx, in.Block, out) |
| addFence(ctx, out.Block) |
| }) |
| } |
| if len(out.Docs) == 0 { |
| out.Docs = findDocumentation(out.AST.CST) |
| } |
| ctx.mappings[in] = out |
| } |
| |
| func method(ctx *context, out *semantic.Function) { |
| functionSignature(ctx, out) |
| t := out.This.Type |
| switch t := t.(type) { |
| case *semantic.Pointer: |
| if class, ok := t.To.(*semantic.Class); !ok { |
| ctx.errorf(out.AST, "expected this as a reference to a class, got %s[%T]", typename(t.To), t.To) |
| } else { |
| class.Methods = append(class.Methods, out) |
| class.Members[out.Name] = out |
| functionBody(ctx, class, out) |
| } |
| case *semantic.Pseudonym: |
| t.Methods = append(t.Methods, out) |
| t.Members[out.Name] = out |
| functionBody(ctx, t, out) |
| case *semantic.Class: |
| t.Methods = append(t.Methods, out) |
| t.Members[out.Name] = out |
| functionBody(ctx, t, out) |
| default: |
| ctx.errorf(out.AST, "invalid type for this , got %s[%T]", typename(t), t) |
| } |
| ctx.mappings[out.AST] = out |
| } |
| |
| func getSignature(ctx *context, at ast.Node, r semantic.Type, args []semantic.Type) *semantic.Signature { |
| buffer := bytes.Buffer{} |
| buffer.WriteString("fun_") |
| buffer.WriteString(r.Typename()) |
| buffer.WriteString("_") |
| for _, a := range args { |
| buffer.WriteString("_") |
| buffer.WriteString(a.Typename()) |
| } |
| name := buffer.String() |
| for _, s := range ctx.api.Signatures { |
| if s.Name == name { |
| if !equal(r, s.Return) { |
| ctx.icef(at, "Signature %s found with non matching return type, got %s expected %s", name, typename(s.Return), typename(r)) |
| } |
| if len(args) != len(s.Arguments) { |
| ctx.icef(at, "Signature %s found with %d arguments, expected %s", name, len(s.Arguments), len(args)) |
| } |
| for i, a := range args { |
| if !equal(a, s.Arguments[i]) { |
| ctx.icef(at, "Signature %s found with non matching arg at %d, got %s expected %s", name, i, typename(s.Arguments[i]), typename(a)) |
| } |
| } |
| return s |
| } |
| } |
| out := &semantic.Signature{ |
| Name: name, |
| Return: r, |
| Arguments: args, |
| } |
| ctx.api.Signatures = append(ctx.api.Signatures, out) |
| return out |
| } |