Exemplo n.º 1
0
// 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()
}
Exemplo n.º 2
0
func (itc *irgTypeConstructor) DecorateMembers(decorator typegraph.GetMemberDecorator, reporter typegraph.IssueReporter, graph *typegraph.TypeGraph) {
	for _, declaration := range itc.irg.Declarations() {
		if declaration.HasAnnotation(CONSTRUCTOR_ANNOTATION) {
			// For each constructor defined, create the intersection of their parameters.
			var parameters = make([]typegraph.TypeReference, 0)
			for constructorIndex, constructor := range declaration.GetAnnotations(CONSTRUCTOR_ANNOTATION) {
				for index, parameter := range constructor.Parameters() {
					parameterType, err := itc.ResolveType(parameter.DeclaredType(), graph)
					if err != nil {
						reporter.ReportError(parameter.GraphNode, "%v", err)
						continue
					}

					var resolvedParameterType = parameterType
					if parameter.IsOptional() {
						resolvedParameterType = resolvedParameterType.AsNullable()
					}

					if index >= len(parameters) {
						// If this is not the first constructor, then this parameter is implicitly optional
						// and therefore nullable.
						if constructorIndex > 0 {
							resolvedParameterType = resolvedParameterType.AsNullable()
						}

						parameters = append(parameters, resolvedParameterType)
					} else {
						parameters[index] = parameters[index].Intersect(resolvedParameterType)
					}
				}
			}

			// Define the construction function for the type.
			typeDecl, _ := graph.GetTypeForSourceNode(declaration.GraphNode)
			var constructorFunction = graph.FunctionTypeReference(typeDecl.GetTypeReference())
			for _, parameterType := range parameters {
				constructorFunction = constructorFunction.WithParameter(parameterType)
			}

			decorator(declaration.GetAnnotations(CONSTRUCTOR_ANNOTATION)[0].GraphNode).
				Exported(true).
				Static(true).
				ReadOnly(true).
				MemberKind(typegraph.NativeConstructorMemberSignature).
				MemberType(constructorFunction).
				Decorate()
		}

		for _, nativeOp := range declaration.GetAnnotations(NATIVE_OPERATOR_ANNOTATION) {
			opName, hasOpName := nativeOp.Value()
			if !hasOpName {
				continue
			}

			opDefinition, found := graph.GetOperatorDefinition(opName)
			if !found {
				continue
			}

			// Define the operator's member type based on the definition.
			typeDecl, _ := graph.GetTypeForSourceNode(declaration.GraphNode)

			var expectedReturnType = opDefinition.ExpectedReturnType(typeDecl.GetTypeReference())
			if expectedReturnType.HasReferredType(graph.BoolType()) {
				expectedReturnType, _ = itc.ResolveType("Boolean", graph)
			}

			var operatorType = graph.FunctionTypeReference(expectedReturnType)
			for _, parameter := range opDefinition.Parameters {
				operatorType = operatorType.WithParameter(parameter.ExpectedType(typeDecl.GetTypeReference()))
			}

			// Add the operator to the type.
			decorator(nativeOp.GraphNode).
				Native(true).
				Exported(true).
				SkipOperatorChecking(true).
				MemberType(operatorType).
				MemberKind(typegraph.NativeOperatorMemberSignature).
				Decorate()
		}

		// Add the declared members.
		for _, member := range declaration.Members() {
			declaredType, err := itc.ResolveType(member.DeclaredType(), graph)
			if err != nil {
				reporter.ReportError(member.GraphNode, "%v", err)
				continue
			}

			var memberType = declaredType
			var memberKind = typegraph.CustomMemberSignature
			var isReadonly = member.IsReadonly()

			switch member.Kind() {
			case webidl.FunctionMember:
				isReadonly = true
				memberKind = typegraph.NativeFunctionMemberSignature
				memberType = graph.FunctionTypeReference(memberType)

				// Add the parameter types.
				var markOptional = false
				for _, parameter := range member.Parameters() {
					if parameter.IsOptional() {
						markOptional = true
					}

					parameterType, err := itc.ResolveType(parameter.DeclaredType(), graph)
					if err != nil {
						reporter.ReportError(member.GraphNode, "%v", err)
						continue
					}

					// All optional parameters get marked as nullable, which means we can skip
					// passing them on function calls.
					if markOptional {
						memberType = memberType.WithParameter(parameterType.AsNullable())
					} else {
						memberType = memberType.WithParameter(parameterType)
					}
				}

			case webidl.AttributeMember:
				memberKind = typegraph.NativePropertyMemberSignature

				if len(member.Parameters()) > 0 {
					reporter.ReportError(member.GraphNode, "Attributes cannot have parameters")
				}

			default:
				panic("Unknown WebIDL member kind")
			}

			decorator := decorator(member.GraphNode)
			if _, hasName := member.Name(); !hasName {
				decorator.Native(true)
			}

			decorator.Exported(true).
				Static(member.IsStatic()).
				ReadOnly(isReadonly).
				MemberKind(memberKind).
				MemberType(memberType).
				Decorate()
		}
	}
}