Exemple #1
0
// 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)
	}
}
Exemple #2
0
// 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)
}
Exemple #3
0
// 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}
}