| // Copyright (C) 2015 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 template |
| |
| import ( |
| "errors" |
| "fmt" |
| "unicode" |
| |
| "reflect" |
| |
| "strings" |
| |
| "android.googlesource.com/platform/tools/gpu/api/semantic" |
| ) |
| |
| var ( |
| // NodeTypeList exposes all the types valid as Is*name* tests |
| NodeTypeList = []interface{}{ |
| // Primitive types |
| "", // string |
| false, // bool |
| // primitive value node types |
| semantic.BoolValue(true), |
| semantic.Int32Value(0), |
| semantic.Uint32Value(0), |
| semantic.Int64Value(0), |
| semantic.Uint64Value(0), |
| semantic.StringValue(""), |
| semantic.Float32Value(1.0), |
| semantic.Float64Value(1.0), |
| // semantic node types |
| semantic.API{}, |
| semantic.Assert{}, |
| semantic.Assign{}, |
| semantic.BinaryOp{}, |
| semantic.BitTest{}, |
| semantic.Branch{}, |
| semantic.Builtin{}, |
| semantic.Call{}, |
| semantic.Cast{}, |
| semantic.Choice{}, |
| semantic.ClassInitializer{}, |
| semantic.Class{}, |
| semantic.Clone{}, |
| semantic.Copy{}, |
| semantic.Create{}, |
| semantic.DeclareLocal{}, |
| semantic.EnumEntry{}, |
| semantic.Enum{}, |
| semantic.Fence{}, |
| semantic.Field{}, |
| semantic.Function{}, |
| semantic.Global{}, |
| semantic.Iteration{}, |
| semantic.Length{}, |
| semantic.Local{}, |
| semantic.Make{}, |
| semantic.MapAssign{}, |
| semantic.MapContains{}, |
| semantic.MapIndex{}, |
| semantic.Map{}, |
| semantic.Member{}, |
| semantic.New{}, |
| semantic.Null{}, |
| semantic.Observed{}, |
| semantic.Parameter{}, |
| semantic.PointerRange{}, |
| semantic.Pointer{}, |
| semantic.Pseudonym{}, |
| semantic.Read{}, |
| semantic.Reference{}, |
| semantic.Return{}, |
| semantic.Select{}, |
| semantic.SliceAssign{}, |
| semantic.SliceIndex{}, |
| semantic.SliceRange{}, |
| semantic.Slice{}, |
| semantic.Slice{}, |
| semantic.StaticArray{}, |
| semantic.Switch{}, |
| semantic.UnaryOp{}, |
| semantic.Unknown{}, |
| semantic.Write{}, |
| // node interface types |
| (*semantic.Annotated)(nil), |
| (*semantic.Expression)(nil), |
| (*semantic.Type)(nil), |
| } |
| |
| nodeTypes = map[string]reflect.Type{} |
| ) |
| |
| func init() { |
| for _, n := range NodeTypeList { |
| nt := baseType(n) |
| name := nt.Name() |
| nodeTypes[name] = nt |
| } |
| } |
| |
| func initNodeTypes(f *Functions) { |
| for _, b := range semantic.BuiltinTypes { |
| b := b |
| name := "Is" + strings.Title(b.Name) |
| f.funcs[name] = func(t semantic.Type) bool { |
| return t == b |
| } |
| } |
| for name, t := range nodeTypes { |
| for _, r := range name { |
| if unicode.IsUpper(r) { |
| f.funcs["Is"+name] = isTypeTest(t) |
| } |
| break |
| } |
| } |
| } |
| |
| // Returns the resolved semantic type of an expression node. |
| func (*Functions) TypeOf(v interface{}) (semantic.Type, error) { |
| if v == nil { |
| return semantic.VoidType, nil |
| } |
| switch e := v.(type) { |
| case semantic.Type: |
| return e, nil |
| case *semantic.Field: |
| return e.Type, nil |
| case semantic.Expression: |
| return e.ExpressionType(), nil |
| default: |
| return nil, fmt.Errorf("Type \"%T\" is not an expression", v) |
| } |
| } |
| |
| // Returns true if v is one of the primitive numeric value types. |
| func (*Functions) IsNumericValue(v interface{}) bool { |
| switch v.(type) { |
| case semantic.Int8Value, |
| semantic.Uint8Value, |
| semantic.Int16Value, |
| semantic.Uint16Value, |
| semantic.Int32Value, |
| semantic.Uint32Value, |
| semantic.Int64Value, |
| semantic.Uint64Value, |
| semantic.Float32Value, |
| semantic.Float64Value: |
| return true |
| default: |
| return false |
| } |
| } |
| |
| // Returns true if t is one of the primitive numeric types. |
| func (*Functions) IsNumericType(t interface{}) bool { |
| if _, builtin := t.(*semantic.Builtin); !builtin { |
| return false |
| } |
| switch t { |
| case semantic.Int8Type, |
| semantic.Uint8Type, |
| semantic.Int16Type, |
| semantic.Uint16Type, |
| semantic.Int32Type, |
| semantic.Uint32Type, |
| semantic.Int64Type, |
| semantic.Uint64Type, |
| semantic.Float32Type, |
| semantic.Float64Type: |
| return true |
| default: |
| return false |
| } |
| } |
| |
| // Returns the base name of the type of v |
| func baseType(v interface{}) reflect.Type { |
| ty := reflect.TypeOf(v) |
| for ty != nil && ty.Kind() == reflect.Ptr { |
| return ty.Elem() |
| } |
| return ty |
| } |
| |
| func isTypeTest(t reflect.Type) func(v interface{}) bool { |
| return func(v interface{}) bool { |
| ty := baseType(v) |
| if ty == nil { |
| return false |
| } |
| return ty.AssignableTo(t) |
| } |
| } |
| |
| // Asserts that the type of v is in the list of expected types |
| func (*Functions) AssertType(v interface{}, expected ...string) (string, error) { |
| got := baseType(v) |
| matched := 0 |
| for _, e := range expected { |
| if e == "nil" { |
| if v == nil { |
| matched++ |
| } |
| continue |
| } |
| et, found := nodeTypes[e] |
| if !found { |
| return "", fmt.Errorf("%s is not a valid type", e) |
| } |
| if got != nil && got.AssignableTo(et) { |
| matched++ |
| } |
| } |
| if matched > 0 { |
| return "", nil |
| } |
| |
| msg := fmt.Sprintf("Type assertion. Got: %s, Expected: ", got) |
| if c := len(expected); c > 1 { |
| msg += strings.Join(expected[:c-1], ", ") |
| msg += " or " + expected[c-1] |
| } else { |
| msg += expected[0] |
| } |
| return "", errors.New(msg) |
| } |