| // Copyright 2018 The Fuchsia 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 fidlgen_cpp |
| |
| import ( |
| "bytes" |
| "fmt" |
| "sort" |
| "strings" |
| |
| "go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgen" |
| ) |
| |
| type Attributes struct { |
| fidlgen.Attributes |
| } |
| |
| // Docs returns C++ documentation comments. |
| func (a Attributes) Docs() string { |
| var buf bytes.Buffer |
| for _, c := range a.DocComments() { |
| buf.WriteString("\n///") |
| buf.WriteString(c) |
| } |
| return buf.String() |
| } |
| |
| type TypeShape struct { |
| fidlgen.TypeShape |
| } |
| |
| func (ts TypeShape) MaxTotalSize() int { |
| return fidlAlign(ts.TypeShape.InlineSize) + fidlAlign(ts.TypeShape.MaxOutOfLine) |
| } |
| |
| func (ts TypeShape) HasPointer() bool { |
| return ts.TypeShape.Depth > 0 |
| } |
| |
| type declKind namespacedEnumMember |
| |
| type declKinds struct { |
| Bits declKind |
| Const declKind |
| Enum declKind |
| Protocol declKind |
| Service declKind |
| Struct declKind |
| Table declKind |
| Union declKind |
| } |
| |
| // Kinds are the different kinds of FIDL declarations. They are used in |
| // header/impl templates to select the correct decl-specific template. |
| var Kinds = namespacedEnum(declKinds{}).(declKinds) |
| |
| // A Kinded value is a declaration in FIDL, for which we would like to |
| // generate some corresponding C++ code. |
| type Kinded interface { |
| Kind() declKind |
| } |
| |
| type familyKind namespacedEnumMember |
| |
| type familyKinds struct { |
| // TrivialCopy identifies values for whom a copy is trivial (like integers) |
| TrivialCopy familyKind |
| |
| // Reference identifies values with a non trivial copy for which we use a |
| // reference on the caller argument. |
| Reference familyKind |
| |
| // String identifies string values for which we can use a const reference |
| // and for which we can optimize the field construction. |
| String familyKind |
| |
| // Vector identifies vector values for which we can use a reference and for |
| // which we can optimize the field construction. |
| Vector familyKind |
| } |
| |
| // FamilyKinds are general categories identifying what operation we should use |
| // to pass a value without a move (LLCPP). It also defines the way we should |
| // initialize a field. |
| var FamilyKinds = namespacedEnum(familyKinds{}).(familyKinds) |
| |
| type typeKind namespacedEnumMember |
| |
| type typeKinds struct { |
| Array typeKind |
| Vector typeKind |
| String typeKind |
| Handle typeKind |
| Request typeKind |
| Primitive typeKind |
| Bits typeKind |
| Enum typeKind |
| Const typeKind |
| Struct typeKind |
| Table typeKind |
| Union typeKind |
| Protocol typeKind |
| } |
| |
| // TypeKinds are the kinds of C++ types (arrays, primitives, structs, ...). |
| var TypeKinds = namespacedEnum(typeKinds{}).(typeKinds) |
| |
| type Type struct { |
| nameVariants |
| |
| WirePointer bool |
| |
| // Defines what operation we should use to pass a value without a move (LLCPP). It also |
| // defines the way we should initialize a field. |
| WireFamily familyKind |
| |
| // NeedsDtor indicates whether this type needs to be destructed explicitely |
| // or not. |
| NeedsDtor bool |
| |
| Kind typeKind |
| |
| IsResource bool |
| Nullable bool |
| |
| DeclarationName fidlgen.EncodedCompoundIdentifier |
| |
| // Set iff IsArray || IsVector |
| ElementType *Type |
| // Valid iff IsArray |
| ElementCount int |
| |
| InlineInEnvelope bool |
| } |
| |
| // IsPrimitiveType returns true if this type is primitive. |
| func (t *Type) IsPrimitiveType() bool { |
| return t.Kind == TypeKinds.Primitive || t.Kind == TypeKinds.Bits || t.Kind == TypeKinds.Enum |
| } |
| |
| // WireArgumentDeclaration returns the argument declaration for this type for the wire variant. |
| func (t *Type) WireArgumentDeclaration(n string) string { |
| switch t.WireFamily { |
| case FamilyKinds.TrivialCopy: |
| return t.String() + " " + n |
| case FamilyKinds.Reference, FamilyKinds.Vector: |
| return t.String() + "& " + n |
| case FamilyKinds.String: |
| return "const " + t.String() + "& " + n |
| default: |
| panic(fmt.Sprintf("Unknown wire family kind %v", t.WireFamily)) |
| } |
| } |
| |
| // WireInitMessage returns message field initialization for the wire variant. |
| func (t *Type) WireInitMessage(n string) string { |
| switch t.WireFamily { |
| case FamilyKinds.TrivialCopy: |
| return fmt.Sprintf("%s(%s)", n, n) |
| case FamilyKinds.Reference: |
| return fmt.Sprintf("%s(std::move(%s))", n, n) |
| case FamilyKinds.String: |
| return fmt.Sprintf("%s(%s)", n, n) |
| case FamilyKinds.Vector: |
| return fmt.Sprintf("%s(%s)", n, n) |
| default: |
| panic(fmt.Sprintf("Unknown wire family kind %v", t.WireFamily)) |
| |
| } |
| } |
| |
| type namingContextKey = string |
| |
| // toKey converts a naming context into a value that can be used as a map key |
| // (i.e. with equality), such that no different naming contexts produce the same |
| // key. A naming context is a stack of strings identifying the naming scopes |
| // that something is defined in; see naming-context in the IR and |
| // https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs/0050_syntax_revamp?hl=en#layout-naming-contexts |
| // for details. |
| func toKey(idents []string) namingContextKey { |
| // relies on the fact that '$' is not a valid part of an identifier |
| return strings.Join(idents, "$") |
| } |
| |
| // ScopedLayout represents the definition of a scoped name for an anonymous |
| // layout. It consists of the scoped name (defined within the parent layout), |
| // and the flattened name (defined at the top level) |
| type ScopedLayout struct { |
| scopedName stringNamePart |
| flattenedName nameVariants |
| } |
| |
| func (s ScopedLayout) ScopedName() string { |
| return s.scopedName.String() |
| } |
| |
| func (s ScopedLayout) FlattenedName() string { |
| return s.flattenedName.NoLeading() |
| } |
| |
| type Member interface { |
| NameAndType() (string, Type) |
| } |
| |
| type Root struct { |
| HandleTypes []string |
| Library fidlgen.LibraryIdentifier |
| Decls []Kinded |
| Dependencies []fidlgen.LibraryIdentifier |
| } |
| |
| func (r *Root) declsOfKind(kind declKind) []Kinded { |
| ds := []Kinded{} |
| for _, d := range r.Decls { |
| if d.Kind() == kind { |
| ds = append(ds, d) |
| } |
| } |
| return ds |
| } |
| |
| func (r *Root) Bits() []Kinded { |
| return r.declsOfKind(Kinds.Bits) |
| } |
| |
| func (r *Root) Consts() []Kinded { |
| return r.declsOfKind(Kinds.Const) |
| } |
| |
| func (r *Root) Enums() []Kinded { |
| return r.declsOfKind(Kinds.Enum) |
| } |
| |
| func (r *Root) Protocols() []Kinded { |
| return r.declsOfKind(Kinds.Protocol) |
| } |
| |
| func (r *Root) Services() []Kinded { |
| return r.declsOfKind(Kinds.Service) |
| } |
| |
| func (r *Root) Structs() []Kinded { |
| return r.declsOfKind(Kinds.Struct) |
| } |
| |
| func (r *Root) Tables() []Kinded { |
| return r.declsOfKind(Kinds.Table) |
| } |
| |
| func (r *Root) Unions() []Kinded { |
| return r.declsOfKind(Kinds.Union) |
| } |
| |
| func (r *Root) ProtocolsForTransport() func(string) []*Protocol { |
| return func(t string) []*Protocol { |
| var ps []*Protocol |
| for _, k := range r.Protocols() { |
| p := k.(*Protocol) |
| _, ok := p.Transports()[t] |
| if ok { |
| ps = append(ps, p) |
| } |
| } |
| return ps |
| } |
| } |
| |
| func (r *Root) LegacyIncludeDir() string { |
| return formatLibraryLegacyPath(r.Library) + "/cpp" |
| } |
| |
| func (r *Root) UnifiedIncludeDir() string { |
| return formatLibraryUnifiedPath(r.Library) + "/cpp" |
| } |
| |
| // SingleComponentLibraryName returns if the FIDL library name only consists of |
| // a single identifier (e.g. "library foo;"). This is significant because the |
| // unified namespace and the natural namespace are identical when the library |
| // only has one component. |
| func (r *Root) SingleComponentLibraryName() bool { |
| return len(r.Library) == 1 |
| } |
| |
| // Namespace returns the C++ namespace for generated protocol types this FIDL |
| // library. |
| func (r *Root) Namespace() namespace { |
| switch currentVariant { |
| case noVariant: |
| fidlgen.TemplateFatalf("Called Root.Namespace() when currentVariant isn't set.\n") |
| case hlcppVariant: |
| return naturalNamespace(r.Library) |
| case unifiedVariant, wireVariant: |
| return unifiedNamespace(r.Library) |
| } |
| panic("not reached") |
| } |
| |
| // Result holds information about error results on methods. |
| type Result struct { |
| ValueMembers []Parameter |
| ResultDecl nameVariants |
| ErrorDecl nameVariants |
| Error Type |
| ValueDecl name |
| ValueStructDecl nameVariants |
| ValueTupleDecl name |
| Value Type |
| } |
| |
| func (r Result) ValueArity() int { |
| return len(r.ValueMembers) |
| } |
| |
| var primitiveTypes = map[fidlgen.PrimitiveSubtype]string{ |
| fidlgen.Bool: "bool", |
| fidlgen.Int8: "int8_t", |
| fidlgen.Int16: "int16_t", |
| fidlgen.Int32: "int32_t", |
| fidlgen.Int64: "int64_t", |
| fidlgen.Uint8: "uint8_t", |
| fidlgen.Uint16: "uint16_t", |
| fidlgen.Uint32: "uint32_t", |
| fidlgen.Uint64: "uint64_t", |
| fidlgen.Float32: "float", |
| fidlgen.Float64: "double", |
| } |
| |
| // NameVariantsForPrimitive returns the C++ name of a FIDL primitive type. |
| func NameVariantsForPrimitive(val fidlgen.PrimitiveSubtype) nameVariants { |
| if t, ok := primitiveTypes[val]; ok { |
| return primitiveNameVariants(t) |
| } |
| panic(fmt.Sprintf("unknown primitive type: %v", val)) |
| } |
| |
| type identifierTransform bool |
| |
| const ( |
| keepPartIfReserved identifierTransform = false |
| changePartIfReserved identifierTransform = true |
| ) |
| |
| func libraryParts(library fidlgen.LibraryIdentifier, identifierTransform identifierTransform) []string { |
| parts := []string{} |
| for _, part := range library { |
| if identifierTransform == changePartIfReserved { |
| parts = append(parts, changeIfReserved(string(part), nsComponentContext)) |
| } else { |
| parts = append(parts, string(part)) |
| } |
| } |
| return parts |
| } |
| |
| func formatLibraryPrefix(library fidlgen.LibraryIdentifier) string { |
| return formatLibrary(library, "_", keepPartIfReserved) |
| } |
| |
| func formatLibraryLegacyPath(library fidlgen.LibraryIdentifier) string { |
| return formatLibrary(library, "/", keepPartIfReserved) |
| |
| } |
| func formatLibraryUnifiedPath(library fidlgen.LibraryIdentifier) string { |
| return fmt.Sprintf("fidl/%s", formatLibrary(library, ".", keepPartIfReserved)) |
| |
| } |
| |
| func formatLibraryPath(library fidlgen.LibraryIdentifier) string { |
| if currentVariant == wireVariant { |
| return formatLibraryUnifiedPath(library) |
| } |
| return formatLibraryLegacyPath(library) |
| } |
| |
| func codingTableName(ident fidlgen.EncodedCompoundIdentifier) string { |
| ci := fidlgen.ParseCompoundIdentifier(ident) |
| return formatLibrary(ci.Library, "_", keepPartIfReserved) + "_" + string(ci.Name) + string(ci.Member) |
| } |
| |
| type compiler struct { |
| symbolPrefix string |
| decls fidlgen.DeclInfoMap |
| library fidlgen.LibraryIdentifier |
| handleTypes map[fidlgen.HandleSubtype]struct{} |
| resultForUnion map[fidlgen.EncodedCompoundIdentifier]*Result |
| requestResponsePayload map[fidlgen.EncodedCompoundIdentifier]fidlgen.Struct |
| // anonymousChildren maps a layout (defined by its naming context key) to |
| // the anonymous layouts defined directly within that layout. We opt to flatten |
| // the naming context and use a map rather than a trie like structure for |
| // simplicity. |
| anonymousChildren map[namingContextKey][]ScopedLayout |
| } |
| |
| func (c *compiler) isInExternalLibrary(ci fidlgen.CompoundIdentifier) bool { |
| if len(ci.Library) != len(c.library) { |
| return true |
| } |
| for i, part := range c.library { |
| if ci.Library[i] != part { |
| return true |
| } |
| } |
| return false |
| } |
| |
| func (c *compiler) compileNameVariants(eci fidlgen.EncodedCompoundIdentifier) nameVariants { |
| ci := fidlgen.ParseCompoundIdentifier(eci) |
| declInfo, ok := c.decls[ci.EncodeDecl()] |
| if !ok { |
| panic(fmt.Sprintf("unknown identifier: %v", eci)) |
| } |
| ctx := declContext(declInfo.Type) |
| name := ctx.transform(ci) // Note: does not handle ci.Member |
| if len(ci.Member) == 0 { |
| return name |
| } |
| |
| member := memberNameContext(declInfo.Type).transform(ci.Member) |
| return name.nestVariants(member) |
| } |
| |
| func (c *compiler) compileCodingTableType(eci fidlgen.EncodedCompoundIdentifier) string { |
| return fmt.Sprintf("%s_%sTable", c.symbolPrefix, fidlgen.ParseCompoundIdentifier(eci).Name) |
| } |
| |
| func (c *compiler) compileType(val fidlgen.Type) Type { |
| r := Type{} |
| r.Nullable = val.Nullable |
| r.InlineInEnvelope = val.TypeShapeV2.InlineSize <= 4 |
| switch val.Kind { |
| case fidlgen.ArrayType: |
| t := c.compileType(*val.ElementType) |
| // Because the unified bindings alias types from the natural domain objects, |
| // the name _transformation_ would be identical between natural and unified, |
| // here and below. We reserve the flexibility to specify different names |
| // in the future. |
| r.nameVariants = nameVariants{ |
| HLCPP: makeName("std::array").arrayTemplate(t.HLCPP, *val.ElementCount), |
| Unified: makeName("std::array").arrayTemplate(t.Unified, *val.ElementCount), |
| Wire: makeName("fidl::Array").arrayTemplate(t.Wire, *val.ElementCount), |
| } |
| r.WirePointer = t.WirePointer |
| r.WireFamily = FamilyKinds.Reference |
| r.NeedsDtor = true |
| r.Kind = TypeKinds.Array |
| r.IsResource = t.IsResource |
| r.ElementType = &t |
| r.ElementCount = *val.ElementCount |
| case fidlgen.VectorType: |
| t := c.compileType(*val.ElementType) |
| if val.Nullable { |
| r.nameVariants.HLCPP = makeName("fidl::VectorPtr").template(t.HLCPP) |
| r.nameVariants.Unified = makeName("fidl::VectorPtr").template(t.Unified) |
| } else { |
| r.nameVariants.HLCPP = makeName("std::vector").template(t.HLCPP) |
| r.nameVariants.Unified = makeName("std::vector").template(t.Unified) |
| } |
| r.nameVariants.Wire = makeName("fidl::VectorView").template(t.Wire) |
| r.WireFamily = FamilyKinds.Vector |
| r.WirePointer = t.WirePointer |
| r.NeedsDtor = true |
| r.Kind = TypeKinds.Vector |
| r.IsResource = t.IsResource |
| r.ElementType = &t |
| case fidlgen.StringType: |
| if val.Nullable { |
| r.HLCPP = makeName("fidl::StringPtr") |
| } else { |
| r.HLCPP = makeName("std::string") |
| } |
| r.Unified = r.HLCPP |
| r.Wire = makeName("fidl::StringView") |
| r.WireFamily = FamilyKinds.String |
| r.NeedsDtor = true |
| r.Kind = TypeKinds.String |
| case fidlgen.HandleType: |
| c.handleTypes[val.HandleSubtype] = struct{}{} |
| r.nameVariants = nameVariantsForHandle(val.HandleSubtype) |
| r.WireFamily = FamilyKinds.Reference |
| r.NeedsDtor = true |
| r.Kind = TypeKinds.Handle |
| r.IsResource = true |
| case fidlgen.RequestType: |
| p := c.compileNameVariants(val.RequestSubtype) |
| r.nameVariants = nameVariants{ |
| HLCPP: makeName("fidl::InterfaceRequest").template(p.HLCPP), |
| Unified: makeName("fidl::InterfaceRequest").template(p.Unified), |
| Wire: makeName("fidl::ServerEnd").template(p.Wire), |
| } |
| r.WireFamily = FamilyKinds.Reference |
| r.NeedsDtor = true |
| r.Kind = TypeKinds.Request |
| r.IsResource = true |
| case fidlgen.PrimitiveType: |
| r.nameVariants = NameVariantsForPrimitive(val.PrimitiveSubtype) |
| r.WireFamily = FamilyKinds.TrivialCopy |
| r.Kind = TypeKinds.Primitive |
| case fidlgen.IdentifierType: |
| name := c.compileNameVariants(val.Identifier) |
| declInfo, ok := c.decls[val.Identifier] |
| if !ok { |
| panic(fmt.Sprintf("unknown identifier: %v", val.Identifier)) |
| } |
| declType := declInfo.Type |
| if declType == fidlgen.ProtocolDeclType { |
| r.nameVariants = nameVariants{ |
| HLCPP: makeName("fidl::InterfaceHandle").template(name.HLCPP), |
| Unified: makeName("fidl::InterfaceHandle").template(name.Unified), |
| Wire: makeName("fidl::ClientEnd").template(name.Wire), |
| } |
| r.WireFamily = FamilyKinds.Reference |
| r.NeedsDtor = true |
| r.Kind = TypeKinds.Protocol |
| r.IsResource = true |
| } else { |
| switch declType { |
| case fidlgen.BitsDeclType: |
| r.Kind = TypeKinds.Bits |
| r.WireFamily = FamilyKinds.TrivialCopy |
| case fidlgen.EnumDeclType: |
| r.Kind = TypeKinds.Enum |
| r.WireFamily = FamilyKinds.TrivialCopy |
| case fidlgen.ConstDeclType: |
| r.Kind = TypeKinds.Const |
| r.WireFamily = FamilyKinds.Reference |
| case fidlgen.StructDeclType: |
| r.Kind = TypeKinds.Struct |
| r.DeclarationName = val.Identifier |
| r.WireFamily = FamilyKinds.Reference |
| r.WirePointer = val.Nullable |
| r.IsResource = declInfo.IsResourceType() |
| case fidlgen.TableDeclType: |
| r.Kind = TypeKinds.Table |
| r.DeclarationName = val.Identifier |
| r.WireFamily = FamilyKinds.Reference |
| r.WirePointer = val.Nullable |
| r.IsResource = declInfo.IsResourceType() |
| case fidlgen.UnionDeclType: |
| r.Kind = TypeKinds.Union |
| r.DeclarationName = val.Identifier |
| r.WireFamily = FamilyKinds.Reference |
| r.IsResource = declInfo.IsResourceType() |
| default: |
| panic(fmt.Sprintf("unknown declaration type: %v", declType)) |
| } |
| |
| if val.Nullable { |
| r.nameVariants.HLCPP = makeName("std::unique_ptr").template(name.HLCPP) |
| r.nameVariants.Unified = makeName("std::unique_ptr").template(name.Unified) |
| if declType == fidlgen.UnionDeclType { |
| r.nameVariants.Wire = name.Wire |
| } else { |
| r.nameVariants.Wire = makeName("fidl::ObjectView").template(name.Wire) |
| } |
| r.NeedsDtor = true |
| } else { |
| r.nameVariants = name |
| r.NeedsDtor = true |
| } |
| } |
| default: |
| panic(fmt.Sprintf("unknown type kind: %v", val.Kind)) |
| } |
| return r |
| } |
| |
| func (c *compiler) getAnonymousChildren(layout fidlgen.Layout) []ScopedLayout { |
| return c.anonymousChildren[toKey(layout.NamingContext)] |
| } |
| |
| func compile(r fidlgen.Root) *Root { |
| root := Root{ |
| Library: fidlgen.ParseLibraryName(r.Name), |
| } |
| |
| c := compiler{ |
| symbolPrefix: formatLibraryPrefix(root.Library), |
| decls: r.DeclsWithDependencies(), |
| library: fidlgen.ParseLibraryName(r.Name), |
| handleTypes: make(map[fidlgen.HandleSubtype]struct{}), |
| resultForUnion: make(map[fidlgen.EncodedCompoundIdentifier]*Result), |
| requestResponsePayload: make(map[fidlgen.EncodedCompoundIdentifier]fidlgen.Struct), |
| anonymousChildren: make(map[namingContextKey][]ScopedLayout), |
| } |
| |
| addAnonymousLayouts := func(layout fidlgen.Layout) { |
| if !layout.IsAnonymous() { |
| return |
| } |
| |
| // given a naming context ["foo", "bar", "baz"], we mark that the layout |
| // at context ["foo", "bar"] has a child "baz" |
| key := toKey(layout.NamingContext[:len(layout.NamingContext)-1]) |
| c.anonymousChildren[key] = append(c.anonymousChildren[key], ScopedLayout{ |
| // TODO(fxbug.dev/60240): change this when other bindings use name transforms |
| scopedName: stringNamePart(fidlgen.ToUpperCamelCase(layout.NamingContext[len(layout.NamingContext)-1])), |
| flattenedName: c.compileNameVariants(layout.GetName()), |
| }) |
| } |
| for _, v := range r.Bits { |
| addAnonymousLayouts(v.Layout) |
| } |
| for _, v := range r.Enums { |
| addAnonymousLayouts(v.Layout) |
| } |
| for _, v := range r.Unions { |
| addAnonymousLayouts(v.Layout) |
| } |
| for _, v := range r.Tables { |
| addAnonymousLayouts(v.Layout) |
| } |
| for _, v := range r.Structs { |
| addAnonymousLayouts(v.Layout) |
| } |
| |
| decls := make(map[fidlgen.EncodedCompoundIdentifier]Kinded) |
| |
| for _, v := range r.Bits { |
| decls[v.Name] = c.compileBits(v) |
| } |
| |
| for _, v := range r.Consts { |
| decls[v.Name] = c.compileConst(v) |
| } |
| |
| for _, v := range r.Enums { |
| decls[v.Name] = c.compileEnum(v) |
| } |
| |
| // Note: for results calculation, we must first compile unions, and structs. |
| |
| for _, v := range r.Unions { |
| decls[v.Name] = c.compileUnion(v) |
| } |
| |
| for _, v := range r.Structs { |
| if v.IsRequestOrResponse { |
| c.requestResponsePayload[v.Name] = v |
| } |
| decls[v.Name] = c.compileStruct(v) |
| } |
| |
| for _, v := range r.Protocols { |
| for _, m := range v.Methods { |
| if m.HasError { |
| var s *Struct |
| valueTypeDecl, ok := decls[m.ValueType.Identifier] |
| if ok { |
| s = valueTypeDecl.(*Struct) |
| } else { |
| // If we are unable to look up the struct, this implies that |
| // this is an externally defined struct. In this case, the |
| // IR exposes the declaration. |
| s = c.compileStruct(*m.ValueStruct) |
| } |
| result := c.compileResult(s, &m) |
| if ok { |
| s.Result = result |
| if resultTypeDecl, ok := decls[m.ResultType.Identifier]; !ok { |
| panic(fmt.Sprintf("success struct %s in library, but result union %s is not", |
| m.ValueType.Identifier, m.ResultType.Identifier)) |
| } else { |
| u := resultTypeDecl.(*Union) |
| u.Result = result |
| } |
| } |
| } |
| } |
| } |
| |
| for _, v := range r.Tables { |
| decls[v.Name] = c.compileTable(v) |
| } |
| |
| for _, v := range r.Protocols { |
| decls[v.Name] = c.compileProtocol(v) |
| } |
| |
| for _, v := range r.Services { |
| decls[v.Name] = c.compileService(v) |
| } |
| |
| for _, v := range r.DeclOrder { |
| // We process only a subset of declarations mentioned in the declaration |
| // order, ignore those we do not support. |
| if d, known := decls[v]; known { |
| root.Decls = append(root.Decls, d) |
| } |
| } |
| |
| for _, l := range r.Libraries { |
| if l.Name == r.Name { |
| // We don't need to include our own header. |
| continue |
| } |
| root.Dependencies = append(root.Dependencies, fidlgen.ParseLibraryName(l.Name)) |
| } |
| |
| // zx::channel is always referenced by the protocols in llcpp bindings API |
| if len(r.Protocols) > 0 { |
| c.handleTypes["channel"] = struct{}{} |
| } |
| |
| // find all unique handle types referenced by the library |
| var handleTypes []string |
| for k := range c.handleTypes { |
| handleTypes = append(handleTypes, string(k)) |
| } |
| sort.Sort(sort.StringSlice(handleTypes)) |
| root.HandleTypes = handleTypes |
| |
| return &root |
| } |
| |
| func compileFor(r fidlgen.Root, n string) *Root { |
| return compile(r.ForBindings(n)) |
| } |