// defineMember defines a single type member under a type or module. func (stc *srgTypeConstructor) defineMember(member srg.SRGMember, parent typegraph.TGTypeOrModule, builder *typegraph.MemberBuilder, reporter typegraph.IssueReporter, graph *typegraph.TypeGraph) { // Define the member's name and source node. builder.Name(member.Name()). SourceNode(member.Node()) // Add the member's generics. for _, generic := range member.Generics() { builder.WithGeneric(generic.Name(), generic.Node()) } builder.Define() }
// addSRGParameterTypes iterates over the parameters defined on the given srgMember, adding their types as parameters // to the specified base type reference. func (stc *srgTypeConstructor) addSRGParameterTypes(member srg.SRGMember, baseReference typegraph.TypeReference, tdg *typegraph.TypeGraph, reporter typegraph.IssueReporter) (typegraph.TypeReference, bool) { var currentReference = baseReference var success = true for _, parameter := range member.Parameters() { parameterTypeRef, result := stc.resolvePossibleType(member.Node(), parameter.DeclaredType, tdg, reporter) if !result { success = false } currentReference = currentReference.WithParameter(parameterTypeRef) } return currentReference, success }
// decorateMember decorates a single type member. func (stc *srgTypeConstructor) decorateMember(member srg.SRGMember, parent typegraph.TGTypeOrModule, decorator *typegraph.MemberDecorator, reporter typegraph.IssueReporter, graph *typegraph.TypeGraph) { // Add the generic's constraints. for _, generic := range member.Generics() { // Note: If the constraint is not valid, the resolve method will report the error and return Any, which is the correct type. constraintType, _ := stc.resolvePossibleType(generic.Node(), generic.GetConstraint, graph, reporter) decorator.DefineGenericConstraint(generic.Node(), constraintType) } // Build all member-specific information. var memberType typegraph.TypeReference = graph.AnyTypeReference() var memberKind typegraph.MemberSignatureKind = typegraph.CustomMemberSignature var isReadOnly bool = true var isStatic bool = false var isPromising bool = true var isImplicitlyCalled bool = false var hasDefaultValue bool = false var isField = false switch member.MemberKind() { case srg.VarMember: // Variables have their declared type. memberType, _ = stc.resolvePossibleType(member.Node(), member.DeclaredType, graph, reporter) memberKind = typegraph.FieldMemberSignature isReadOnly = false isPromising = false isField = true _, hasDefaultValue = member.Node().TryGetNode(parser.NodePredicateTypeFieldDefaultValue) case srg.PropertyMember: // Properties have their declared type. memberType, _ = stc.resolvePossibleType(member.Node(), member.DeclaredType, graph, reporter) memberKind = typegraph.PropertyMemberSignature isReadOnly = member.IsReadOnly() isImplicitlyCalled = true // Decorate the property *getter* with its return type. getter, found := member.Getter() if found { decorator.CreateReturnable(getter.GraphNode, memberType) } case srg.ConstructorMember: memberKind = typegraph.ConstructorMemberSignature // Constructors are static. isStatic = true // Constructors have a type of a function that returns an instance of the parent type. returnType := graph.NewInstanceTypeReference(parent.(typegraph.TGTypeDecl)) functionType := graph.NewTypeReference(graph.FunctionType(), returnType) memberType, _ = stc.addSRGParameterTypes(member, functionType, graph, reporter) // Decorate the constructor with its return type. decorator.CreateReturnable(member.Node(), returnType) // Constructors have custom signature types that return 'any' to allow them to match // interfaces. var signatureType = graph.FunctionTypeReference(graph.AnyTypeReference()) signatureType, _ = stc.addSRGParameterTypes(member, signatureType, graph, reporter) decorator.SignatureType(signatureType) case srg.OperatorMember: memberKind = typegraph.OperatorMemberSignature // Operators are read-only. isReadOnly = true // Operators have type function<DeclaredType>(parameters). returnType, _ := stc.resolvePossibleType(member.Node(), member.DeclaredType, graph, reporter) functionType := graph.NewTypeReference(graph.FunctionType(), returnType) memberType, _ = stc.addSRGParameterTypes(member, functionType, graph, reporter) // Make sure instance members under interfaces do not have bodies (and static members do). if parent.IsType() { parentType := parent.AsType() if parentType.TypeKind() == typegraph.ImplicitInterfaceType { opDef, found := graph.GetOperatorDefinition(member.Name()) // Note: If not found, the type graph will emit an error. if found { if member.HasImplementation() != opDef.IsStatic { if opDef.IsStatic { reporter.ReportError(member.GraphNode, "Static operator %v under %v %v must have an implementation", member.Name(), parentType.Title(), parentType.Name()) } else { reporter.ReportError(member.GraphNode, "Instance operator %v under %v %v cannot have an implementation", member.Name(), parentType.Title(), parentType.Name()) } } } } } // Note: Operators get decorated with a returnable by the construction system automatically. case srg.FunctionMember: memberKind = typegraph.FunctionMemberSignature // Functions are read-only. isReadOnly = true // Functions have type function<ReturnType>(parameters). returnType, _ := stc.resolvePossibleType(member.Node(), member.ReturnType, graph, reporter) // Decorate the function with its return type. decorator.CreateReturnable(member.Node(), returnType) // If the function is an async function, make it non-promising and return a Awaitable instead. if member.IsAsyncFunction() { isPromising = false returnType = graph.AwaitableTypeReference(returnType) } functionType := graph.NewTypeReference(graph.FunctionType(), returnType) memberType, _ = stc.addSRGParameterTypes(member, functionType, graph, reporter) } // Decorate the member with whether it is exported. decorator.Exported(member.IsExported()) // Decorate the member with whether it is an async function. decorator.InvokesAsync(member.IsAsyncFunction()) // If the member is under a module, then it is static. decorator.Static(isStatic || !parent.IsType()) // Decorate the member with whether it is promising. decorator.Promising(isPromising) // Decorate the member with whether it has a default value. decorator.HasDefaultValue(hasDefaultValue) // Decorate the member with whether it is a field. decorator.Field(isField) // Decorate the member with whether it is implicitly called. decorator.ImplicitlyCalled(isImplicitlyCalled) // Decorate the member with whether it is read-only. decorator.ReadOnly(isReadOnly) // Decorate the member with its type. decorator.MemberType(memberType) // Decorate the member with its kind. decorator.MemberKind(memberKind) // Decorate the member with its tags, if any. for name, value := range member.Tags() { decorator.WithTag(name, value) } // Finalize the member. decorator.Decorate() }