| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package transcoder |
| |
| import ( |
| "fmt" |
| "strings" |
| |
| "mojo/public/interfaces/bindings/mojom_types" |
| |
| "v.io/v23/vdl" |
| ) |
| |
| /*// Given a descriptor mapping, produce 2 maps. |
| // The former maps from mojom identifiers to VDL Type. |
| // The latter maps from VDL Type string (hash cons) to the mojom identifier. |
| // These maps are used to interconvert more easily. |
| func AnalyzeMojomDescriptors(mp map[string]mojom_types.UserDefinedType) map[string]*vdl.Type { |
| m2V := make(map[string]*vdl.Type) |
| for s, udt := range mp { |
| m2V[s] = mojomToVDLTypeUDT(udt, mp) |
| } |
| return m2V |
| }*/ |
| |
| // Convert the known type reference to a vdl type. |
| // Panics if the type reference was not known. |
| /*func TypeReferenceToVDLType(tr mojom_types.TypeReference, mp map[string]mojom_types.UserDefinedType) *vdl.Type { |
| if udt, ok := mp[tr.TypeKey]; ok { |
| return mojomToVDLTypeUDT(udt, mp) |
| } |
| panic("Type Key %s was not present in the mapping", tr.typeKey) |
| }*/ |
| |
| func mojomToVDLTypeUDT(udt mojom_types.UserDefinedType, mp map[string]mojom_types.UserDefinedType) (vt *vdl.Type) { |
| u := interface{}(udt) |
| switch u := u.(type) { // To do the type switch, udt has to be converted to interface{}. |
| case *mojom_types.UserDefinedTypeEnumType: // enum |
| me := u.Value |
| |
| // TODO: Assumes that the maximum enum index is len(me.Values) - 1. |
| labels := make([]string, len(me.Values)) |
| for _, ev := range me.Values { // per EnumValue... |
| // EnumValue has DeclData, EnumTypeKey, and IntValue. |
| // We just need the first and last. |
| labels[int(ev.IntValue)] = *ev.DeclData.ShortName |
| } |
| |
| vt = vdl.NamedType(mojomToVdlPath(*me.DeclData.FullIdentifier), vdl.EnumType(labels...)) |
| case *mojom_types.UserDefinedTypeStructType: // struct |
| ms := u.Value |
| |
| vt = MojomStructToVDLType(ms, mp) |
| case *mojom_types.UserDefinedTypeUnionType: // union |
| mu := u.Value |
| |
| vfields := make([]vdl.Field, len(mu.Fields)) |
| for ix, mfield := range mu.Fields { |
| vfields[ix] = vdl.Field{ |
| Name: *mfield.DeclData.ShortName, |
| Type: MojomToVDLType(mfield.Type, mp), |
| } |
| } |
| vt = vdl.NamedType(mojomToVdlPath(*mu.DeclData.FullIdentifier), vdl.UnionType(vfields...)) |
| case *mojom_types.UserDefinedTypeInterfaceType: // interface |
| panic("interfaces don't exist in vdl") |
| default: // unknown |
| panic(fmt.Errorf("user defined type %#v with unknown tag %d", udt, udt.Tag())) |
| } |
| return vt |
| } |
| |
| func MojomStructToVDLType(ms mojom_types.MojomStruct, mp map[string]mojom_types.UserDefinedType) (vt *vdl.Type) { |
| vfields := make([]vdl.Field, len(ms.Fields)) |
| for ix, mfield := range ms.Fields { |
| vfields[ix] = vdl.Field{ |
| Name: *mfield.DeclData.ShortName, |
| Type: MojomToVDLType(mfield.Type, mp), |
| } |
| } |
| vt = vdl.NamedType(mojomToVdlPath(*ms.DeclData.FullIdentifier), vdl.StructType(vfields...)) |
| return vt |
| } |
| |
| // Given a mojom Type and the descriptor mapping, produce the corresponding vdltype. |
| func MojomToVDLType(mojomtype mojom_types.Type, mp map[string]mojom_types.UserDefinedType) (vt *vdl.Type) { |
| // TODO(alexfandrianto): Cyclic types? |
| mt := interface{}(mojomtype) |
| switch mt := interface{}(mt).(type) { // To do the type switch, mt has to be converted to interface{}. |
| case *mojom_types.TypeSimpleType: // TypeSimpleType |
| switch mt.Value { |
| case mojom_types.SimpleType_Bool: |
| vt = vdl.BoolType |
| case mojom_types.SimpleType_Double: |
| vt = vdl.Float64Type |
| case mojom_types.SimpleType_Float: |
| vt = vdl.Float32Type |
| case mojom_types.SimpleType_InT8: |
| vt = vdl.Int8Type |
| case mojom_types.SimpleType_InT16: |
| vt = vdl.Int16Type |
| case mojom_types.SimpleType_InT32: |
| vt = vdl.Int32Type |
| case mojom_types.SimpleType_InT64: |
| vt = vdl.Int64Type |
| case mojom_types.SimpleType_UinT8: |
| vt = vdl.ByteType |
| case mojom_types.SimpleType_UinT16: |
| vt = vdl.Uint16Type |
| case mojom_types.SimpleType_UinT32: |
| vt = vdl.Uint32Type |
| case mojom_types.SimpleType_UinT64: |
| vt = vdl.Uint64Type |
| } |
| case *mojom_types.TypeStringType: // TypeStringType |
| st := mt.Value |
| if st.Nullable { |
| panic("nullable strings don't exist in vdl") |
| } |
| vt = vdl.StringType |
| case *mojom_types.TypeArrayType: // TypeArrayType |
| at := mt.Value |
| if at.Nullable { |
| panic("nullable arrays don't exist in vdl") |
| } |
| if at.FixedLength > 0 { |
| vt = vdl.ArrayType(int(at.FixedLength), MojomToVDLType(at.ElementType, mp)) |
| } else { |
| vt = vdl.ListType(MojomToVDLType(at.ElementType, mp)) |
| } |
| case *mojom_types.TypeMapType: // TypeMapType |
| // Note that mojom doesn't have sets. |
| m := mt.Value |
| if m.Nullable { |
| panic("nullable maps don't exist in vdl") |
| } |
| vt = vdl.MapType(MojomToVDLType(m.KeyType, mp), MojomToVDLType(m.ValueType, mp)) |
| case *mojom_types.TypeHandleType: // TypeHandleType |
| panic("handles don't exist in vdl") |
| case *mojom_types.TypeTypeReference: // TypeTypeReference |
| tr := mt.Value |
| if tr.IsInterfaceRequest { |
| panic("interface requests don't exist in vdl") |
| } |
| udt := mp[*tr.TypeKey] |
| if udt.Tag() != 1 && tr.Nullable { |
| panic("nullable non-struct type reference cannot be represented in vdl") |
| } |
| vt = mojomToVDLTypeUDT(udt, mp) |
| default: |
| panic(fmt.Errorf("%#v has unknown tag %d", mojomtype, mojomtype.Tag())) |
| } |
| |
| return vt |
| } |
| |
| func VDLToMojomType(t *vdl.Type) (mojomtype mojom_types.Type, mp map[string]mojom_types.UserDefinedType) { |
| mp = map[string]mojom_types.UserDefinedType{} |
| mojomtype = vdlToMojomTypeInternal(t, true, false, mp) |
| return |
| } |
| |
| func vdlToMojomTypeInternal(t *vdl.Type, outermostType bool, nullable bool, mp map[string]mojom_types.UserDefinedType) (mojomtype mojom_types.Type) { |
| switch t.Kind() { |
| case vdl.Bool, vdl.Float64, vdl.Float32, vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64, vdl.Byte, vdl.Uint16, vdl.Uint32, vdl.Uint64: |
| return &mojom_types.TypeSimpleType{ |
| simpleTypeCode(t.Kind()), |
| } |
| case vdl.String: |
| return &mojom_types.TypeStringType{ |
| stringType(nullable), |
| } |
| case vdl.Array: |
| elem := vdlToMojomTypeInternal(t.Elem(), false, false, mp) |
| return &mojom_types.TypeArrayType{ |
| arrayType(elem, nullable, t.Len()), |
| } |
| case vdl.List: |
| elem := vdlToMojomTypeInternal(t.Elem(), false, false, mp) |
| return &mojom_types.TypeArrayType{ |
| listType(elem, nullable), |
| } |
| case vdl.Map: |
| key := vdlToMojomTypeInternal(t.Key(), false, false, mp) |
| elem := vdlToMojomTypeInternal(t.Elem(), false, false, mp) |
| return &mojom_types.TypeMapType{ |
| mapType(key, elem, nullable), |
| } |
| case vdl.Struct, vdl.Union, vdl.Enum: |
| udtKey := addUserDefinedType(t, mp) |
| ret := &mojom_types.TypeTypeReference{ |
| mojom_types.TypeReference{ |
| Nullable: nullable, |
| TypeKey: &udtKey, |
| }, |
| } |
| if !outermostType { |
| // This is needed to match the output of the generator exactly, the outermost type |
| // is not given an identifier. |
| ret.Value.Identifier = ret.Value.TypeKey |
| } |
| return ret |
| case vdl.Optional: |
| return vdlToMojomTypeInternal(t.Elem(), false, true, mp) |
| default: |
| panic(fmt.Sprintf("conversion from VDL kind %v to mojom type not implemented", t.Kind())) |
| } |
| } |
| |
| func addUserDefinedType(t *vdl.Type, mp map[string]mojom_types.UserDefinedType) string { |
| key := mojomTypeKey(t) |
| if _, ok := mp[key]; ok { |
| return key |
| } |
| mp[key] = nil // placeholder to stop recursion |
| |
| var udt mojom_types.UserDefinedType |
| switch t.Kind() { |
| case vdl.Struct: |
| udt = structType(t, mp) |
| case vdl.Union: |
| udt = unionType(t, mp) |
| case vdl.Enum: |
| udt = enumType(t) |
| default: |
| panic(fmt.Sprintf("conversion from VDL kind %v to mojom user defined type not implemented", t.Kind())) |
| } |
| |
| mp[key] = udt |
| return key |
| } |
| |
| func simpleTypeCode(k vdl.Kind) mojom_types.SimpleType { |
| switch k { |
| case vdl.Bool: |
| return mojom_types.SimpleType_Bool |
| case vdl.Float64: |
| return mojom_types.SimpleType_Double |
| case vdl.Float32: |
| return mojom_types.SimpleType_Float |
| case vdl.Int8: |
| return mojom_types.SimpleType_InT8 |
| case vdl.Int16: |
| return mojom_types.SimpleType_InT16 |
| case vdl.Int32: |
| return mojom_types.SimpleType_InT32 |
| case vdl.Int64: |
| return mojom_types.SimpleType_InT64 |
| case vdl.Byte: |
| return mojom_types.SimpleType_UinT8 |
| case vdl.Uint16: |
| return mojom_types.SimpleType_UinT16 |
| case vdl.Uint32: |
| return mojom_types.SimpleType_UinT32 |
| case vdl.Uint64: |
| return mojom_types.SimpleType_UinT64 |
| default: |
| panic(fmt.Sprintf("kind %v does not represent a simple type", k)) |
| } |
| } |
| |
| func stringType(nullable bool) mojom_types.StringType { |
| return mojom_types.StringType{nullable} |
| } |
| |
| func arrayType(elem mojom_types.Type, nullable bool, length int) mojom_types.ArrayType { |
| return mojom_types.ArrayType{nullable, int32(length), elem} |
| } |
| |
| func listType(elem mojom_types.Type, nullable bool) mojom_types.ArrayType { |
| return mojom_types.ArrayType{nullable, -1, elem} |
| } |
| |
| func mapType(key, value mojom_types.Type, nullable bool) mojom_types.MapType { |
| return mojom_types.MapType{nullable, key, value} |
| } |
| |
| func structType(t *vdl.Type, mp map[string]mojom_types.UserDefinedType) mojom_types.UserDefinedType { |
| structFields := make([]mojom_types.StructField, t.NumField()) |
| for i := 0; i < t.NumField(); i++ { |
| structFields[i] = mojom_types.StructField{ |
| DeclData: &mojom_types.DeclarationData{ShortName: strPtr(t.Field(i).Name)}, |
| Type: vdlToMojomTypeInternal(t.Field(i).Type, false, false, mp), |
| Offset: 0, // Despite the fact that we can calculated the offset, set it to zero to match the generator |
| } |
| } |
| _, name := vdl.SplitIdent(t.Name()) |
| return &mojom_types.UserDefinedTypeStructType{ |
| mojom_types.MojomStruct{ |
| DeclData: &mojom_types.DeclarationData{ |
| ShortName: strPtr(name), |
| FullIdentifier: strPtr(mojomIdentifier(t)), |
| }, |
| Fields: structFields, |
| }, |
| } |
| } |
| |
| func unionType(t *vdl.Type, mp map[string]mojom_types.UserDefinedType) mojom_types.UserDefinedType { |
| unionFields := make([]mojom_types.UnionField, t.NumField()) |
| for i := 0; i < t.NumField(); i++ { |
| unionFields[i] = mojom_types.UnionField{ |
| DeclData: &mojom_types.DeclarationData{ShortName: strPtr(t.Field(i).Name)}, |
| Type: vdlToMojomTypeInternal(t.Field(i).Type, false, false, mp), |
| Tag: uint32(i), |
| } |
| } |
| _, name := vdl.SplitIdent(t.Name()) |
| return &mojom_types.UserDefinedTypeUnionType{ |
| mojom_types.MojomUnion{ |
| DeclData: &mojom_types.DeclarationData{ |
| ShortName: strPtr(name), |
| FullIdentifier: strPtr(mojomIdentifier(t)), |
| }, |
| Fields: unionFields, |
| }, |
| } |
| } |
| |
| func enumType(t *vdl.Type) mojom_types.UserDefinedType { |
| enumValues := make([]mojom_types.EnumValue, t.NumEnumLabel()) |
| for i := 0; i < t.NumEnumLabel(); i++ { |
| enumValues[i] = mojom_types.EnumValue{ |
| DeclData: &mojom_types.DeclarationData{ShortName: strPtr(t.EnumLabel(i))}, |
| IntValue: int32(i), |
| EnumTypeKey: mojomTypeKey(t), |
| } |
| } |
| _, name := vdl.SplitIdent(t.Name()) |
| return &mojom_types.UserDefinedTypeEnumType{ |
| mojom_types.MojomEnum{ |
| DeclData: &mojom_types.DeclarationData{ |
| ShortName: strPtr(name), |
| FullIdentifier: strPtr(mojomIdentifier(t)), |
| }, |
| Values: enumValues, |
| }, |
| } |
| } |
| |
| func strPtr(x string) *string { |
| return &x |
| } |
| |
| // mojomTypeKey creates a key from the vdl type's name that matches the generator's key. |
| // The reason for exactly matching the generator is to simplify the tests. |
| func mojomTypeKey(t *vdl.Type) string { |
| pkgPath, name := vdl.SplitIdent(t.Name()) |
| pathComponents := strings.Split(pkgPath, "/") |
| return fmt.Sprintf("%s_%s__", pathComponents[len(pathComponents)-1], name) |
| } |
| |
| func mojomIdentifier(t *vdl.Type) string { |
| return strings.Replace(t.Name(), "/", ".", -1) |
| } |
| |
| // "a.b.c.D" -> "a/b/c.D" |
| func mojomToVdlPath(path string) string { |
| lastDot := strings.LastIndex(path, ".") |
| if lastDot == -1 { |
| return path |
| } |
| return strings.Replace(path[:lastDot], ".", "/", -1) + path[lastDot:] |
| } |