// checkAndComputeOperator handles specialized logic for operator members. func (mb *MemberDecorator) checkAndComputeOperator(memberNode compilergraph.ModifiableGraphNode, name string) { name = strings.ToLower(name) // Verify that the operator matches a known operator. definition, ok := mb.tdg.operators[name] if !ok { mb.tdg.decorateWithError(memberNode, "Unknown operator '%s' defined on type '%s'", name, mb.parent().Name()) return } // Some operators are static and some are assignable. mb.static = definition.IsStatic mb.readonly = !definition.IsAssignable // Ensure that the declared return type is equal to that expected. declaredReturnType := mb.memberType.Generics()[0] containingType := mb.tdg.NewInstanceTypeReference(mb.parent().AsType()) expectedReturnType := definition.ExpectedReturnType(containingType) if !mb.skipOperatorChecking { if !expectedReturnType.IsAny() && !declaredReturnType.IsAny() && declaredReturnType != expectedReturnType { mb.tdg.decorateWithError(memberNode, "Operator '%s' defined on type '%s' expects a return type of '%v'; found %v", name, mb.parent().Name(), expectedReturnType, declaredReturnType) return } } // Decorate the operator with its return type. var actualReturnType = expectedReturnType if expectedReturnType.IsAny() { actualReturnType = declaredReturnType } mb.CreateReturnable(mb.sourceNode, actualReturnType) // Ensure we have the expected number of parameters. parametersExpected := definition.Parameters if !mb.skipOperatorChecking { if mb.memberType.ParameterCount() != len(parametersExpected) { mb.tdg.decorateWithError(memberNode, "Operator '%s' defined on type '%s' expects %v parameters; found %v", name, mb.parent().Name(), len(parametersExpected), mb.memberType.ParameterCount()) return } } var memberType = mb.tdg.NewTypeReference(mb.tdg.FunctionType(), actualReturnType) // Ensure the parameters expected on the operator match those specified. parameterTypes := mb.memberType.Parameters() for index, parameterType := range parameterTypes { if !mb.skipOperatorChecking { expectedType := parametersExpected[index].ExpectedType(containingType) if !expectedType.IsAny() && expectedType != parameterType { mb.tdg.decorateWithError(memberNode, "Parameter '%s' (#%v) for operator '%s' defined on type '%s' expects type %v; found %v", parametersExpected[index].Name, index, name, mb.parent().Name(), expectedType, parameterType) } } memberType = memberType.WithParameter(parameterType) } // Decorate the member with its type. memberNode.DecorateWithTagged(NodePredicateMemberType, memberType) // Decorate the member with its signature. if definition.IsStatic { mb.decorateWithSig(mb.tdg.AnyTypeReference()) } else { mb.decorateWithSig(memberType) } }
// decorateWithError decorates the given node with an associated error node. func (t *TypeGraph) decorateWithError(node compilergraph.ModifiableGraphNode, message string, args ...interface{}) { errorNode := node.Modifier().CreateNode(NodeTypeError) errorNode.Decorate(NodePredicateErrorMessage, fmt.Sprintf(message, args...)) node.Connect(NodePredicateError, errorNode) }
// Define defines the member under the type or module in the type graph. func (mb *MemberBuilder) Define() TGMember { var name = mb.name if mb.isOperator { // Normalize the name by lowercasing it. name = strings.ToLower(mb.name) } // Create the member node. var memberNode compilergraph.ModifiableGraphNode if mb.isOperator { memberNode = mb.modifier.CreateNode(NodeTypeOperator) memberNode.Decorate(NodePredicateOperatorName, name) memberNode.Decorate(NodePredicateMemberName, operatorMemberNamePrefix+name) } else { memberNode = mb.modifier.CreateNode(NodeTypeMember) memberNode.Decorate(NodePredicateMemberName, name) } if mb.hasSourceNode { memberNode.Connect(NodePredicateSource, mb.sourceNode) } memberNode.Decorate(NodePredicateModulePath, mb.parent.ParentModule().Get(NodePredicateModulePath)) // Decorate the member with its generics. for index, genericInfo := range mb.memberGenerics { genericBuilder := genericBuilder{ modifier: mb.modifier, tdg: mb.tdg, parentNode: memberNode, genericKind: typeMemberGeneric, index: index, parentPredicate: NodePredicateMemberGeneric, } genericBuilder.Name(genericInfo.name) if genericInfo.hasSourceNode { genericBuilder.SourceNode(genericInfo.sourceNode) } genericBuilder.defineGeneric() } // Add the member to the parent node. parentNode := mb.modifier.Modify(mb.parent.Node()) if mb.isOperator { parentNode.Connect(NodePredicateTypeOperator, memberNode) } else { parentNode.Connect(NodePredicateMember, memberNode) } return TGMember{memberNode.AsNode(), mb.tdg} }