blob: 1fbb6f6f4fc5b24d5cc1e290eee6222ba4415bc8 [file] [log] [blame]
// 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 (
"strconv"
"strings"
"android.googlesource.com/platform/tools/gpu/api/ast"
"android.googlesource.com/platform/tools/gpu/api/semantic"
)
func type_(ctx *context, in interface{}) semantic.Type {
switch in := in.(type) {
case *ast.Identifier:
return simpleType(ctx, in)
case *ast.MapType:
return mapType(ctx, in)
case *ast.ArrayType:
return arrayType(ctx, in)
case *ast.StaticArrayType:
return staticArrayType(ctx, in)
case *ast.PointerType:
return pointerType(ctx, in)
default:
ctx.errorf(in, "Unhandled typeref %T found", in)
return semantic.VoidType
}
}
func simpleType(ctx *context, in *ast.Identifier) semantic.Type {
name := in.Value
out := ctx.findType(in, name)
if out == nil {
ctx.errorf(in, "Type %s not found", name)
return semantic.VoidType
}
if a, ok := out.(*alias); ok {
if a.To == nil {
a.To = type_(ctx, a.AST.To)
}
return a.To
}
return out
}
func mapType(ctx *context, in *ast.MapType) *semantic.Map {
kt := type_(ctx, in.KeyType)
vt := type_(ctx, in.ValueType)
name := strings.Title(vt.Typename()) + "_" + kt.Typename() + "Map"
for _, m := range ctx.api.Maps {
if m.Name == name {
if !equal(kt, m.KeyType) {
ctx.icef(in, "Map %s found with non matching key, got %s expected %s", name, typename(m.KeyType), typename(kt))
}
if !equal(vt, m.ValueType) {
ctx.icef(in, "Map %s found with non matching value, got %s expected %s", name, typename(m.ValueType), typename(vt))
}
return m
}
}
out := &semantic.Map{
Name: name,
KeyType: kt,
ValueType: vt,
Members: semantic.Members{},
}
for _, f := range []*semantic.Function{
&semantic.Function{Name: "Get",
FullParameters: []*semantic.Parameter{{},
{Name: "key", Type: kt},
{Name: "value", Type: vt},
{Type: vt},
},
},
&semantic.Function{Name: "Delete",
FullParameters: []*semantic.Parameter{{},
{Name: "key", Type: kt},
},
},
&semantic.Function{Name: "Range",
FullParameters: []*semantic.Parameter{{},
{Type: semantic.AnyType},
},
},
} {
f.Owner = out
f.This = f.FullParameters[0]
f.This.Name = "self"
f.This.Type = out
last := f.FullParameters[len(f.FullParameters)-1]
if last.Name == "" {
f.Return = f.FullParameters[len(f.FullParameters)-1]
f.Return.Output = true
f.Outputs = append(f.Outputs, f.Return)
} else {
f.Return = &semantic.Parameter{Type: semantic.VoidType}
}
out.Members[f.Name] = f
}
ctx.api.Maps = append(ctx.api.Maps, out)
return out
}
func arrayType(ctx *context, in *ast.ArrayType) *semantic.Array {
vt := type_(ctx, in.ValueType)
name := strings.Title(vt.Typename()) + "Array"
for _, a := range ctx.api.Arrays {
if a.Name == name {
if !equal(vt, a.ValueType) {
ctx.icef(in, "Array %s found with non matching value, got %s expected %s", name, typename(a.ValueType), typename(vt))
}
return a
}
}
out := &semantic.Array{
Name: name,
ValueType: vt,
}
ctx.api.Arrays = append(ctx.api.Arrays, out)
return out
}
func staticArrayType(ctx *context, in *ast.StaticArrayType) *semantic.StaticArray {
vt := type_(ctx, in.ValueType)
name := strings.Title(vt.Typename()) + "StaticArray"
for _, a := range ctx.api.StaticArrays {
if a.Name == name {
if !equal(vt, a.ValueType) {
ctx.icef(in, "Static array %s found with non matching value, got %s expected %s", name, typename(a.ValueType), typename(vt))
}
return a
}
}
out := &semantic.StaticArray{
Name: name,
ValueType: vt,
}
ctx.with(semantic.Uint32Type, func() {
for _, d := range in.Dimensions {
e := expression(ctx, d)
if n, ok := e.(semantic.Uint32Value); ok {
out.Dimensions = append(out.Dimensions, n)
} else {
ctx.errorf(in, "Array dimension must be a constant number, got %T", e)
}
}
})
ctx.api.StaticArrays = append(ctx.api.StaticArrays, out)
return out
}
func getPointerType(ctx *context, at interface{}, to semantic.Type) *semantic.Pointer {
name := strings.Title(to.Typename()) + "Ref"
for _, p := range ctx.api.Pointers {
if p.Name == name {
if !equal(to, p.To) {
ctx.icef(at, "Pointer %s found with non matching value, got %s expected %s", name, typename(p.To), typename(to))
}
return p
}
}
out := &semantic.Pointer{
Name: name,
To: to,
}
ctx.api.Pointers = append(ctx.api.Pointers, out)
return out
}
func pointerType(ctx *context, in *ast.PointerType) *semantic.Pointer {
vt := type_(ctx, in.To)
return getPointerType(ctx, in, vt)
}
func enum(ctx *context, out *semantic.Enum) {
if len(out.AllEntries) > 0 {
// Already resolved.
return
}
in := out.AST
out.Annotations = annotations(ctx, in.Annotations)
out.IsBitfield = in.IsBitfield
for _, e := range in.Entries {
v, err := strconv.ParseUint(e.Value.Value, 0, 32)
if err != nil {
ctx.errorf(e, "could not parse %s as uint32", e.Value)
continue
}
entry := &semantic.EnumEntry{
AST: e,
Enum: out,
Name: e.Name.Value,
Value: uint32(v),
}
out.Entries = append(out.Entries, entry)
out.AllEntries = append(out.AllEntries, entry)
}
for _, extends := range in.Extends {
t := ctx.findType(extends, extends.Value)
if e, ok := t.(*semantic.Enum); !ok {
ctx.errorf(extends, "non enum entry %s in extension list", typename(t))
} else {
out.Extends = append(out.Extends, e)
enum(ctx, e)
for _, entry := range e.AllEntries {
copy := *entry
copy.Enum = out
out.AllEntries = append(out.AllEntries, &copy)
}
}
}
for _, entry := range out.AllEntries {
ctx.add(entry.Name, entry)
}
}
func class(ctx *context, out *semantic.Class) {
in := out.AST
out.Annotations = annotations(ctx, in.Annotations)
for _, extends := range in.Extends {
t := ctx.findType(extends, extends.Value)
if c, ok := t.(*semantic.Class); !ok {
ctx.errorf(extends, "non class entry %s in extension list", typename(t))
} else {
out.Extends = append(out.Extends, c)
c.ExtendedBy = append(c.ExtendedBy, out)
}
}
out.Fields = make([]*semantic.Field, len(in.Fields))
for i, f := range in.Fields {
field := field(ctx, f, out)
out.Fields[i] = field
out.Members[field.Name] = field
}
}
func field(ctx *context, in *ast.Field, class *semantic.Class) *semantic.Field {
out := &semantic.Field{AST: in, Name: in.Name.Value, Class: class}
out.Annotations = annotations(ctx, in.Annotations)
out.Type = type_(ctx, in.Type)
if in.Default != nil {
ctx.with(out.Type, func() {
out.Default = expression(ctx, in.Default)
})
dt := out.Default.ExpressionType()
if !assignable(out.Type, dt) {
ctx.errorf(in, "cannot assign %s to %s", typename(dt), typename(out.Type))
}
}
return out
}
func pseudonym(ctx *context, out *semantic.Pseudonym) {
in := out.AST
out.Annotations = annotations(ctx, in.Annotations)
out.To = type_(ctx, in.To)
}
func typename(e semantic.Type) string {
if e == nil {
return "missing"
} else {
return e.Typename()
}
}